diff options
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/ra_ide_api/src/syntax_tree.rs | 87 | ||||
-rw-r--r-- | crates/ra_ide_api/tests/test/main.rs | 254 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 4 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/req.rs | 1 | ||||
-rw-r--r-- | editors/code/package.json | 2 | ||||
-rw-r--r-- | editors/code/src/commands/syntaxTree.ts | 46 | ||||
-rw-r--r-- | editors/code/src/events/change_active_text_editor.ts | 39 | ||||
-rw-r--r-- | editors/code/src/events/change_text_document.ts | 10 | ||||
-rw-r--r-- | editors/code/src/extension.ts | 16 |
10 files changed, 423 insertions, 43 deletions
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 6546d0644..b8a4adbce 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -32,13 +32,14 @@ mod references; | |||
32 | mod impls; | 32 | mod impls; |
33 | mod assists; | 33 | mod assists; |
34 | mod diagnostics; | 34 | mod diagnostics; |
35 | mod syntax_tree; | ||
35 | 36 | ||
36 | #[cfg(test)] | 37 | #[cfg(test)] |
37 | mod marks; | 38 | mod marks; |
38 | 39 | ||
39 | use std::sync::Arc; | 40 | use std::sync::Arc; |
40 | 41 | ||
41 | use ra_syntax::{SourceFile, TreeArc, TextRange, TextUnit, AstNode}; | 42 | use ra_syntax::{SourceFile, TreeArc, TextRange, TextUnit}; |
42 | use ra_text_edit::TextEdit; | 43 | use ra_text_edit::TextEdit; |
43 | use ra_db::{ | 44 | use ra_db::{ |
44 | SourceDatabase, CheckCanceled, | 45 | SourceDatabase, CheckCanceled, |
@@ -245,8 +246,8 @@ impl Analysis { | |||
245 | 246 | ||
246 | /// Returns a syntax tree represented as `String`, for debug purposes. | 247 | /// Returns a syntax tree represented as `String`, for debug purposes. |
247 | // FIXME: use a better name here. | 248 | // FIXME: use a better name here. |
248 | pub fn syntax_tree(&self, file_id: FileId) -> String { | 249 | pub fn syntax_tree(&self, file_id: FileId, text_range: Option<TextRange>) -> String { |
249 | self.db.parse(file_id).syntax().debug_dump() | 250 | syntax_tree::syntax_tree(&self.db, file_id, text_range) |
250 | } | 251 | } |
251 | 252 | ||
252 | /// Returns an edit to remove all newlines in the range, cleaning up minor | 253 | /// Returns an edit to remove all newlines in the range, cleaning up minor |
diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs new file mode 100644 index 000000000..bbe9222b4 --- /dev/null +++ b/crates/ra_ide_api/src/syntax_tree.rs | |||
@@ -0,0 +1,87 @@ | |||
1 | use ra_db::SourceDatabase; | ||
2 | use crate::db::RootDatabase; | ||
3 | use ra_syntax::{ | ||
4 | SourceFile, SyntaxNode, TextRange, AstNode, | ||
5 | algo::{self, visit::{visitor, Visitor}}, ast::{self, AstToken} | ||
6 | }; | ||
7 | |||
8 | pub use ra_db::FileId; | ||
9 | |||
10 | pub(crate) fn syntax_tree( | ||
11 | db: &RootDatabase, | ||
12 | file_id: FileId, | ||
13 | text_range: Option<TextRange>, | ||
14 | ) -> String { | ||
15 | if let Some(text_range) = text_range { | ||
16 | let file = db.parse(file_id); | ||
17 | let node = algo::find_covering_node(file.syntax(), text_range); | ||
18 | |||
19 | if let Some(tree) = syntax_tree_for_string(node, text_range) { | ||
20 | return tree; | ||
21 | } | ||
22 | |||
23 | node.debug_dump() | ||
24 | } else { | ||
25 | db.parse(file_id).syntax().debug_dump() | ||
26 | } | ||
27 | } | ||
28 | |||
29 | /// Attempts parsing the selected contents of a string literal | ||
30 | /// as rust syntax and returns its syntax tree | ||
31 | fn syntax_tree_for_string(node: &SyntaxNode, text_range: TextRange) -> Option<String> { | ||
32 | // When the range is inside a string | ||
33 | // we'll attempt parsing it as rust syntax | ||
34 | // to provide the syntax tree of the contents of the string | ||
35 | visitor() | ||
36 | .visit(|node: &ast::String| syntax_tree_for_token(node, text_range)) | ||
37 | .visit(|node: &ast::RawString| syntax_tree_for_token(node, text_range)) | ||
38 | .accept(node)? | ||
39 | } | ||
40 | |||
41 | fn syntax_tree_for_token<T: AstToken>(node: &T, text_range: TextRange) -> Option<String> { | ||
42 | // Range of the full node | ||
43 | let node_range = node.syntax().range(); | ||
44 | let text = node.text().to_string(); | ||
45 | |||
46 | // We start at some point inside the node | ||
47 | // Either we have selected the whole string | ||
48 | // or our selection is inside it | ||
49 | let start = text_range.start() - node_range.start(); | ||
50 | |||
51 | // how many characters we have selected | ||
52 | let len = text_range.len().to_usize(); | ||
53 | |||
54 | let node_len = node_range.len().to_usize(); | ||
55 | |||
56 | let start = start.to_usize(); | ||
57 | |||
58 | // We want to cap our length | ||
59 | let len = len.min(node_len); | ||
60 | |||
61 | // Ensure our slice is inside the actual string | ||
62 | let end = if start + len < text.len() { start + len } else { text.len() - start }; | ||
63 | |||
64 | let text = &text[start..end]; | ||
65 | |||
66 | // Remove possible extra string quotes from the start | ||
67 | // and the end of the string | ||
68 | let text = text | ||
69 | .trim_start_matches('r') | ||
70 | .trim_start_matches('#') | ||
71 | .trim_start_matches('"') | ||
72 | .trim_end_matches('#') | ||
73 | .trim_end_matches('"') | ||
74 | .trim() | ||
75 | // Remove custom markers | ||
76 | .replace("<|>", ""); | ||
77 | |||
78 | let parsed = SourceFile::parse(&text); | ||
79 | |||
80 | // If the "file" parsed without errors, | ||
81 | // return its syntax | ||
82 | if parsed.errors().is_empty() { | ||
83 | return Some(parsed.syntax().debug_dump()); | ||
84 | } | ||
85 | |||
86 | None | ||
87 | } | ||
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs index ff1a0e46b..0f0766f62 100644 --- a/crates/ra_ide_api/tests/test/main.rs +++ b/crates/ra_ide_api/tests/test/main.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use insta::assert_debug_snapshot_matches; | 1 | use insta::assert_debug_snapshot_matches; |
2 | use ra_ide_api::{ | 2 | use ra_ide_api::{ |
3 | mock_analysis::{single_file, single_file_with_position, MockAnalysis}, | 3 | mock_analysis::{single_file, single_file_with_position, single_file_with_range, MockAnalysis}, |
4 | AnalysisChange, CrateGraph, Edition::Edition2018, Query, NavigationTarget, | 4 | AnalysisChange, CrateGraph, Edition::Edition2018, Query, NavigationTarget, |
5 | ReferenceSearchResult, | 5 | ReferenceSearchResult, |
6 | }; | 6 | }; |
@@ -138,3 +138,255 @@ mod foo { | |||
138 | assert_eq!(s.name(), "FooInner"); | 138 | assert_eq!(s.name(), "FooInner"); |
139 | assert_eq!(s.container_name(), Some(&SmolStr::new("foo"))); | 139 | assert_eq!(s.container_name(), Some(&SmolStr::new("foo"))); |
140 | } | 140 | } |
141 | |||
142 | #[test] | ||
143 | fn test_syntax_tree_without_range() { | ||
144 | // Basic syntax | ||
145 | let (analysis, file_id) = single_file(r#"fn foo() {}"#); | ||
146 | let syn = analysis.syntax_tree(file_id, None); | ||
147 | |||
148 | assert_eq!( | ||
149 | syn.trim(), | ||
150 | r#" | ||
151 | SOURCE_FILE@[0; 11) | ||
152 | FN_DEF@[0; 11) | ||
153 | FN_KW@[0; 2) | ||
154 | WHITESPACE@[2; 3) | ||
155 | NAME@[3; 6) | ||
156 | IDENT@[3; 6) "foo" | ||
157 | PARAM_LIST@[6; 8) | ||
158 | L_PAREN@[6; 7) | ||
159 | R_PAREN@[7; 8) | ||
160 | WHITESPACE@[8; 9) | ||
161 | BLOCK@[9; 11) | ||
162 | L_CURLY@[9; 10) | ||
163 | R_CURLY@[10; 11) | ||
164 | "# | ||
165 | .trim() | ||
166 | ); | ||
167 | |||
168 | let (analysis, file_id) = single_file( | ||
169 | r#" | ||
170 | fn test() { | ||
171 | assert!(" | ||
172 | fn foo() { | ||
173 | } | ||
174 | ", ""); | ||
175 | }"# | ||
176 | .trim(), | ||
177 | ); | ||
178 | let syn = analysis.syntax_tree(file_id, None); | ||
179 | |||
180 | assert_eq!( | ||
181 | syn.trim(), | ||
182 | r#" | ||
183 | SOURCE_FILE@[0; 60) | ||
184 | FN_DEF@[0; 60) | ||
185 | FN_KW@[0; 2) | ||
186 | WHITESPACE@[2; 3) | ||
187 | NAME@[3; 7) | ||
188 | IDENT@[3; 7) "test" | ||
189 | PARAM_LIST@[7; 9) | ||
190 | L_PAREN@[7; 8) | ||
191 | R_PAREN@[8; 9) | ||
192 | WHITESPACE@[9; 10) | ||
193 | BLOCK@[10; 60) | ||
194 | L_CURLY@[10; 11) | ||
195 | WHITESPACE@[11; 16) | ||
196 | EXPR_STMT@[16; 58) | ||
197 | MACRO_CALL@[16; 57) | ||
198 | PATH@[16; 22) | ||
199 | PATH_SEGMENT@[16; 22) | ||
200 | NAME_REF@[16; 22) | ||
201 | IDENT@[16; 22) "assert" | ||
202 | EXCL@[22; 23) | ||
203 | TOKEN_TREE@[23; 57) | ||
204 | L_PAREN@[23; 24) | ||
205 | STRING@[24; 52) | ||
206 | COMMA@[52; 53) | ||
207 | WHITESPACE@[53; 54) | ||
208 | STRING@[54; 56) | ||
209 | R_PAREN@[56; 57) | ||
210 | SEMI@[57; 58) | ||
211 | WHITESPACE@[58; 59) | ||
212 | R_CURLY@[59; 60) | ||
213 | "# | ||
214 | .trim() | ||
215 | ); | ||
216 | } | ||
217 | |||
218 | #[test] | ||
219 | fn test_syntax_tree_with_range() { | ||
220 | let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim()); | ||
221 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | ||
222 | |||
223 | assert_eq!( | ||
224 | syn.trim(), | ||
225 | r#" | ||
226 | FN_DEF@[0; 11) | ||
227 | FN_KW@[0; 2) | ||
228 | WHITESPACE@[2; 3) | ||
229 | NAME@[3; 6) | ||
230 | IDENT@[3; 6) "foo" | ||
231 | PARAM_LIST@[6; 8) | ||
232 | L_PAREN@[6; 7) | ||
233 | R_PAREN@[7; 8) | ||
234 | WHITESPACE@[8; 9) | ||
235 | BLOCK@[9; 11) | ||
236 | L_CURLY@[9; 10) | ||
237 | R_CURLY@[10; 11) | ||
238 | "# | ||
239 | .trim() | ||
240 | ); | ||
241 | |||
242 | let (analysis, range) = single_file_with_range( | ||
243 | r#"fn test() { | ||
244 | <|>assert!(" | ||
245 | fn foo() { | ||
246 | } | ||
247 | ", "");<|> | ||
248 | }"# | ||
249 | .trim(), | ||
250 | ); | ||
251 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | ||
252 | |||
253 | assert_eq!( | ||
254 | syn.trim(), | ||
255 | r#" | ||
256 | EXPR_STMT@[16; 58) | ||
257 | MACRO_CALL@[16; 57) | ||
258 | PATH@[16; 22) | ||
259 | PATH_SEGMENT@[16; 22) | ||
260 | NAME_REF@[16; 22) | ||
261 | IDENT@[16; 22) "assert" | ||
262 | EXCL@[22; 23) | ||
263 | TOKEN_TREE@[23; 57) | ||
264 | L_PAREN@[23; 24) | ||
265 | STRING@[24; 52) | ||
266 | COMMA@[52; 53) | ||
267 | WHITESPACE@[53; 54) | ||
268 | STRING@[54; 56) | ||
269 | R_PAREN@[56; 57) | ||
270 | SEMI@[57; 58) | ||
271 | "# | ||
272 | .trim() | ||
273 | ); | ||
274 | } | ||
275 | |||
276 | #[test] | ||
277 | fn test_syntax_tree_inside_string() { | ||
278 | let (analysis, range) = single_file_with_range( | ||
279 | r#"fn test() { | ||
280 | assert!(" | ||
281 | <|>fn foo() { | ||
282 | }<|> | ||
283 | fn bar() { | ||
284 | } | ||
285 | ", ""); | ||
286 | }"# | ||
287 | .trim(), | ||
288 | ); | ||
289 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | ||
290 | assert_eq!( | ||
291 | syn.trim(), | ||
292 | r#" | ||
293 | SOURCE_FILE@[0; 12) | ||
294 | FN_DEF@[0; 12) | ||
295 | FN_KW@[0; 2) | ||
296 | WHITESPACE@[2; 3) | ||
297 | NAME@[3; 6) | ||
298 | IDENT@[3; 6) "foo" | ||
299 | PARAM_LIST@[6; 8) | ||
300 | L_PAREN@[6; 7) | ||
301 | R_PAREN@[7; 8) | ||
302 | WHITESPACE@[8; 9) | ||
303 | BLOCK@[9; 12) | ||
304 | L_CURLY@[9; 10) | ||
305 | WHITESPACE@[10; 11) | ||
306 | R_CURLY@[11; 12) | ||
307 | "# | ||
308 | .trim() | ||
309 | ); | ||
310 | |||
311 | // With a raw string | ||
312 | let (analysis, range) = single_file_with_range( | ||
313 | r###"fn test() { | ||
314 | assert!(r#" | ||
315 | <|>fn foo() { | ||
316 | }<|> | ||
317 | fn bar() { | ||
318 | } | ||
319 | "#, ""); | ||
320 | }"### | ||
321 | .trim(), | ||
322 | ); | ||
323 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | ||
324 | assert_eq!( | ||
325 | syn.trim(), | ||
326 | r#" | ||
327 | SOURCE_FILE@[0; 12) | ||
328 | FN_DEF@[0; 12) | ||
329 | FN_KW@[0; 2) | ||
330 | WHITESPACE@[2; 3) | ||
331 | NAME@[3; 6) | ||
332 | IDENT@[3; 6) "foo" | ||
333 | PARAM_LIST@[6; 8) | ||
334 | L_PAREN@[6; 7) | ||
335 | R_PAREN@[7; 8) | ||
336 | WHITESPACE@[8; 9) | ||
337 | BLOCK@[9; 12) | ||
338 | L_CURLY@[9; 10) | ||
339 | WHITESPACE@[10; 11) | ||
340 | R_CURLY@[11; 12) | ||
341 | "# | ||
342 | .trim() | ||
343 | ); | ||
344 | |||
345 | // With a raw string | ||
346 | let (analysis, range) = single_file_with_range( | ||
347 | r###"fn test() { | ||
348 | assert!(r<|>#" | ||
349 | fn foo() { | ||
350 | } | ||
351 | fn bar() { | ||
352 | }"<|>#, ""); | ||
353 | }"### | ||
354 | .trim(), | ||
355 | ); | ||
356 | let syn = analysis.syntax_tree(range.file_id, Some(range.range)); | ||
357 | assert_eq!( | ||
358 | syn.trim(), | ||
359 | r#" | ||
360 | SOURCE_FILE@[0; 25) | ||
361 | FN_DEF@[0; 12) | ||
362 | FN_KW@[0; 2) | ||
363 | WHITESPACE@[2; 3) | ||
364 | NAME@[3; 6) | ||
365 | IDENT@[3; 6) "foo" | ||
366 | PARAM_LIST@[6; 8) | ||
367 | L_PAREN@[6; 7) | ||
368 | R_PAREN@[7; 8) | ||
369 | WHITESPACE@[8; 9) | ||
370 | BLOCK@[9; 12) | ||
371 | L_CURLY@[9; 10) | ||
372 | WHITESPACE@[10; 11) | ||
373 | R_CURLY@[11; 12) | ||
374 | WHITESPACE@[12; 13) | ||
375 | FN_DEF@[13; 25) | ||
376 | FN_KW@[13; 15) | ||
377 | WHITESPACE@[15; 16) | ||
378 | NAME@[16; 19) | ||
379 | IDENT@[16; 19) "bar" | ||
380 | PARAM_LIST@[19; 21) | ||
381 | L_PAREN@[19; 20) | ||
382 | R_PAREN@[20; 21) | ||
383 | WHITESPACE@[21; 22) | ||
384 | BLOCK@[22; 25) | ||
385 | L_CURLY@[22; 23) | ||
386 | WHITESPACE@[23; 24) | ||
387 | R_CURLY@[24; 25) | ||
388 | |||
389 | "# | ||
390 | .trim() | ||
391 | ); | ||
392 | } | ||
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index dce6fcc67..89e96a33a 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -32,7 +32,9 @@ pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result<String> { | |||
32 | 32 | ||
33 | pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> Result<String> { | 33 | pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> Result<String> { |
34 | let id = params.text_document.try_conv_with(&world)?; | 34 | let id = params.text_document.try_conv_with(&world)?; |
35 | let res = world.analysis().syntax_tree(id); | 35 | let line_index = world.analysis().file_line_index(id); |
36 | let text_range = params.range.map(|p| p.conv_with(&line_index)); | ||
37 | let res = world.analysis().syntax_tree(id, text_range); | ||
36 | Ok(res) | 38 | Ok(res) |
37 | } | 39 | } |
38 | 40 | ||
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index e224ede80..5c589f969 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs | |||
@@ -39,6 +39,7 @@ impl Request for SyntaxTree { | |||
39 | #[serde(rename_all = "camelCase")] | 39 | #[serde(rename_all = "camelCase")] |
40 | pub struct SyntaxTreeParams { | 40 | pub struct SyntaxTreeParams { |
41 | pub text_document: TextDocumentIdentifier, | 41 | pub text_document: TextDocumentIdentifier, |
42 | pub range: Option<Range>, | ||
42 | } | 43 | } |
43 | 44 | ||
44 | pub enum ExtendSelection {} | 45 | pub enum ExtendSelection {} |
diff --git a/editors/code/package.json b/editors/code/package.json index d4ce2ae2c..fda411810 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -75,7 +75,7 @@ | |||
75 | "commands": [ | 75 | "commands": [ |
76 | { | 76 | { |
77 | "command": "rust-analyzer.syntaxTree", | 77 | "command": "rust-analyzer.syntaxTree", |
78 | "title": "Show syntax tree for current file", | 78 | "title": "Show Syntax Tree", |
79 | "category": "Rust Analyzer" | 79 | "category": "Rust Analyzer" |
80 | }, | 80 | }, |
81 | { | 81 | { |
diff --git a/editors/code/src/commands/syntaxTree.ts b/editors/code/src/commands/syntaxTree.ts index c0baf08c5..2f50fe14b 100644 --- a/editors/code/src/commands/syntaxTree.ts +++ b/editors/code/src/commands/syntaxTree.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import { TextDocumentIdentifier } from 'vscode-languageclient'; | 2 | import { Range, TextDocumentIdentifier } from 'vscode-languageclient'; |
3 | 3 | ||
4 | import { Server } from '../server'; | 4 | import { Server } from '../server'; |
5 | 5 | ||
6 | export const syntaxTreeUri = vscode.Uri.parse('rust-analyzer://syntaxtree'); | 6 | export const syntaxTreeUri = vscode.Uri.parse('rust-analyzer://syntaxtree'); |
7 | 7 | ||
8 | export class TextDocumentContentProvider | 8 | export class SyntaxTreeContentProvider |
9 | implements vscode.TextDocumentContentProvider { | 9 | implements vscode.TextDocumentContentProvider { |
10 | public eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | 10 | public eventEmitter = new vscode.EventEmitter<vscode.Uri>(); |
11 | public syntaxTree: string = 'Not available'; | 11 | public syntaxTree: string = 'Not available'; |
@@ -17,8 +17,21 @@ export class TextDocumentContentProvider | |||
17 | if (editor == null) { | 17 | if (editor == null) { |
18 | return ''; | 18 | return ''; |
19 | } | 19 | } |
20 | |||
21 | let range: Range | undefined; | ||
22 | |||
23 | // When the range based query is enabled we take the range of the selection | ||
24 | if (uri.query === 'range=true') { | ||
25 | range = editor.selection.isEmpty | ||
26 | ? undefined | ||
27 | : Server.client.code2ProtocolConverter.asRange( | ||
28 | editor.selection | ||
29 | ); | ||
30 | } | ||
31 | |||
20 | const request: SyntaxTreeParams = { | 32 | const request: SyntaxTreeParams = { |
21 | textDocument: { uri: editor.document.uri.toString() } | 33 | textDocument: { uri: editor.document.uri.toString() }, |
34 | range | ||
22 | }; | 35 | }; |
23 | return Server.client.sendRequest<SyntaxTreeResult>( | 36 | return Server.client.sendRequest<SyntaxTreeResult>( |
24 | 'rust-analyzer/syntaxTree', | 37 | 'rust-analyzer/syntaxTree', |
@@ -33,6 +46,7 @@ export class TextDocumentContentProvider | |||
33 | 46 | ||
34 | interface SyntaxTreeParams { | 47 | interface SyntaxTreeParams { |
35 | textDocument: TextDocumentIdentifier; | 48 | textDocument: TextDocumentIdentifier; |
49 | range?: Range; | ||
36 | } | 50 | } |
37 | 51 | ||
38 | type SyntaxTreeResult = string; | 52 | type SyntaxTreeResult = string; |
@@ -40,11 +54,23 @@ type SyntaxTreeResult = string; | |||
40 | // Opens the virtual file that will show the syntax tree | 54 | // Opens the virtual file that will show the syntax tree |
41 | // | 55 | // |
42 | // The contents of the file come from the `TextDocumentContentProvider` | 56 | // The contents of the file come from the `TextDocumentContentProvider` |
43 | export async function handle() { | 57 | export function createHandle(provider: SyntaxTreeContentProvider) { |
44 | const document = await vscode.workspace.openTextDocument(syntaxTreeUri); | 58 | return async () => { |
45 | return vscode.window.showTextDocument( | 59 | const editor = vscode.window.activeTextEditor; |
46 | document, | 60 | const rangeEnabled = !!(editor && !editor.selection.isEmpty); |
47 | vscode.ViewColumn.Two, | 61 | |
48 | true | 62 | const uri = rangeEnabled |
49 | ); | 63 | ? vscode.Uri.parse(`${syntaxTreeUri.toString()}?range=true`) |
64 | : syntaxTreeUri; | ||
65 | |||
66 | const document = await vscode.workspace.openTextDocument(uri); | ||
67 | |||
68 | provider.eventEmitter.fire(uri); | ||
69 | |||
70 | return vscode.window.showTextDocument( | ||
71 | document, | ||
72 | vscode.ViewColumn.Two, | ||
73 | true | ||
74 | ); | ||
75 | }; | ||
50 | } | 76 | } |
diff --git a/editors/code/src/events/change_active_text_editor.ts b/editors/code/src/events/change_active_text_editor.ts index af295b2ec..64be56225 100644 --- a/editors/code/src/events/change_active_text_editor.ts +++ b/editors/code/src/events/change_active_text_editor.ts | |||
@@ -1,23 +1,32 @@ | |||
1 | import { TextEditor } from 'vscode'; | 1 | import { TextEditor } from 'vscode'; |
2 | import { TextDocumentIdentifier } from 'vscode-languageclient'; | 2 | import { TextDocumentIdentifier } from 'vscode-languageclient'; |
3 | 3 | ||
4 | import { | ||
5 | SyntaxTreeContentProvider, | ||
6 | syntaxTreeUri | ||
7 | } from '../commands/syntaxTree'; | ||
4 | import { Decoration } from '../highlighting'; | 8 | import { Decoration } from '../highlighting'; |
5 | import { Server } from '../server'; | 9 | import { Server } from '../server'; |
6 | 10 | ||
7 | export async function handle(editor: TextEditor | undefined) { | 11 | export function makeHandler(syntaxTreeProvider: SyntaxTreeContentProvider) { |
8 | if ( | 12 | return async function handle(editor: TextEditor | undefined) { |
9 | !Server.config.highlightingOn || | 13 | if (!editor || editor.document.languageId !== 'rust') { |
10 | !editor || | 14 | return; |
11 | editor.document.languageId !== 'rust' | 15 | } |
12 | ) { | 16 | |
13 | return; | 17 | syntaxTreeProvider.eventEmitter.fire(syntaxTreeUri); |
14 | } | 18 | |
15 | const params: TextDocumentIdentifier = { | 19 | if (!Server.config.highlightingOn) { |
16 | uri: editor.document.uri.toString() | 20 | return; |
21 | } | ||
22 | |||
23 | const params: TextDocumentIdentifier = { | ||
24 | uri: editor.document.uri.toString() | ||
25 | }; | ||
26 | const decorations = await Server.client.sendRequest<Decoration[]>( | ||
27 | 'rust-analyzer/decorationsRequest', | ||
28 | params | ||
29 | ); | ||
30 | Server.highlighter.setHighlights(editor, decorations); | ||
17 | }; | 31 | }; |
18 | const decorations = await Server.client.sendRequest<Decoration[]>( | ||
19 | 'rust-analyzer/decorationsRequest', | ||
20 | params | ||
21 | ); | ||
22 | Server.highlighter.setHighlights(editor, decorations); | ||
23 | } | 32 | } |
diff --git a/editors/code/src/events/change_text_document.ts b/editors/code/src/events/change_text_document.ts index 6be057245..89488bc61 100644 --- a/editors/code/src/events/change_text_document.ts +++ b/editors/code/src/events/change_text_document.ts | |||
@@ -1,20 +1,18 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | 2 | ||
3 | import { | 3 | import { |
4 | syntaxTreeUri, | 4 | SyntaxTreeContentProvider, |
5 | TextDocumentContentProvider | 5 | syntaxTreeUri |
6 | } from '../commands/syntaxTree'; | 6 | } from '../commands/syntaxTree'; |
7 | 7 | ||
8 | export function createHandler( | 8 | export function createHandler(syntaxTreeProvider: SyntaxTreeContentProvider) { |
9 | textDocumentContentProvider: TextDocumentContentProvider | ||
10 | ) { | ||
11 | return (event: vscode.TextDocumentChangeEvent) => { | 9 | return (event: vscode.TextDocumentChangeEvent) => { |
12 | const doc = event.document; | 10 | const doc = event.document; |
13 | if (doc.languageId !== 'rust') { | 11 | if (doc.languageId !== 'rust') { |
14 | return; | 12 | return; |
15 | } | 13 | } |
16 | afterLs(() => { | 14 | afterLs(() => { |
17 | textDocumentContentProvider.eventEmitter.fire(syntaxTreeUri); | 15 | syntaxTreeProvider.eventEmitter.fire(syntaxTreeUri); |
18 | }); | 16 | }); |
19 | }; | 17 | }; |
20 | } | 18 | } |
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts index 8b332eeb2..941beba18 100644 --- a/editors/code/src/extension.ts +++ b/editors/code/src/extension.ts | |||
@@ -2,7 +2,7 @@ import * as vscode from 'vscode'; | |||
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | 3 | ||
4 | import * as commands from './commands'; | 4 | import * as commands from './commands'; |
5 | import { TextDocumentContentProvider } from './commands/syntaxTree'; | 5 | import { SyntaxTreeContentProvider } from './commands/syntaxTree'; |
6 | import * as events from './events'; | 6 | import * as events from './events'; |
7 | import * as notifications from './notifications'; | 7 | import * as notifications from './notifications'; |
8 | import { Server } from './server'; | 8 | import { Server } from './server'; |
@@ -52,7 +52,6 @@ export function activate(context: vscode.ExtensionContext) { | |||
52 | registerCommand('rust-analyzer.collectGarbage', () => | 52 | registerCommand('rust-analyzer.collectGarbage', () => |
53 | Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null) | 53 | Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null) |
54 | ); | 54 | ); |
55 | registerCommand('rust-analyzer.syntaxTree', commands.syntaxTree.handle); | ||
56 | registerCommand( | 55 | registerCommand( |
57 | 'rust-analyzer.extendSelection', | 56 | 'rust-analyzer.extendSelection', |
58 | commands.extendSelection.handle | 57 | commands.extendSelection.handle |
@@ -95,22 +94,27 @@ export function activate(context: vscode.ExtensionContext) { | |||
95 | notifications.publishDecorations.handle | 94 | notifications.publishDecorations.handle |
96 | ] | 95 | ] |
97 | ]; | 96 | ]; |
97 | const syntaxTreeContentProvider = new SyntaxTreeContentProvider(); | ||
98 | 98 | ||
99 | // The events below are plain old javascript events, triggered and handled by vscode | 99 | // The events below are plain old javascript events, triggered and handled by vscode |
100 | vscode.window.onDidChangeActiveTextEditor( | 100 | vscode.window.onDidChangeActiveTextEditor( |
101 | events.changeActiveTextEditor.handle | 101 | events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider) |
102 | ); | 102 | ); |
103 | 103 | ||
104 | const textDocumentContentProvider = new TextDocumentContentProvider(); | ||
105 | disposeOnDeactivation( | 104 | disposeOnDeactivation( |
106 | vscode.workspace.registerTextDocumentContentProvider( | 105 | vscode.workspace.registerTextDocumentContentProvider( |
107 | 'rust-analyzer', | 106 | 'rust-analyzer', |
108 | textDocumentContentProvider | 107 | syntaxTreeContentProvider |
109 | ) | 108 | ) |
110 | ); | 109 | ); |
111 | 110 | ||
111 | registerCommand( | ||
112 | 'rust-analyzer.syntaxTree', | ||
113 | commands.syntaxTree.createHandle(syntaxTreeContentProvider) | ||
114 | ); | ||
115 | |||
112 | vscode.workspace.onDidChangeTextDocument( | 116 | vscode.workspace.onDidChangeTextDocument( |
113 | events.changeTextDocument.createHandler(textDocumentContentProvider), | 117 | events.changeTextDocument.createHandler(syntaxTreeContentProvider), |
114 | null, | 118 | null, |
115 | context.subscriptions | 119 | context.subscriptions |
116 | ); | 120 | ); |