diff options
author | Jeremy A. Kolb <[email protected]> | 2018-09-23 16:13:27 +0100 |
---|---|---|
committer | Jeremy A. Kolb <[email protected]> | 2018-09-23 16:19:36 +0100 |
commit | bd2b2f1b48f86d59c3b746b72a14192f75419a84 (patch) | |
tree | f8a4d9e1cc79dccb4812879642d382b6a4184f6e /crates/ra_lsp_server/src/main_loop/handlers.rs | |
parent | e293a16d6b430befe6eb8be315ad60e7b2b10926 (diff) |
Implement folding ranges
Diffstat (limited to 'crates/ra_lsp_server/src/main_loop/handlers.rs')
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 2d9391859..36cdeda38 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -1,15 +1,18 @@ | |||
1 | use std::collections::HashMap; | 1 | use std::collections::{HashMap, HashSet}; |
2 | 2 | ||
3 | use languageserver_types::{ | 3 | use languageserver_types::{ |
4 | Diagnostic, DiagnosticSeverity, DocumentSymbol, | 4 | Diagnostic, DiagnosticSeverity, DocumentSymbol, |
5 | CodeActionResponse, Command, TextDocumentIdentifier, | 5 | CodeActionResponse, Command, TextDocumentIdentifier, |
6 | SymbolInformation, Position, Location, TextEdit, | 6 | SymbolInformation, Position, Location, TextEdit, |
7 | CompletionItem, InsertTextFormat, CompletionItemKind, | 7 | CompletionItem, InsertTextFormat, CompletionItemKind, |
8 | FoldingRange, FoldingRangeParams, FoldingRangeKind | ||
8 | }; | 9 | }; |
9 | use serde_json::to_value; | 10 | use serde_json::to_value; |
10 | use ra_analysis::{Query, FileId, RunnableKind, JobToken}; | 11 | use ra_analysis::{Query, FileId, RunnableKind, JobToken}; |
11 | use ra_syntax::{ | 12 | use ra_syntax::{ |
13 | algo::{siblings, walk, Direction}, | ||
12 | text_utils::contains_offset_nonstrict, | 14 | text_utils::contains_offset_nonstrict, |
15 | SyntaxKind, SyntaxNodeRef, TextRange | ||
13 | }; | 16 | }; |
14 | 17 | ||
15 | use ::{ | 18 | use ::{ |
@@ -177,6 +180,7 @@ pub fn handle_workspace_symbol( | |||
177 | world, &line_index | 180 | world, &line_index |
178 | )?, | 181 | )?, |
179 | container_name: None, | 182 | container_name: None, |
183 | deprecated: None, | ||
180 | }; | 184 | }; |
181 | res.push(info); | 185 | res.push(info); |
182 | }; | 186 | }; |
@@ -365,6 +369,90 @@ pub fn handle_completion( | |||
365 | Ok(Some(req::CompletionResponse::Array(items))) | 369 | Ok(Some(req::CompletionResponse::Array(items))) |
366 | } | 370 | } |
367 | 371 | ||
372 | pub fn handle_folding_range( | ||
373 | world: ServerWorld, | ||
374 | params: FoldingRangeParams, | ||
375 | _token: JobToken, | ||
376 | ) -> Result<Option<Vec<FoldingRange>>> { | ||
377 | let file_id = params.text_document.try_conv_with(&world)?; | ||
378 | let file = world.analysis().file_syntax(file_id); | ||
379 | let line_index = world.analysis().file_line_index(file_id); | ||
380 | let syntax = file.syntax(); | ||
381 | |||
382 | let mut res = vec![]; | ||
383 | let mut visited = HashSet::new(); | ||
384 | |||
385 | for node in walk::preorder(syntax) { | ||
386 | if visited.contains(&node) { | ||
387 | continue; | ||
388 | } | ||
389 | |||
390 | let range_and_kind = match node.kind() { | ||
391 | SyntaxKind::COMMENT => ( | ||
392 | contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited), | ||
393 | Some(FoldingRangeKind::Comment), | ||
394 | ), | ||
395 | SyntaxKind::USE_ITEM => ( | ||
396 | contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited), | ||
397 | Some(FoldingRangeKind::Imports), | ||
398 | ), | ||
399 | _ => (None, None), | ||
400 | }; | ||
401 | |||
402 | match range_and_kind { | ||
403 | (Some(range), Some(kind)) => { | ||
404 | let range = range.conv_with(&line_index); | ||
405 | res.push(FoldingRange { | ||
406 | start_line: range.start.line, | ||
407 | start_character: Some(range.start.character), | ||
408 | end_line: range.end.line, | ||
409 | end_character: Some(range.start.character), | ||
410 | kind: Some(kind), | ||
411 | }); | ||
412 | } | ||
413 | _ => {} | ||
414 | } | ||
415 | } | ||
416 | |||
417 | if res.is_empty() { | ||
418 | Ok(None) | ||
419 | } else { | ||
420 | Ok(Some(res)) | ||
421 | } | ||
422 | } | ||
423 | |||
424 | fn contiguous_range_for<'a>( | ||
425 | kind: SyntaxKind, | ||
426 | node: SyntaxNodeRef<'a>, | ||
427 | visited: &mut HashSet<SyntaxNodeRef<'a>>, | ||
428 | ) -> Option<TextRange> { | ||
429 | visited.insert(node); | ||
430 | |||
431 | let left = node; | ||
432 | let mut right = node; | ||
433 | for node in siblings(node, Direction::Forward) { | ||
434 | visited.insert(node); | ||
435 | match node.kind() { | ||
436 | SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), | ||
437 | k => { | ||
438 | if k == kind { | ||
439 | right = node | ||
440 | } else { | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | if left != right { | ||
447 | Some(TextRange::from_to( | ||
448 | left.range().start(), | ||
449 | right.range().end(), | ||
450 | )) | ||
451 | } else { | ||
452 | None | ||
453 | } | ||
454 | } | ||
455 | |||
368 | pub fn handle_code_action( | 456 | pub fn handle_code_action( |
369 | world: ServerWorld, | 457 | world: ServerWorld, |
370 | params: req::CodeActionParams, | 458 | params: req::CodeActionParams, |