diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index e76e12b4..c8109297 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -127,7 +127,7 @@ impl Range { /// A selection consists of one or more selection ranges. /// invariant: A selection can never be empty (always contains at least primary range). -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Selection { ranges: SmallVec<[Range; 1]>, primary_index: usize, diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ddee8b93..d2aa481a 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -238,11 +238,13 @@ pub fn move_next_word_end(cx: &mut Context) { } pub fn move_file_start(cx: &mut Context) { + push_jump(cx); let doc = cx.doc(); doc.set_selection(Selection::point(0)); } pub fn move_file_end(cx: &mut Context) { + push_jump(cx); let doc = cx.doc(); let text = doc.text(); let last_line = text.line_to_char(text.len_lines().saturating_sub(2)); @@ -1027,9 +1029,21 @@ pub fn normal_mode(cx: &mut Context) { } } +// Store a jump on the jumplist. +fn push_jump(cx: &mut Context) { + let jump = { + let doc = cx.doc(); + (doc.id(), doc.selection().clone()) + }; + cx.view().jumps.push(jump); +} + pub fn goto_mode(cx: &mut Context) { let count = cx.count; + if count > 1 { + push_jump(cx); + // TODO: can't go to line 1 since we can't distinguish between g and 1g, g gets converted // to 1g let doc = cx.doc(); @@ -1069,6 +1083,8 @@ pub fn exit_select_mode(cx: &mut Context) { fn _goto(cx: &mut Context, locations: Vec) { use helix_view::editor::Action; + push_jump(cx); + fn jump_to(editor: &mut Editor, location: &lsp::Location, action: Action) { let id = editor .open(PathBuf::from(location.uri.path()), action) diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index f401f0f9..d7a72377 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -258,6 +258,7 @@ pub fn default() -> Keymaps { ctrl!('i') => commands::jump_forward, // TODO: ctrl-i conflicts tab ctrl!('o') => commands::jump_backward, + // ctrl!('s') => commands::save_selection, ); // TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether // we keep this separate select mode. More keys can fit into normal mode then, but it's weird diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 8cb82fcb..0e38e598 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -49,7 +49,7 @@ pub fn regex_prompt( doc.set_selection(snapshot.clone()); } PromptEvent::Validate => { - // + // TODO: push_jump to store selection just before jump } PromptEvent::Update => { // skip empty input, TODO: trigger default diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index abc829c0..6e73104a 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -274,6 +274,11 @@ impl Document { self.history.commit_revision(&transaction, &old_state); } + #[inline] + pub fn id(&self) -> DocumentId { + self.id + } + #[inline] pub fn mode(&self) -> Mode { self.mode diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 7a239d4a..9e4c1373 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -27,9 +27,12 @@ impl JumpList { } pub fn push(&mut self, jump: Jump) { - self.jumps.truncate(self.current + 1); - self.jumps.push(jump); - self.current += 1; + self.jumps.truncate(self.current); + // don't push duplicates + if self.jumps.last() != Some(&jump) { + self.jumps.push(jump); + self.current = self.jumps.len(); + } } pub fn forward(&mut self, count: usize) -> Option<&Jump> {