summaryrefslogtreecommitdiff
path: root/helix-core/src/object.rs
diff options
context:
space:
mode:
authorMatouš Dzivjak2022-01-06 02:12:02 +0000
committerGitHub2022-01-06 02:12:02 +0000
commit2e02a1d6bc004212033b9c4e5ed0de0fd880796c (patch)
treee73a695e58ddf7242d3cab282b93dd1ad9488ee5 /helix-core/src/object.rs
parent66afbc9fff1ec5947ea5718f7817887aa0c853c8 (diff)
feat(commands): shrink_selection (#1340)
* feat(commands): shrink_selection Add `shrink_selection` command that can be used to shrink previously expanded selection. To make `shrink_selection` work it was necessary to add selection history to the Document since we want to shrink the selection towards the syntax tree node that was initially selected. Selection history is cleared any time the user changes selection other way than by `expand_selection`. This ensures that we don't get some funky edge cases when user calls `shrink_selection`. Related: https://github.com/helix-editor/helix/discussions/1328 * Refactor shrink_selection, move history to view * Remove useless comment * Add default key mapping for extend&shrink selection * Rework contains_selection method * Shrink selection without expand selects first child
Diffstat (limited to 'helix-core/src/object.rs')
-rw-r--r--helix-core/src/object.rs29
1 files changed, 27 insertions, 2 deletions
diff --git a/helix-core/src/object.rs b/helix-core/src/object.rs
index 717c5994..21fa24fb 100644
--- a/helix-core/src/object.rs
+++ b/helix-core/src/object.rs
@@ -1,7 +1,5 @@
use crate::{Range, RopeSlice, Selection, Syntax};
-// TODO: to contract_selection we'd need to store the previous ranges before expand.
-// Maybe just contract to the first child node?
pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: &Selection) -> Selection {
let tree = syntax.tree();
@@ -34,3 +32,30 @@ pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: &Selection)
}
})
}
+
+pub fn shrink_selection(syntax: &Syntax, text: RopeSlice, selection: &Selection) -> Selection {
+ let tree = syntax.tree();
+
+ selection.clone().transform(|range| {
+ let from = text.char_to_byte(range.from());
+ let to = text.char_to_byte(range.to());
+
+ let descendant = match tree.root_node().descendant_for_byte_range(from, to) {
+ // find first child, if not possible, fallback to the node that contains selection
+ Some(descendant) => match descendant.child(0) {
+ Some(child) => child,
+ None => descendant,
+ },
+ None => return range,
+ };
+
+ let from = text.byte_to_char(descendant.start_byte());
+ let to = text.byte_to_char(descendant.end_byte());
+
+ if range.head < range.anchor {
+ Range::new(to, from)
+ } else {
+ Range::new(from, to)
+ }
+ })
+}