diff --git a/src/default_config.toml b/src/default_config.toml index a2aee60fb7..e22f5dd41d 100644 --- a/src/default_config.toml +++ b/src/default_config.toml @@ -167,6 +167,7 @@ log_menu.log_other = ["o"] log_menu.quit = ["q", "esc"] log_menu.-n = ["-n"] log_menu.--grep = ["-F"] +log_menu.-G = ["-G"] root.merge_menu = ["m"] merge_menu.--ff-only = ["-f"] diff --git a/src/items.rs b/src/items.rs index 47699d28ec..81c460eeb1 100644 --- a/src/items.rs +++ b/src/items.rs @@ -7,6 +7,7 @@ use crate::highlight; use crate::item_data::ItemData; use crate::item_data::Ref; use crate::item_data::SectionHeader; +use git2::DiffOptions; use git2::Oid; use git2::Repository; use ratatui::text::Line; @@ -300,6 +301,7 @@ pub(crate) fn log( limit: usize, rev: Option, msg_regex: Option, + changes_regex: Option, ) -> Res> { let mut revwalk = repo.revwalk().map_err(Error::ReadLog)?; if let Some(r) = rev { @@ -350,6 +352,43 @@ pub(crate) fn log( return Ok(None); } + if let Some(re) = &changes_regex { + let parent = commit.parent(0).ok(); + let parent_tree = parent + .as_ref() + .map(|p| p.tree()) + .transpose() + .map_err(Error::ReadLog)?; + let current_tree = commit.tree().map_err(Error::ReadLog)?; + + let mut opts = DiffOptions::new(); + let diff = repo + .diff_tree_to_tree(parent_tree.as_ref(), Some(¤t_tree), Some(&mut opts)) + .map_err(Error::ReadLog)?; + + let mut found = false; + + diff.print(git2::DiffFormat::Patch, |_delta, _hunk, line| { + let content = std::str::from_utf8(line.content()).unwrap_or(""); + + match line.origin() { + '+' | '-' => { + if re.is_match(content) { + found = true; + return false; + } + } + _ => {} + } + true + }) + .ok(); + + if !found { + return Ok(None); + } + } + let associated_references: Vec<_> = references .iter() .filter(|(commit, _)| commit.id() == oid) diff --git a/src/ops/log.rs b/src/ops/log.rs index 7e49d284f6..9928ccfacd 100644 --- a/src/ops/log.rs +++ b/src/ops/log.rs @@ -21,6 +21,7 @@ pub(crate) fn init_args() -> Vec { positive_number, ), Arg::new_arg("--grep", "Search messages", None, any_regex), + Arg::new_arg("-G", "Search changes", None, any_regex), // Arg::new_str("-S", "Search occurrences"), // TODO: Implement search ] } @@ -98,6 +99,14 @@ fn goto_log_screen(app: &mut App, rev: Option) { let msg_regex = msg_regex_menu.and_then(|arg| arg.value_as::().cloned()); + let changes_regex_menu = app + .state + .pending_menu + .as_ref() + .and_then(|m| m.args.get("-G")); + + let changes_regex = changes_regex_menu.and_then(|arg| arg.value_as::().cloned()); + app.state.screens.push( screen::log::create( Arc::clone(&app.state.config), @@ -106,6 +115,7 @@ fn goto_log_screen(app: &mut App, rev: Option) { limit as usize, rev, msg_regex, + changes_regex, ) .expect("Couldn't create screen"), ); diff --git a/src/screen/log.rs b/src/screen/log.rs index eb06b5e2e3..5db599f747 100644 --- a/src/screen/log.rs +++ b/src/screen/log.rs @@ -12,10 +12,11 @@ pub(crate) fn create( limit: usize, rev: Option, msg_regex: Option, + changes_regex: Option, ) -> Res { Screen::new( Arc::clone(&config), size, - Box::new(move || log(&repo, limit, rev, msg_regex.clone())), + Box::new(move || log(&repo, limit, rev, msg_regex.clone(), changes_regex.clone())), ) } diff --git a/src/screen/status.rs b/src/screen/status.rs index 72d24aa4d6..e59f91a33a 100644 --- a/src/screen/status.rs +++ b/src/screen/status.rs @@ -240,5 +240,5 @@ fn create_log_section_items<'a>( }, ] .into_iter() - .chain(items::log(repo, limit, None, None).unwrap()) + .chain(items::log(repo, limit, None, None, None).unwrap()) } diff --git a/src/tests/log_grep_changes.rs b/src/tests/log_grep_changes.rs new file mode 100644 index 0000000000..49ac222557 --- /dev/null +++ b/src/tests/log_grep_changes.rs @@ -0,0 +1,33 @@ +use super::*; + +fn setup(ctx: TestContext) -> TestContext { + commit(&ctx.dir, "first", "third"); + commit(&ctx.dir, "first", "second"); + commit(&ctx.dir, "first", "first"); + ctx +} + +#[test] +fn grep_changes_prompt() { + snapshot!(setup(setup_clone!()), "l-G"); +} + +#[test] +fn grep_changes_set_example() { + snapshot!(setup(setup_clone!()), "l-Gexample"); +} + +#[test] +fn grep_changes_second() { + snapshot!(setup(setup_clone!()), "l-Gsecondl"); +} + +#[test] +fn grep_changes_no_match() { + snapshot!(setup(setup_clone!()), "l-Gdoesntexistl"); +} + +#[test] +fn grep_changes_second_other() { + snapshot!(setup(setup_clone!()), "l-Gsecondomain"); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 9df83e6eb1..c79335491c 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -21,6 +21,7 @@ mod discard; mod editor; mod fetch; mod log; +mod log_grep_changes; mod merge; mod pull; mod push; diff --git a/src/tests/snapshots/gitu__tests__log__grep_prompt.snap b/src/tests/snapshots/gitu__tests__log__grep_prompt.snap index cef1f071d9..62733f6c6e 100644 --- a/src/tests/snapshots/gitu__tests__log__grep_prompt.snap +++ b/src/tests/snapshots/gitu__tests__log__grep_prompt.snap @@ -18,8 +18,8 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| Log Arguments | l current -F Search messages (--grep) | - o other -n Limit number of commits (-n=256) | - q/esc Quit/Close | + o other -G Search changes (-G) | + q/esc Quit/Close -n Limit number of commits (-n=256) | ────────────────────────────────────────────────────────────────────────────────| ? Search messages: › █ | -styles_hash: 30915effaeaeb2e3 +styles_hash: 68173f9f5398311b diff --git a/src/tests/snapshots/gitu__tests__log__grep_set_example.snap b/src/tests/snapshots/gitu__tests__log__grep_set_example.snap index 2bfcca8eeb..a71981a9db 100644 --- a/src/tests/snapshots/gitu__tests__log__grep_set_example.snap +++ b/src/tests/snapshots/gitu__tests__log__grep_set_example.snap @@ -20,6 +20,6 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| Log Arguments | l current -F Search messages (--grep=example) | - o other -n Limit number of commits (-n=256) | - q/esc Quit/Close | -styles_hash: 5877b9adb59fe24d + o other -G Search changes (-G) | + q/esc Quit/Close -n Limit number of commits (-n=256) | +styles_hash: 30b4594236e60aa2 diff --git a/src/tests/snapshots/gitu__tests__log__limit_prompt.snap b/src/tests/snapshots/gitu__tests__log__limit_prompt.snap index cdca916481..bffbbadd4f 100644 --- a/src/tests/snapshots/gitu__tests__log__limit_prompt.snap +++ b/src/tests/snapshots/gitu__tests__log__limit_prompt.snap @@ -18,8 +18,8 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| Log Arguments | l current -F Search messages (--grep) | - o other -n Limit number of commits (-n) | - q/esc Quit/Close | + o other -G Search changes (-G) | + q/esc Quit/Close -n Limit number of commits (-n) | ────────────────────────────────────────────────────────────────────────────────| ? Limit number of commits (default 256): › █ | -styles_hash: 99ca458c7c196a27 +styles_hash: f0682b6afe30adf9 diff --git a/src/tests/snapshots/gitu__tests__log__limit_set_10.snap b/src/tests/snapshots/gitu__tests__log__limit_set_10.snap index 073a41dbbd..525bec067f 100644 --- a/src/tests/snapshots/gitu__tests__log__limit_set_10.snap +++ b/src/tests/snapshots/gitu__tests__log__limit_set_10.snap @@ -20,6 +20,6 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| Log Arguments | l current -F Search messages (--grep) | - o other -n Limit number of commits (-n=10) | - q/esc Quit/Close | -styles_hash: 195bb974698466ed + o other -G Search changes (-G) | + q/esc Quit/Close -n Limit number of commits (-n=10) | +styles_hash: 6b49349f1757c2bd diff --git a/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_no_match.snap b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_no_match.snap new file mode 100644 index 0000000000..81aff8709c --- /dev/null +++ b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_no_match.snap @@ -0,0 +1,25 @@ +--- +source: src/tests/log_grep_changes.rs +expression: ctx.redact_buffer() +--- +▌No commits found | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | +styles_hash: 90ecdf643519e051 diff --git a/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_prompt.snap b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_prompt.snap new file mode 100644 index 0000000000..7eccde487d --- /dev/null +++ b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_prompt.snap @@ -0,0 +1,25 @@ +--- +source: src/tests/log_grep_changes.rs +expression: ctx.redact_buffer() +--- +▌On branch main | +▌Your branch is ahead of 'origin/main' by 3 commit(s). | + | + Recent commits | + a7fb92e main modify first | + eb42c24 modify first | + a086849 add first | + b66a0bf origin/main add initial-file | + | + | + | + | + | +────────────────────────────────────────────────────────────────────────────────| + Log Arguments | + l current -F Search messages (--grep) | + o other -G Search changes (-G) | + q/esc Quit/Close -n Limit number of commits (-n=256) | +────────────────────────────────────────────────────────────────────────────────| +? Search changes: › █ | +styles_hash: f31db5867a2f6c5d diff --git a/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_second.snap b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_second.snap new file mode 100644 index 0000000000..8c47286755 --- /dev/null +++ b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_second.snap @@ -0,0 +1,25 @@ +--- +source: src/tests/log_grep_changes.rs +expression: ctx.redact_buffer() +--- +▌a7fb92e main modify first | + eb42c24 modify first | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | +styles_hash: a908290abddd40c9 diff --git a/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_second_other.snap b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_second_other.snap new file mode 100644 index 0000000000..8c47286755 --- /dev/null +++ b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_second_other.snap @@ -0,0 +1,25 @@ +--- +source: src/tests/log_grep_changes.rs +expression: ctx.redact_buffer() +--- +▌a7fb92e main modify first | + eb42c24 modify first | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | +styles_hash: a908290abddd40c9 diff --git a/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_set_example.snap b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_set_example.snap new file mode 100644 index 0000000000..1b20b6d39a --- /dev/null +++ b/src/tests/snapshots/gitu__tests__log_grep_changes__grep_changes_set_example.snap @@ -0,0 +1,25 @@ +--- +source: src/tests/log_grep_changes.rs +expression: ctx.redact_buffer() +--- +▌On branch main | +▌Your branch is ahead of 'origin/main' by 3 commit(s). | + | + Recent commits | + a7fb92e main modify first | + eb42c24 modify first | + a086849 add first | + b66a0bf origin/main add initial-file | + | + | + | + | + | + | + | +────────────────────────────────────────────────────────────────────────────────| + Log Arguments | + l current -F Search messages (--grep) | + o other -G Search changes (-G=example) | + q/esc Quit/Close -n Limit number of commits (-n=256) | +styles_hash: 835226a0c290291d