aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/gen_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_analysis/src/lib.rs5
-rw-r--r--crates/ra_editor/src/folding_ranges.rs142
-rw-r--r--crates/ra_editor/src/lib.rs2
-rw-r--r--crates/ra_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/caps.rs6
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs44
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs1
8 files changed, 195 insertions, 9 deletions
diff --git a/crates/gen_lsp_server/Cargo.toml b/crates/gen_lsp_server/Cargo.toml
index 4eb508fc0..6580ba6e4 100644
--- a/crates/gen_lsp_server/Cargo.toml
+++ b/crates/gen_lsp_server/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"] 4authors = ["Aleksey Kladov <[email protected]>"]
5 5
6[dependencies] 6[dependencies]
7languageserver-types = "0.50.0" 7languageserver-types = "0.51.0"
8log = "0.4.3" 8log = "0.4.3"
9 9
10failure = "0.1.2" 10failure = "0.1.2"
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 4da55ab26..b4c7db476 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -34,6 +34,7 @@ use imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
34pub use ra_editor::{ 34pub use ra_editor::{
35 StructureNode, LineIndex, FileSymbol, 35 StructureNode, LineIndex, FileSymbol,
36 Runnable, RunnableKind, HighlightedRange, CompletionItem, 36 Runnable, RunnableKind, HighlightedRange, CompletionItem,
37 Fold, FoldKind
37}; 38};
38pub use job::{JobToken, JobHandle}; 39pub use job::{JobToken, JobHandle};
39 40
@@ -224,6 +225,10 @@ impl Analysis {
224 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { 225 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
225 self.imp.diagnostics(file_id) 226 self.imp.diagnostics(file_id)
226 } 227 }
228 pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> {
229 let file = self.imp.file_syntax(file_id);
230 ra_editor::folding_ranges(&file)
231 }
227} 232}
228 233
229#[derive(Debug)] 234#[derive(Debug)]
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs
new file mode 100644
index 000000000..817da28d1
--- /dev/null
+++ b/crates/ra_editor/src/folding_ranges.rs
@@ -0,0 +1,142 @@
1use std::collections::HashSet;
2
3use ra_syntax::{
4 File, TextRange, SyntaxNodeRef,
5 SyntaxKind,
6 algo::{walk, Direction, siblings},
7};
8
9#[derive(Debug, PartialEq, Eq)]
10pub enum FoldKind {
11 Comment,
12 Imports,
13}
14
15#[derive(Debug)]
16pub struct Fold {
17 pub range: TextRange,
18 pub kind: FoldKind,
19}
20
21pub fn folding_ranges(file: &File) -> Vec<Fold> {
22 let syntax = file.syntax();
23
24 let mut res = vec![];
25 let mut visited = HashSet::new();
26
27 for node in walk::preorder(syntax) {
28 if visited.contains(&node) {
29 continue;
30 }
31
32 let range_and_kind = match node.kind() {
33 SyntaxKind::COMMENT => (
34 contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited),
35 Some(FoldKind::Comment),
36 ),
37 SyntaxKind::USE_ITEM => (
38 contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited),
39 Some(FoldKind::Imports),
40 ),
41 _ => (None, None),
42 };
43
44 match range_and_kind {
45 (Some(range), Some(kind)) => {
46 res.push(Fold {
47 range: range,
48 kind: kind
49 });
50 }
51 _ => {}
52 }
53 }
54
55 res
56}
57
58fn contiguous_range_for<'a>(
59 kind: SyntaxKind,
60 node: SyntaxNodeRef<'a>,
61 visited: &mut HashSet<SyntaxNodeRef<'a>>,
62) -> Option<TextRange> {
63 visited.insert(node);
64
65 let left = node;
66 let mut right = node;
67 for node in siblings(node, Direction::Forward) {
68 visited.insert(node);
69 match node.kind() {
70 SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (),
71 k => {
72 if k == kind {
73 right = node
74 } else {
75 break;
76 }
77 }
78 }
79 }
80 if left != right {
81 Some(TextRange::from_to(
82 left.range().start(),
83 right.range().end(),
84 ))
85 } else {
86 None
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_fold_comments() {
96 let text = r#"
97// Hello
98// this is a multiline
99// comment
100//
101
102// But this is not
103
104fn main() {
105 // We should
106 // also
107 // fold
108 // this one.
109}"#;
110
111 let file = File::parse(&text);
112 let folds = folding_ranges(&file);
113 assert_eq!(folds.len(), 2);
114 assert_eq!(folds[0].range.start(), 1.into());
115 assert_eq!(folds[0].range.end(), 46.into());
116 assert_eq!(folds[0].kind, FoldKind::Comment);
117
118 assert_eq!(folds[1].range.start(), 84.into());
119 assert_eq!(folds[1].range.end(), 137.into());
120 assert_eq!(folds[1].kind, FoldKind::Comment);
121 }
122
123 #[test]
124 fn test_fold_imports() {
125 let text = r#"
126use std::str;
127use std::vec;
128use std::io as iop;
129
130fn main() {
131}"#;
132
133 let file = File::parse(&text);
134 let folds = folding_ranges(&file);
135 assert_eq!(folds.len(), 1);
136 assert_eq!(folds[0].range.start(), 1.into());
137 assert_eq!(folds[0].range.end(), 48.into());
138 assert_eq!(folds[0].kind, FoldKind::Imports);
139 }
140
141
142} \ No newline at end of file
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index 78ed34c7c..de929d73a 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -10,6 +10,7 @@ mod extend_selection;
10mod symbols; 10mod symbols;
11mod line_index; 11mod line_index;
12mod edit; 12mod edit;
13mod folding_ranges;
13mod code_actions; 14mod code_actions;
14mod typing; 15mod typing;
15mod completion; 16mod completion;
@@ -36,6 +37,7 @@ pub use self::{
36 }, 37 },
37 typing::{join_lines, on_eq_typed}, 38 typing::{join_lines, on_eq_typed},
38 completion::{scope_completion, CompletionItem}, 39 completion::{scope_completion, CompletionItem},
40 folding_ranges::{Fold, FoldKind, folding_ranges}
39}; 41};
40 42
41#[derive(Debug)] 43#[derive(Debug)]
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index b851f70e1..32463e499 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -15,7 +15,7 @@ crossbeam-channel = "0.2.4"
15flexi_logger = "0.9.1" 15flexi_logger = "0.9.1"
16log = "0.4.3" 16log = "0.4.3"
17url_serde = "0.2.0" 17url_serde = "0.2.0"
18languageserver-types = "0.50.0" 18languageserver-types = "0.51.0"
19walkdir = "2.2.0" 19walkdir = "2.2.0"
20im = "12.0.0" 20im = "12.0.0"
21cargo_metadata = "0.6.0" 21cargo_metadata = "0.6.0"
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 7456aea8a..3c628f29c 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -1,5 +1,7 @@
1use languageserver_types::{ 1use languageserver_types::{
2 ServerCapabilities, 2 ServerCapabilities,
3 CodeActionProviderCapability,
4 FoldingRangeProviderCapability,
3 TextDocumentSyncCapability, 5 TextDocumentSyncCapability,
4 TextDocumentSyncOptions, 6 TextDocumentSyncOptions,
5 TextDocumentSyncKind, 7 TextDocumentSyncKind,
@@ -32,7 +34,7 @@ pub fn server_capabilities() -> ServerCapabilities {
32 document_highlight_provider: None, 34 document_highlight_provider: None,
33 document_symbol_provider: Some(true), 35 document_symbol_provider: Some(true),
34 workspace_symbol_provider: Some(true), 36 workspace_symbol_provider: Some(true),
35 code_action_provider: Some(true), 37 code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
36 code_lens_provider: None, 38 code_lens_provider: None,
37 document_formatting_provider: None, 39 document_formatting_provider: None,
38 document_range_formatting_provider: None, 40 document_range_formatting_provider: None,
@@ -40,10 +42,12 @@ pub fn server_capabilities() -> ServerCapabilities {
40 first_trigger_character: "=".to_string(), 42 first_trigger_character: "=".to_string(),
41 more_trigger_character: None, 43 more_trigger_character: None,
42 }), 44 }),
45 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
43 rename_provider: None, 46 rename_provider: None,
44 color_provider: None, 47 color_provider: None,
45 execute_command_provider: Some(ExecuteCommandOptions { 48 execute_command_provider: Some(ExecuteCommandOptions {
46 commands: vec!["apply_code_action".to_string()], 49 commands: vec!["apply_code_action".to_string()],
47 }), 50 }),
51 workspace: None,
48 } 52 }
49} 53}
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index b2ebc9cdc..51061543c 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -1,15 +1,16 @@
1use std::collections::HashMap; 1use std::collections::{HashMap};
2 2
3use languageserver_types::{ 3use languageserver_types::{
4 Diagnostic, DiagnosticSeverity, DocumentSymbol, 4 Diagnostic, DiagnosticSeverity, DocumentSymbol,
5 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, FoldKind};
11use ra_syntax::{ 12use ra_syntax::{
12 text_utils::contains_offset_nonstrict, 13 text_utils::contains_offset_nonstrict
13}; 14};
14 15
15use ::{ 16use ::{
@@ -177,6 +178,7 @@ pub fn handle_workspace_symbol(
177 world, &line_index 178 world, &line_index
178 )?, 179 )?,
179 container_name: None, 180 container_name: None,
181 deprecated: None,
180 }; 182 };
181 res.push(info); 183 res.push(info);
182 }; 184 };
@@ -365,11 +367,41 @@ pub fn handle_completion(
365 Ok(Some(req::CompletionResponse::Array(items))) 367 Ok(Some(req::CompletionResponse::Array(items)))
366} 368}
367 369
370pub fn handle_folding_range(
371 world: ServerWorld,
372 params: FoldingRangeParams,
373 _token: JobToken,
374) -> Result<Option<Vec<FoldingRange>>> {
375 let file_id = params.text_document.try_conv_with(&world)?;
376 let line_index = world.analysis().file_line_index(file_id);
377
378 let res = Some(world.analysis()
379 .folding_ranges(file_id)
380 .into_iter()
381 .map(|fold| {
382 let kind = match fold.kind {
383 FoldKind::Comment => FoldingRangeKind::Comment,
384 FoldKind::Imports => FoldingRangeKind::Imports
385 };
386 let range = fold.range.conv_with(&line_index);
387 FoldingRange {
388 start_line: range.start.line,
389 start_character: Some(range.start.character),
390 end_line: range.end.line,
391 end_character: Some(range.start.character),
392 kind: Some(kind)
393 }
394 })
395 .collect());
396
397 Ok(res)
398}
399
368pub fn handle_code_action( 400pub fn handle_code_action(
369 world: ServerWorld, 401 world: ServerWorld,
370 params: req::CodeActionParams, 402 params: req::CodeActionParams,
371 _token: JobToken, 403 _token: JobToken,
372) -> Result<Option<Vec<Command>>> { 404) -> Result<Option<CodeActionResponse>> {
373 let file_id = params.text_document.try_conv_with(&world)?; 405 let file_id = params.text_document.try_conv_with(&world)?;
374 let line_index = world.analysis().file_line_index(file_id); 406 let line_index = world.analysis().file_line_index(file_id);
375 let range = params.range.conv_with(&line_index); 407 let range = params.range.conv_with(&line_index);
@@ -392,7 +424,7 @@ pub fn handle_code_action(
392 res.push(cmd); 424 res.push(cmd);
393 } 425 }
394 426
395 Ok(Some(res)) 427 Ok(Some(CodeActionResponse::Commands(res)))
396} 428}
397 429
398pub fn publish_diagnostics( 430pub fn publish_diagnostics(
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)) => {