diff options
Diffstat (limited to 'libeditor')
-rw-r--r-- | libeditor/Cargo.toml | 1 | ||||
-rw-r--r-- | libeditor/src/extend_selection.rs | 36 | ||||
-rw-r--r-- | libeditor/src/lib.rs | 29 |
3 files changed, 63 insertions, 3 deletions
diff --git a/libeditor/Cargo.toml b/libeditor/Cargo.toml index 1a532ce2f..92abd3289 100644 --- a/libeditor/Cargo.toml +++ b/libeditor/Cargo.toml | |||
@@ -6,4 +6,3 @@ publish = false | |||
6 | 6 | ||
7 | [dependencies] | 7 | [dependencies] |
8 | libsyntax2 = { path = "../" } | 8 | libsyntax2 = { path = "../" } |
9 | text_unit = "0.1.2" | ||
diff --git a/libeditor/src/extend_selection.rs b/libeditor/src/extend_selection.rs new file mode 100644 index 000000000..16d4bc084 --- /dev/null +++ b/libeditor/src/extend_selection.rs | |||
@@ -0,0 +1,36 @@ | |||
1 | use libsyntax2::{ | ||
2 | TextRange, SyntaxNodeRef, | ||
3 | SyntaxKind::WHITESPACE, | ||
4 | algo::{find_leaf_at_offset, find_covering_node, ancestors}, | ||
5 | }; | ||
6 | |||
7 | |||
8 | pub(crate) fn extend_selection(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange> { | ||
9 | if range.is_empty() { | ||
10 | let offset = range.start(); | ||
11 | let mut leaves = find_leaf_at_offset(root, offset); | ||
12 | if let Some(leaf) = leaves.clone().find(|node| node.kind() != WHITESPACE) { | ||
13 | return Some(leaf.range()); | ||
14 | } | ||
15 | let ws = leaves.next()?; | ||
16 | // let ws_suffix = file.text().slice( | ||
17 | // TextRange::from_to(offset, ws.range().end()) | ||
18 | // ); | ||
19 | // if ws.text().contains("\n") && !ws_suffix.contains("\n") { | ||
20 | // if let Some(line_end) = file.text() | ||
21 | // .slice(TextSuffix::from(ws.range().end())) | ||
22 | // .find("\n") | ||
23 | // { | ||
24 | // let range = TextRange::from_len(ws.range().end(), line_end); | ||
25 | // return Some(find_covering_node(file.root(), range).range()); | ||
26 | // } | ||
27 | // } | ||
28 | return Some(ws.range()); | ||
29 | }; | ||
30 | let node = find_covering_node(root, range); | ||
31 | |||
32 | match ancestors(node).skip_while(|n| n.range() == range).next() { | ||
33 | None => None, | ||
34 | Some(parent) => Some(parent.range()), | ||
35 | } | ||
36 | } | ||
diff --git a/libeditor/src/lib.rs b/libeditor/src/lib.rs index 091aed125..a0c003fb5 100644 --- a/libeditor/src/lib.rs +++ b/libeditor/src/lib.rs | |||
@@ -1,12 +1,13 @@ | |||
1 | extern crate libsyntax2; | 1 | extern crate libsyntax2; |
2 | extern crate text_unit; | 2 | |
3 | mod extend_selection; | ||
3 | 4 | ||
4 | use libsyntax2::{ | 5 | use libsyntax2::{ |
5 | SyntaxNodeRef, | 6 | SyntaxNodeRef, |
6 | algo::walk, | 7 | algo::walk, |
7 | SyntaxKind::*, | 8 | SyntaxKind::*, |
8 | }; | 9 | }; |
9 | use text_unit::TextRange; | 10 | pub use libsyntax2::{TextRange, TextUnit}; |
10 | 11 | ||
11 | pub struct File { | 12 | pub struct File { |
12 | inner: libsyntax2::File | 13 | inner: libsyntax2::File |
@@ -71,6 +72,11 @@ impl File { | |||
71 | .collect(); | 72 | .collect(); |
72 | res // NLL :-( | 73 | res // NLL :-( |
73 | } | 74 | } |
75 | |||
76 | pub fn extend_selection(&self, range: TextRange) -> Option<TextRange> { | ||
77 | let syntax = self.inner.syntax(); | ||
78 | extend_selection::extend_selection(syntax.as_ref(), range) | ||
79 | } | ||
74 | } | 80 | } |
75 | 81 | ||
76 | 82 | ||
@@ -96,3 +102,22 @@ impl<'f> Declaration<'f> { | |||
96 | self.0.range() | 102 | self.0.range() |
97 | } | 103 | } |
98 | } | 104 | } |
105 | |||
106 | #[cfg(test)] | ||
107 | mod tests { | ||
108 | use super::*; | ||
109 | |||
110 | #[test] | ||
111 | fn test_extend_selection() { | ||
112 | let text = r#"fn foo() { | ||
113 | 1 + 1 | ||
114 | } | ||
115 | "#; | ||
116 | let file = File::new(text); | ||
117 | let range = TextRange::offset_len(18.into(), 0.into()); | ||
118 | let range = file.extend_selection(range).unwrap(); | ||
119 | assert_eq!(range, TextRange::from_to(17.into(), 18.into())); | ||
120 | let range = file.extend_selection(range).unwrap(); | ||
121 | assert_eq!(range, TextRange::from_to(15.into(), 20.into())); | ||
122 | } | ||
123 | } | ||