diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bdad9ba..1c9038c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * use [tombi](https://github.com/tombi-toml/tombi) for all toml file formatting * open the external editor from the status diff view [[@WaterWhisperer](https://github.com/WaterWhisperer)] ([#2805](https://github.com/gitui-org/gitui/issues/2805)) +* open external editor at the cursor line from any diff view (status, log, blame), with editor-specific goto syntax (Helix, VS Code, vi-style) [@paaloeye](https://github.com/paaloeye) ([#2952](https://github.com/gitui-org/gitui/pull/2952)) ### Fixes * crash when opening submodule ([#2895](https://github.com/gitui-org/gitui/issues/2895)) diff --git a/src/components/diff.rs b/src/components/diff.rs index f02e247a..a6d6ec81 100644 --- a/src/components/diff.rs +++ b/src/components/diff.rs @@ -1082,4 +1082,80 @@ mod tests { if path == "src/main.rs" )); } + + #[test] + fn diff_component_opens_editor_at_cursor_line() { + use asyncgit::sync::diff::{DiffLinePosition, Hunk}; + use asyncgit::FileDiff; + + let env = Environment::test_env(); + let mut comp = DiffComponent::new(&env, false); + comp.focus(true); + comp.current.path = String::from("src/main.rs"); + + // build a minimal FileDiff: one hunk with a header line and + // two content lines at known new_lineno values + let hunk = Hunk { + header_hash: 0, + lines: vec![ + DiffLine { + content: "@@ -1,2 +1,2 @@".into(), + line_type: DiffLineType::Header, + position: DiffLinePosition { + old_lineno: None, + new_lineno: None, + }, + }, + DiffLine { + content: "context".into(), + line_type: DiffLineType::None, + position: DiffLinePosition { + old_lineno: Some(1), + new_lineno: Some(1), + }, + }, + DiffLine { + content: "added line".into(), + line_type: DiffLineType::Add, + position: DiffLinePosition { + old_lineno: None, + new_lineno: Some(2), + }, + }, + ], + }; + let file_diff = FileDiff { + hunks: vec![hunk], + lines: 3, + untracked: false, + sizes: (0, 0), + size_delta: 0, + }; + comp.update(String::from("src/main.rs"), false, file_diff); + + // move cursor to the Add line (index 2 in the flat list) + comp.move_selection(ScrollType::Down); + comp.move_selection(ScrollType::Down); + + let event = Event::Key(KeyEvent::new( + KeyCode::Char('e'), + KeyModifiers::empty(), + )); + assert!(matches!( + comp.event(&event).unwrap(), + EventState::Consumed + )); + + let queued = env.queue.pop(); + assert!( + matches!( + queued, + Some(InternalEvent::OpenExternalEditor( + Some(_), + Some(2) + )) + ), + "expected OpenExternalEditor with line Some(2)" + ); + } }