diff --git a/crates/cli/src/tui/components/history.rs b/crates/cli/src/tui/components/history.rs index ba63ce0..6b36f59 100644 --- a/crates/cli/src/tui/components/history.rs +++ b/crates/cli/src/tui/components/history.rs @@ -1,9 +1,13 @@ // use git_next_core::git::graph::Log; +use lazy_static::lazy_static; use ratatui::{ - text::{Line, Text}, + style::{Color, Style, Styled as _}, + text::{Line, Span, Text}, widgets::{Paragraph, Widget}, }; +use regex::Regex; +use tracing::info; use super::HeightContraintLength; @@ -39,8 +43,88 @@ impl LogLine { Self { raw: raw.into() } } } +lazy_static::lazy_static! { + static ref RE: Regex = + #[allow(clippy::unwrap_used)] + Regex::new( + r"^(?
.*)\s(?[0-9a-f]{7})\s\((? .*?)\)\s(? .*)", + ).unwrap(); + + static ref BRANCHES: Regex = + #[allow(clippy::unwrap_used)] + Regex::new( + r"origin\/(? [^,]+)", + ).unwrap(); +} impl From for Line<'_> { fn from(value: LogLine) -> Self { - Line::from(value.raw) + if let Some(caps) = RE.captures(&value.raw) { + let pre = caps["pre"].to_owned(); + let hash = caps["hash"].to_owned(); + let message = caps["message"].to_owned(); + info!(branches=?caps["branches"], "raw branches"); + let mut branches = BRANCHES + .captures_iter(&caps["branches"]) + .map(|captures| captures["branch"].to_owned()) + .collect:: >(); + if branches.is_empty() { + // line without branches + Line::from(vec![ + pre.into(), + " ".into(), + hash.into(), + " ".into(), + message.into(), + ]) + } else { + // line withbranches + let mut spans = vec![pre.into(), " ".into(), hash.into(), " ".into()]; + info!(?branches, "matched branch list"); + branches.sort(); + branches + .into_iter() + .map(|branch| Span::from(branch).style(Style::default().fg(Color::Blue))) + .for_each(|span| { + spans.push("[".into()); + spans.push(span); + spans.push("]".into()); + }); + spans.push(" ".into()); + spans.push(message.into()); + Line::from(spans) + } + } else { + // non-commit line + Line::from(value.raw.clone()) + } + } +} + +#[cfg(test)] +mod tests { + use tracing::info; + + use super::RE; + + #[test_log::test] + fn parse_log_line() -> Result<(), Box > { + let line = "* 97b6853 (origin/next, origin/main, origin/dev, origin/HEAD) refactor(tui): simplify repo identity widget"; + RE.captures(line).map_or_else( + || Err("Failed to capture".into()), + |caps| { + info!(?caps, ""); + assert_eq!(&caps["pre"], "*"); + assert_eq!(&caps["hash"], "97b6853"); + assert_eq!(&caps["branch1"], "next"); + assert_eq!(&caps["branch2"], "main"); + assert_eq!(&caps["branch3"], "dev"); + assert_eq!(&caps["branch4"], "HEAD"); + assert_eq!( + &caps["message"], + "refactor(tui): simplify repo identity widget" + ); + Ok(()) + }, + ) } }