vim: Single quote mark (#27231)

Closes #22398

Release Notes:

- vim: Adds `'` and `"` marks (last location jumped from in the current
buffer, and location when last exiting a buffer)

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
AidanV 2025-03-21 22:45:57 -07:00 committed by GitHub
parent d82b547596
commit fa677bdc38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 88 additions and 3 deletions

View file

@ -2147,6 +2147,7 @@ impl Editor {
self.push_to_nav_history(
*old_cursor_position,
Some(new_cursor_position.to_point(buffer)),
false,
cx,
);
@ -10809,10 +10810,15 @@ impl Editor {
self.nav_history.as_ref()
}
pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
}
fn push_to_nav_history(
&mut self,
cursor_anchor: Anchor,
new_position: Option<Point>,
is_deactivate: bool,
cx: &mut Context<Self>,
) {
if let Some(nav_history) = self.nav_history.as_mut() {
@ -10838,6 +10844,10 @@ impl Editor {
}),
cx,
);
cx.emit(EditorEvent::PushedToNavHistory {
anchor: cursor_anchor,
is_deactivate,
})
}
}
@ -18617,6 +18627,10 @@ pub enum EditorEvent {
},
Reloaded,
CursorShapeChanged,
PushedToNavHistory {
anchor: Anchor,
is_deactivate: bool,
},
}
impl EventEmitter<EditorEvent> for Editor {}

View file

@ -737,7 +737,7 @@ impl Item for Editor {
fn deactivated(&mut self, _: &mut Window, cx: &mut Context<Self>) {
let selection = self.selections.newest_anchor();
self.push_to_nav_history(selection.head(), None, cx);
self.push_to_nav_history(selection.head(), None, true, cx);
}
fn workspace_deactivated(&mut self, _: &mut Window, cx: &mut Context<Self>) {

View file

@ -210,6 +210,9 @@ impl Vim {
let Some(mut anchors) = anchors else { return };
self.update_editor(window, cx, |_, editor, _, cx| {
editor.create_nav_history_entry(cx);
});
let is_active_operator = self.active_operator().is_some();
if is_active_operator {
if let Some(anchor) = anchors.last() {
@ -264,7 +267,7 @@ impl Vim {
pub fn set_mark(
&mut self,
name: String,
mut name: String,
anchors: Vec<Anchor>,
buffer_entity: &Entity<MultiBuffer>,
window: &mut Window,
@ -273,6 +276,9 @@ impl Vim {
let Some(workspace) = self.workspace(window) else {
return;
};
if name == "`" {
name = "'".to_string();
}
let entity_id = workspace.entity_id();
Vim::update_globals(cx, |vim_globals, cx| {
let Some(marks_state) = vim_globals.marks.get(&entity_id) else {
@ -286,11 +292,14 @@ impl Vim {
pub fn get_mark(
&self,
name: &str,
mut name: &str,
editor: &mut Editor,
window: &mut Window,
cx: &mut App,
) -> Option<Mark> {
if name == "`" {
name = "'";
}
if matches!(name, "{" | "}" | "(" | ")") {
let (map, selections) = editor.selections.all_display(cx);
let anchors = selections
@ -331,3 +340,29 @@ pub fn jump_motion(
(point, SelectionGoal::None)
}
#[cfg(test)]
mod test {
use gpui::TestAppContext;
use crate::test::NeovimBackedTestContext;
#[gpui::test]
async fn test_quote_mark(cx: &mut TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇHello, world!").await;
cx.simulate_shared_keystrokes("w m o").await;
cx.shared_state().await.assert_eq("Helloˇ, world!");
cx.simulate_shared_keystrokes("$ ` o").await;
cx.shared_state().await.assert_eq("Helloˇ, world!");
cx.simulate_shared_keystrokes("` `").await;
cx.shared_state().await.assert_eq("Hello, worldˇ!");
cx.simulate_shared_keystrokes("` `").await;
cx.shared_state().await.assert_eq("Helloˇ, world!");
cx.simulate_shared_keystrokes("$ m '").await;
cx.shared_state().await.assert_eq("Hello, worldˇ!");
cx.simulate_shared_keystrokes("^ ` `").await;
cx.shared_state().await.assert_eq("Hello, worldˇ!");
}
}

View file

@ -822,6 +822,19 @@ impl Vim {
EditorEvent::Edited { .. } => self.push_to_change_list(window, cx),
EditorEvent::FocusedIn => self.sync_vim_settings(window, cx),
EditorEvent::CursorShapeChanged => self.cursor_shape_changed(window, cx),
EditorEvent::PushedToNavHistory {
anchor,
is_deactivate,
} => {
self.update_editor(window, cx, |vim, editor, window, cx| {
let mark = if *is_deactivate {
"\"".to_string()
} else {
"'".to_string()
};
vim.set_mark(mark, vec![*anchor], editor.buffer(), window, cx);
});
}
_ => {}
}
}

View file

@ -0,0 +1,23 @@
{"Put":{"state":"ˇHello, world!"}}
{"Key":"w"}
{"Key":"m"}
{"Key":"o"}
{"Get":{"state":"Helloˇ, world!","mode":"Normal"}}
{"Key":"$"}
{"Key":"`"}
{"Key":"o"}
{"Get":{"state":"Helloˇ, world!","mode":"Normal"}}
{"Key":"`"}
{"Key":"`"}
{"Get":{"state":"Hello, worldˇ!","mode":"Normal"}}
{"Key":"`"}
{"Key":"`"}
{"Get":{"state":"Helloˇ, world!","mode":"Normal"}}
{"Key":"$"}
{"Key":"m"}
{"Key":"'"}
{"Get":{"state":"Hello, worldˇ!","mode":"Normal"}}
{"Key":"^"}
{"Key":"`"}
{"Key":"`"}
{"Get":{"state":"Hello, worldˇ!","mode":"Normal"}}