Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | helix-term/src/commands.rs | 49 | ||||
| -rw-r--r-- | helix-view/src/document.rs | 35 | ||||
| -rw-r--r-- | helix-view/src/view.rs | 3 |
3 files changed, 61 insertions, 26 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8edf5944..aafe9619 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3942,6 +3942,7 @@ fn goto_first_diag(cx: &mut Context) { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; + doc.set_selection(view.id, selection); view.diagnostics_handler .immediately_show_diagnostic(doc, view.id); @@ -3953,6 +3954,7 @@ fn goto_last_diag(cx: &mut Context) { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; + doc.set_selection(view.id, selection); view.diagnostics_handler .immediately_show_diagnostic(doc, view.id); @@ -4009,6 +4011,7 @@ fn goto_prev_diag(cx: &mut Context) { view.diagnostics_handler .immediately_show_diagnostic(doc, view.id); }; + cx.editor.apply_motion(motion) } @@ -5444,6 +5447,8 @@ fn reverse_selection_contents(cx: &mut Context) { // tree sitter node selection +const EXPAND_KEY: &str = "expand"; + fn expand_selection(cx: &mut Context) { let motion = |editor: &mut Editor| { let (view, doc) = current!(editor); @@ -5451,42 +5456,52 @@ fn expand_selection(cx: &mut Context) { if let Some(syntax) = doc.syntax() { let text = doc.text().slice(..); - let current_selection = doc.selection(view.id); + let current_selection = doc.selection(view.id).clone(); let selection = object::expand_selection(syntax, text, current_selection.clone()); // check if selection is different from the last one - if *current_selection != selection { - // save current selection so it can be restored using shrink_selection - view.object_selections.push(current_selection.clone()); + if current_selection != selection { + let prev_selections = doc + .view_data_mut(view.id) + .object_selections + .entry(EXPAND_KEY) + .or_default(); - doc.set_selection(view.id, selection); + // save current selection so it can be restored using shrink_selection + prev_selections.push(current_selection); + doc.set_selection_clear(view.id, selection, false); } } }; + cx.editor.apply_motion(motion); } fn shrink_selection(cx: &mut Context) { let motion = |editor: &mut Editor| { let (view, doc) = current!(editor); - let current_selection = doc.selection(view.id); + let current_selection = doc.selection(view.id).clone(); + let prev_expansions = doc + .view_data_mut(view.id) + .object_selections + .entry(EXPAND_KEY) + .or_default(); + // try to restore previous selection - if let Some(prev_selection) = view.object_selections.pop() { - if current_selection.contains(&prev_selection) { - doc.set_selection(view.id, prev_selection); - return; - } else { - // clear existing selection as they can't be shrunk to anyway - view.object_selections.clear(); - } + if let Some(prev_selection) = prev_expansions.pop() { + // allow shrinking the selection only if current selection contains the previous object selection + doc.set_selection_clear(view.id, prev_selection, false); + return; } + // if not previous selection, shrink to first child if let Some(syntax) = doc.syntax() { let text = doc.text().slice(..); - let selection = object::shrink_selection(syntax, text, current_selection.clone()); - doc.set_selection(view.id, selection); + let selection = object::shrink_selection(syntax, text, current_selection); + doc.set_selection_clear(view.id, selection, false); } }; + cx.editor.apply_motion(motion); } @@ -5605,8 +5620,6 @@ fn match_brackets(cx: &mut Context) { doc.set_selection(view.id, selection); } -// - fn jump_forward(cx: &mut Context) { let count = cx.count(); let config = cx.editor.config(); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 04b7703c..c0672001 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1320,15 +1320,27 @@ impl Document { Ok(()) } - /// Select text within the [`Document`]. - pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) { + /// Select text within the [`Document`], optionally clearing the previous selection state. + pub fn set_selection_clear(&mut self, view_id: ViewId, selection: Selection, clear_prev: bool) { // TODO: use a transaction? self.selections .insert(view_id, selection.ensure_invariants(self.text().slice(..))); + helix_event::dispatch(SelectionDidChange { doc: self, view: view_id, - }) + }); + + if clear_prev { + self.view_data + .entry(view_id) + .and_modify(|view_data| view_data.object_selections.clear()); + } + } + + /// Select text within the [`Document`]. + pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) { + self.set_selection_clear(view_id, selection, true); } /// Find the origin selection of the text in a document, i.e. where @@ -1520,6 +1532,12 @@ impl Document { apply_inlay_hint_changes(padding_after_inlay_hints); } + // clear out all associated view object selections, as they are no + // longer valid + self.view_data + .values_mut() + .for_each(|view_data| view_data.object_selections.clear()); + helix_event::dispatch(DocumentDidChange { doc: self, view: view_id, @@ -1962,13 +1980,13 @@ impl Document { &self.selections } - fn view_data(&self, view_id: ViewId) -> &ViewData { + pub fn view_data(&self, view_id: ViewId) -> &ViewData { self.view_data .get(&view_id) .expect("This should only be called after ensure_view_init") } - fn view_data_mut(&mut self, view_id: ViewId) -> &mut ViewData { + pub fn view_data_mut(&mut self, view_id: ViewId) -> &mut ViewData { self.view_data.entry(view_id).or_default() } @@ -2286,9 +2304,13 @@ impl Document { } } +/// Stores data needed for views that are tied to this specific Document. #[derive(Debug, Default)] pub struct ViewData { view_position: ViewPosition, + + /// used to store previous selections of tree-sitter objects + pub object_selections: HashMap<&'static str, Vec<Selection>>, } #[derive(Clone, Debug)] @@ -2339,6 +2361,7 @@ mod test { Arc::new(ArcSwap::from_pointee(syntax::Loader::default())), ); let view = ViewId::default(); + doc.ensure_view_init(view); doc.set_selection(view, Selection::single(0, 0)); let transaction = @@ -2377,7 +2400,9 @@ mod test { Arc::new(ArcSwap::new(Arc::new(Config::default()))), Arc::new(ArcSwap::from_pointee(syntax::Loader::default())), ); + let view = ViewId::default(); + doc.ensure_view_init(view); doc.set_selection(view, Selection::single(5, 5)); // insert diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index aecf09a6..d275befb 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -137,8 +137,6 @@ pub struct View { // uses two docs because we want to be able to swap between the // two last modified docs which we need to manually keep track of pub last_modified_docs: [Option<DocumentId>; 2], - /// used to store previous selections of tree-sitter objects - pub object_selections: Vec<Selection>, /// all gutter-related configuration settings, used primarily for gutter rendering pub gutters: GutterConfig, /// A mapping between documents and the last history revision the view was updated at. @@ -175,7 +173,6 @@ impl View { jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel docs_access_history: Vec::new(), last_modified_docs: [None, None], - object_selections: Vec::new(), gutters, doc_revisions: HashMap::new(), diagnostics_handler: DiagnosticsHandler::new(), |