diff options
Diffstat (limited to 'crates/libeditor/src/lib.rs')
-rw-r--r-- | crates/libeditor/src/lib.rs | 228 |
1 files changed, 0 insertions, 228 deletions
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs deleted file mode 100644 index b3cf2ef55..000000000 --- a/crates/libeditor/src/lib.rs +++ /dev/null | |||
@@ -1,228 +0,0 @@ | |||
1 | extern crate libsyntax2; | ||
2 | extern crate superslice; | ||
3 | extern crate itertools; | ||
4 | extern crate join_to_string; | ||
5 | #[cfg(test)] | ||
6 | #[macro_use] | ||
7 | extern crate test_utils as _test_utils; | ||
8 | |||
9 | mod extend_selection; | ||
10 | mod symbols; | ||
11 | mod line_index; | ||
12 | mod edit; | ||
13 | mod code_actions; | ||
14 | mod typing; | ||
15 | mod completion; | ||
16 | mod scope; | ||
17 | #[cfg(test)] | ||
18 | mod test_utils; | ||
19 | |||
20 | use libsyntax2::{ | ||
21 | File, TextUnit, TextRange, SyntaxNodeRef, | ||
22 | ast::{self, AstNode, NameOwner}, | ||
23 | algo::{walk, find_leaf_at_offset, ancestors}, | ||
24 | SyntaxKind::{self, *}, | ||
25 | }; | ||
26 | pub use libsyntax2::AtomEdit; | ||
27 | pub use self::{ | ||
28 | line_index::{LineIndex, LineCol}, | ||
29 | extend_selection::extend_selection, | ||
30 | symbols::{StructureNode, file_structure, FileSymbol, file_symbols}, | ||
31 | edit::{EditBuilder, Edit}, | ||
32 | code_actions::{ | ||
33 | LocalEdit, | ||
34 | flip_comma, add_derive, add_impl, | ||
35 | introduce_variable, | ||
36 | }, | ||
37 | typing::{join_lines, on_eq_typed}, | ||
38 | completion::{scope_completion, CompletionItem}, | ||
39 | }; | ||
40 | |||
41 | #[derive(Debug)] | ||
42 | pub struct HighlightedRange { | ||
43 | pub range: TextRange, | ||
44 | pub tag: &'static str, | ||
45 | } | ||
46 | |||
47 | #[derive(Debug)] | ||
48 | pub struct Diagnostic { | ||
49 | pub range: TextRange, | ||
50 | pub msg: String, | ||
51 | } | ||
52 | |||
53 | #[derive(Debug)] | ||
54 | pub struct Runnable { | ||
55 | pub range: TextRange, | ||
56 | pub kind: RunnableKind, | ||
57 | } | ||
58 | |||
59 | #[derive(Debug)] | ||
60 | pub enum RunnableKind { | ||
61 | Test { name: String }, | ||
62 | Bin, | ||
63 | } | ||
64 | |||
65 | pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { | ||
66 | const BRACES: &[SyntaxKind] = &[ | ||
67 | L_CURLY, R_CURLY, | ||
68 | L_BRACK, R_BRACK, | ||
69 | L_PAREN, R_PAREN, | ||
70 | L_ANGLE, R_ANGLE, | ||
71 | ]; | ||
72 | let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset) | ||
73 | .filter_map(|node| { | ||
74 | let idx = BRACES.iter().position(|&brace| brace == node.kind())?; | ||
75 | Some((node, idx)) | ||
76 | }) | ||
77 | .next()?; | ||
78 | let parent = brace_node.parent()?; | ||
79 | let matching_kind = BRACES[brace_idx ^ 1]; | ||
80 | let matching_node = parent.children() | ||
81 | .find(|node| node.kind() == matching_kind)?; | ||
82 | Some(matching_node.range().start()) | ||
83 | } | ||
84 | |||
85 | pub fn highlight(file: &File) -> Vec<HighlightedRange> { | ||
86 | let mut res = Vec::new(); | ||
87 | for node in walk::preorder(file.syntax()) { | ||
88 | let tag = match node.kind() { | ||
89 | ERROR => "error", | ||
90 | COMMENT | DOC_COMMENT => "comment", | ||
91 | STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", | ||
92 | ATTR => "attribute", | ||
93 | NAME_REF => "text", | ||
94 | NAME => "function", | ||
95 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", | ||
96 | LIFETIME => "parameter", | ||
97 | k if k.is_keyword() => "keyword", | ||
98 | _ => continue, | ||
99 | }; | ||
100 | res.push(HighlightedRange { | ||
101 | range: node.range(), | ||
102 | tag, | ||
103 | }) | ||
104 | } | ||
105 | res | ||
106 | } | ||
107 | |||
108 | pub fn diagnostics(file: &File) -> Vec<Diagnostic> { | ||
109 | let mut res = Vec::new(); | ||
110 | |||
111 | for node in walk::preorder(file.syntax()) { | ||
112 | if node.kind() == ERROR { | ||
113 | res.push(Diagnostic { | ||
114 | range: node.range(), | ||
115 | msg: "Syntax Error".to_string(), | ||
116 | }); | ||
117 | } | ||
118 | } | ||
119 | res.extend(file.errors().into_iter().map(|err| Diagnostic { | ||
120 | range: TextRange::offset_len(err.offset, 1.into()), | ||
121 | msg: err.msg, | ||
122 | })); | ||
123 | res | ||
124 | } | ||
125 | |||
126 | pub fn syntax_tree(file: &File) -> String { | ||
127 | ::libsyntax2::utils::dump_tree(file.syntax()) | ||
128 | } | ||
129 | |||
130 | pub fn runnables(file: &File) -> Vec<Runnable> { | ||
131 | walk::preorder(file.syntax()) | ||
132 | .filter_map(ast::FnDef::cast) | ||
133 | .filter_map(|f| { | ||
134 | let name = f.name()?.text(); | ||
135 | let kind = if name == "main" { | ||
136 | RunnableKind::Bin | ||
137 | } else if f.has_atom_attr("test") { | ||
138 | RunnableKind::Test { | ||
139 | name: name.to_string() | ||
140 | } | ||
141 | } else { | ||
142 | return None; | ||
143 | }; | ||
144 | Some(Runnable { | ||
145 | range: f.syntax().range(), | ||
146 | kind, | ||
147 | }) | ||
148 | }) | ||
149 | .collect() | ||
150 | } | ||
151 | |||
152 | pub fn find_node_at_offset<'a, N: AstNode<'a>>( | ||
153 | syntax: SyntaxNodeRef<'a>, | ||
154 | offset: TextUnit, | ||
155 | ) -> Option<N> { | ||
156 | let leaves = find_leaf_at_offset(syntax, offset); | ||
157 | let leaf = leaves.clone() | ||
158 | .find(|leaf| !leaf.kind().is_trivia()) | ||
159 | .or_else(|| leaves.right_biased())?; | ||
160 | ancestors(leaf) | ||
161 | .filter_map(N::cast) | ||
162 | .next() | ||
163 | } | ||
164 | |||
165 | #[cfg(test)] | ||
166 | mod tests { | ||
167 | use super::*; | ||
168 | use test_utils::{assert_eq_dbg, extract_offset, add_cursor}; | ||
169 | |||
170 | #[test] | ||
171 | fn test_highlighting() { | ||
172 | let file = File::parse(r#" | ||
173 | // comment | ||
174 | fn main() {} | ||
175 | println!("Hello, {}!", 92); | ||
176 | "#); | ||
177 | let hls = highlight(&file); | ||
178 | assert_eq_dbg( | ||
179 | r#"[HighlightedRange { range: [1; 11), tag: "comment" }, | ||
180 | HighlightedRange { range: [12; 14), tag: "keyword" }, | ||
181 | HighlightedRange { range: [15; 19), tag: "function" }, | ||
182 | HighlightedRange { range: [29; 36), tag: "text" }, | ||
183 | HighlightedRange { range: [38; 50), tag: "string" }, | ||
184 | HighlightedRange { range: [52; 54), tag: "literal" }]"#, | ||
185 | &hls, | ||
186 | ); | ||
187 | } | ||
188 | |||
189 | #[test] | ||
190 | fn test_runnables() { | ||
191 | let file = File::parse(r#" | ||
192 | fn main() {} | ||
193 | |||
194 | #[test] | ||
195 | fn test_foo() {} | ||
196 | |||
197 | #[test] | ||
198 | #[ignore] | ||
199 | fn test_foo() {} | ||
200 | "#); | ||
201 | let runnables = runnables(&file); | ||
202 | assert_eq_dbg( | ||
203 | r#"[Runnable { range: [1; 13), kind: Bin }, | ||
204 | Runnable { range: [15; 39), kind: Test { name: "test_foo" } }, | ||
205 | Runnable { range: [41; 75), kind: Test { name: "test_foo" } }]"#, | ||
206 | &runnables, | ||
207 | ) | ||
208 | } | ||
209 | |||
210 | #[test] | ||
211 | fn test_matching_brace() { | ||
212 | fn do_check(before: &str, after: &str) { | ||
213 | let (pos, before) = extract_offset(before); | ||
214 | let file = File::parse(&before); | ||
215 | let new_pos = match matching_brace(&file, pos) { | ||
216 | None => pos, | ||
217 | Some(pos) => pos, | ||
218 | }; | ||
219 | let actual = add_cursor(&before, new_pos); | ||
220 | assert_eq_text!(after, &actual); | ||
221 | } | ||
222 | |||
223 | do_check( | ||
224 | "struct Foo { a: i32, }<|>", | ||
225 | "struct Foo <|>{ a: i32, }", | ||
226 | ); | ||
227 | } | ||
228 | } | ||