aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy A. Kolb <[email protected]>2018-09-23 16:13:27 +0100
committerJeremy A. Kolb <[email protected]>2018-09-23 16:19:36 +0100
commitbd2b2f1b48f86d59c3b746b72a14192f75419a84 (patch)
treef8a4d9e1cc79dccb4812879642d382b6a4184f6e
parente293a16d6b430befe6eb8be315ad60e7b2b10926 (diff)
Implement folding ranges
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs90
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs1
2 files changed, 90 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 @@
1use std::collections::HashMap; 1use std::collections::{HashMap, HashSet};
2 2
3use languageserver_types::{ 3use 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};
9use serde_json::to_value; 10use serde_json::to_value;
10use ra_analysis::{Query, FileId, RunnableKind, JobToken}; 11use ra_analysis::{Query, FileId, RunnableKind, JobToken};
11use ra_syntax::{ 12use 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
15use ::{ 18use ::{
@@ -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
372pub 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
424fn 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
368pub fn handle_code_action( 456pub fn handle_code_action(
369 world: ServerWorld, 457 world: ServerWorld,
370 params: req::CodeActionParams, 458 params: req::CodeActionParams,
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs
index 2b2279e97..abc58b70e 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop/mod.rs
@@ -253,6 +253,7 @@ fn on_request(
253 .on::<req::DecorationsRequest>(handlers::handle_decorations)? 253 .on::<req::DecorationsRequest>(handlers::handle_decorations)?
254 .on::<req::Completion>(handlers::handle_completion)? 254 .on::<req::Completion>(handlers::handle_completion)?
255 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 255 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
256 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
256 .finish(); 257 .finish();
257 match req { 258 match req {
258 Ok((id, handle)) => { 259 Ok((id, handle)) => {