aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor/src/lib.rs')
-rw-r--r--crates/libeditor/src/lib.rs228
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 @@
1extern crate libsyntax2;
2extern crate superslice;
3extern crate itertools;
4extern crate join_to_string;
5#[cfg(test)]
6#[macro_use]
7extern crate test_utils as _test_utils;
8
9mod extend_selection;
10mod symbols;
11mod line_index;
12mod edit;
13mod code_actions;
14mod typing;
15mod completion;
16mod scope;
17#[cfg(test)]
18mod test_utils;
19
20use libsyntax2::{
21 File, TextUnit, TextRange, SyntaxNodeRef,
22 ast::{self, AstNode, NameOwner},
23 algo::{walk, find_leaf_at_offset, ancestors},
24 SyntaxKind::{self, *},
25};
26pub use libsyntax2::AtomEdit;
27pub 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)]
42pub struct HighlightedRange {
43 pub range: TextRange,
44 pub tag: &'static str,
45}
46
47#[derive(Debug)]
48pub struct Diagnostic {
49 pub range: TextRange,
50 pub msg: String,
51}
52
53#[derive(Debug)]
54pub struct Runnable {
55 pub range: TextRange,
56 pub kind: RunnableKind,
57}
58
59#[derive(Debug)]
60pub enum RunnableKind {
61 Test { name: String },
62 Bin,
63}
64
65pub 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
85pub 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
108pub 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
126pub fn syntax_tree(file: &File) -> String {
127 ::libsyntax2::utils::dump_tree(file.syntax())
128}
129
130pub 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
152pub 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)]
166mod 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
174fn 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#"
192fn main() {}
193
194#[test]
195fn test_foo() {}
196
197#[test]
198#[ignore]
199fn 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}