aboutsummaryrefslogtreecommitdiff
path: root/libeditor
diff options
context:
space:
mode:
Diffstat (limited to 'libeditor')
-rw-r--r--libeditor/Cargo.toml1
-rw-r--r--libeditor/src/extend_selection.rs36
-rw-r--r--libeditor/src/lib.rs29
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]
8libsyntax2 = { path = "../" } 8libsyntax2 = { path = "../" }
9text_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 @@
1use libsyntax2::{
2 TextRange, SyntaxNodeRef,
3 SyntaxKind::WHITESPACE,
4 algo::{find_leaf_at_offset, find_covering_node, ancestors},
5};
6
7
8pub(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 @@
1extern crate libsyntax2; 1extern crate libsyntax2;
2extern crate text_unit; 2
3mod extend_selection;
3 4
4use libsyntax2::{ 5use libsyntax2::{
5 SyntaxNodeRef, 6 SyntaxNodeRef,
6 algo::walk, 7 algo::walk,
7 SyntaxKind::*, 8 SyntaxKind::*,
8}; 9};
9use text_unit::TextRange; 10pub use libsyntax2::{TextRange, TextUnit};
10 11
11pub struct File { 12pub 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)]
107mod 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}