aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_lsp_server/src')
-rw-r--r--crates/ra_lsp_server/src/conv.rs106
-rw-r--r--crates/ra_lsp_server/src/lib.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs24
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs22
-rw-r--r--crates/ra_lsp_server/src/world.rs9
5 files changed, 133 insertions, 30 deletions
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 1318a1738..ee503633d 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -227,22 +227,57 @@ impl ConvWith<(&LineIndex, LineEndings)> for &AtomTextEdit {
227 } 227 }
228} 228}
229 229
230impl ConvWith<&LineIndex> for Fold { 230pub(crate) struct FoldConvCtx<'a> {
231 pub(crate) text: &'a str,
232 pub(crate) line_index: &'a LineIndex,
233 pub(crate) line_folding_only: bool,
234}
235
236impl ConvWith<&FoldConvCtx<'_>> for Fold {
231 type Output = lsp_types::FoldingRange; 237 type Output = lsp_types::FoldingRange;
232 238
233 fn conv_with(self, line_index: &LineIndex) -> lsp_types::FoldingRange { 239 fn conv_with(self, ctx: &FoldConvCtx) -> lsp_types::FoldingRange {
234 let range = self.range.conv_with(&line_index); 240 let kind = match self.kind {
235 lsp_types::FoldingRange { 241 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
236 start_line: range.start.line, 242 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
237 start_character: Some(range.start.character), 243 FoldKind::Mods => None,
238 end_line: range.end.line, 244 FoldKind::Block => None,
239 end_character: Some(range.end.character), 245 };
240 kind: match self.kind { 246
241 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), 247 let range = self.range.conv_with(&ctx.line_index);
242 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), 248
243 FoldKind::Mods => None, 249 if ctx.line_folding_only {
244 FoldKind::Block => None, 250 // Clients with line_folding_only == true (such as VSCode) will fold the whole end line
245 }, 251 // even if it contains text not in the folding range. To prevent that we exclude
252 // range.end.line from the folding region if there is more text after range.end
253 // on the same line.
254 let has_more_text_on_end_line = ctx.text
255 [TextRange::from_to(self.range.end(), TextUnit::of_str(ctx.text))]
256 .chars()
257 .take_while(|it| *it != '\n')
258 .any(|it| !it.is_whitespace());
259
260 let end_line = if has_more_text_on_end_line {
261 range.end.line.saturating_sub(1)
262 } else {
263 range.end.line
264 };
265
266 lsp_types::FoldingRange {
267 start_line: range.start.line,
268 start_character: None,
269 end_line,
270 end_character: None,
271 kind,
272 }
273 } else {
274 lsp_types::FoldingRange {
275 start_line: range.start.line,
276 start_character: Some(range.start.character),
277 end_line: range.end.line,
278 end_character: Some(range.end.character),
279 kind,
280 }
246 } 281 }
247 } 282 }
248} 283}
@@ -512,3 +547,46 @@ where
512 self.map(|it| it.try_conv_with(ctx)).collect() 547 self.map(|it| it.try_conv_with(ctx)).collect()
513 } 548 }
514} 549}
550
551#[cfg(test)]
552mod tests {
553 use super::*;
554 use test_utils::extract_ranges;
555
556 #[test]
557 fn conv_fold_line_folding_only_fixup() {
558 let text = r#"<fold>mod a;
559mod b;
560mod c;</fold>
561
562fn main() <fold>{
563 if cond <fold>{
564 a::do_a();
565 }</fold> else <fold>{
566 b::do_b();
567 }</fold>
568}</fold>"#;
569
570 let (ranges, text) = extract_ranges(text, "fold");
571 assert_eq!(ranges.len(), 4);
572 let folds = vec![
573 Fold { range: ranges[0], kind: FoldKind::Mods },
574 Fold { range: ranges[1], kind: FoldKind::Block },
575 Fold { range: ranges[2], kind: FoldKind::Block },
576 Fold { range: ranges[3], kind: FoldKind::Block },
577 ];
578
579 let line_index = LineIndex::new(&text);
580 let ctx = FoldConvCtx { text: &text, line_index: &line_index, line_folding_only: true };
581 let converted: Vec<_> = folds.into_iter().map_conv_with(&ctx).collect();
582
583 let expected_lines = [(0, 2), (4, 10), (5, 6), (7, 9)];
584 assert_eq!(converted.len(), expected_lines.len());
585 for (folding_range, (start_line, end_line)) in converted.iter().zip(expected_lines.iter()) {
586 assert_eq!(folding_range.start_line, *start_line);
587 assert_eq!(folding_range.start_character, None);
588 assert_eq!(folding_range.end_line, *end_line);
589 assert_eq!(folding_range.end_character, None);
590 }
591 }
592}
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs
index 7a71a90fb..0e5dbbbd5 100644
--- a/crates/ra_lsp_server/src/lib.rs
+++ b/crates/ra_lsp_server/src/lib.rs
@@ -7,7 +7,7 @@ mod conv;
7mod main_loop; 7mod main_loop;
8mod markdown; 8mod markdown;
9pub mod req; 9pub mod req;
10pub mod config; 10mod config;
11mod world; 11mod world;
12 12
13pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; 13pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 35c35d32b..0b5d9c44d 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -111,6 +111,21 @@ pub fn main_loop(
111 connection.sender.send(request.into()).unwrap(); 111 connection.sender.send(request.into()).unwrap();
112 } 112 }
113 113
114 let options = {
115 let text_document_caps = client_caps.text_document.as_ref();
116 Options {
117 publish_decorations: config.publish_decorations,
118 supports_location_link: text_document_caps
119 .and_then(|it| it.definition)
120 .and_then(|it| it.link_support)
121 .unwrap_or(false),
122 line_folding_only: text_document_caps
123 .and_then(|it| it.folding_range.as_ref())
124 .and_then(|it| it.line_folding_only)
125 .unwrap_or(false),
126 }
127 };
128
114 let feature_flags = { 129 let feature_flags = {
115 let mut ff = FeatureFlags::default(); 130 let mut ff = FeatureFlags::default();
116 for (flag, value) in config.feature_flags { 131 for (flag, value) in config.feature_flags {
@@ -133,14 +148,7 @@ pub fn main_loop(
133 config.lru_capacity, 148 config.lru_capacity,
134 &globs, 149 &globs,
135 Watch(!config.use_client_watching), 150 Watch(!config.use_client_watching),
136 Options { 151 options,
137 publish_decorations: config.publish_decorations,
138 supports_location_link: client_caps
139 .text_document
140 .and_then(|it| it.definition)
141 .and_then(|it| it.link_support)
142 .unwrap_or(false),
143 },
144 feature_flags, 152 feature_flags,
145 ) 153 )
146 }; 154 };
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 10e271376..307082865 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -18,7 +18,7 @@ use serde_json::to_value;
18 18
19use crate::{ 19use crate::{
20 cargo_target_spec::{runnable_args, CargoTargetSpec}, 20 cargo_target_spec::{runnable_args, CargoTargetSpec},
21 conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith, TryConvWithToVec}, 21 conv::{to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith, TryConvWithToVec},
22 req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind}, 22 req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind},
23 world::WorldSnapshot, 23 world::WorldSnapshot,
24 LspError, Result, 24 LspError, Result,
@@ -383,8 +383,14 @@ pub fn handle_folding_range(
383) -> Result<Option<Vec<FoldingRange>>> { 383) -> Result<Option<Vec<FoldingRange>>> {
384 let file_id = params.text_document.try_conv_with(&world)?; 384 let file_id = params.text_document.try_conv_with(&world)?;
385 let folds = world.analysis().folding_ranges(file_id)?; 385 let folds = world.analysis().folding_ranges(file_id)?;
386 let text = world.analysis().file_text(file_id)?;
386 let line_index = world.analysis().file_line_index(file_id)?; 387 let line_index = world.analysis().file_line_index(file_id)?;
387 let res = Some(folds.into_iter().map_conv_with(&*line_index).collect()); 388 let ctx = FoldConvCtx {
389 text: &text,
390 line_index: &line_index,
391 line_folding_only: world.options.line_folding_only,
392 };
393 let res = Some(folds.into_iter().map_conv_with(&ctx).collect());
388 Ok(res) 394 Ok(res)
389} 395}
390 396
@@ -475,7 +481,6 @@ pub fn handle_references(
475 params: req::ReferenceParams, 481 params: req::ReferenceParams,
476) -> Result<Option<Vec<Location>>> { 482) -> Result<Option<Vec<Location>>> {
477 let position = params.text_document_position.try_conv_with(&world)?; 483 let position = params.text_document_position.try_conv_with(&world)?;
478 let line_index = world.analysis().file_line_index(position.file_id)?;
479 484
480 let refs = match world.analysis().find_all_refs(position)? { 485 let refs = match world.analysis().find_all_refs(position)? {
481 None => return Ok(None), 486 None => return Ok(None),
@@ -484,13 +489,19 @@ pub fn handle_references(
484 489
485 let locations = if params.context.include_declaration { 490 let locations = if params.context.include_declaration {
486 refs.into_iter() 491 refs.into_iter()
487 .filter_map(|r| to_location(r.file_id, r.range, &world, &line_index).ok()) 492 .filter_map(|r| {
493 let line_index = world.analysis().file_line_index(r.file_id).ok()?;
494 to_location(r.file_id, r.range, &world, &line_index).ok()
495 })
488 .collect() 496 .collect()
489 } else { 497 } else {
490 // Only iterate over the references if include_declaration was false 498 // Only iterate over the references if include_declaration was false
491 refs.references() 499 refs.references()
492 .iter() 500 .iter()
493 .filter_map(|r| to_location(r.file_id, r.range, &world, &line_index).ok()) 501 .filter_map(|r| {
502 let line_index = world.analysis().file_line_index(r.file_id).ok()?;
503 to_location(r.file_id, r.range, &world, &line_index).ok()
504 })
494 .collect() 505 .collect()
495 }; 506 };
496 507
@@ -740,6 +751,7 @@ pub fn handle_document_highlight(
740 751
741 Ok(Some( 752 Ok(Some(
742 refs.into_iter() 753 refs.into_iter()
754 .filter(|r| r.file_id == file_id)
743 .map(|r| DocumentHighlight { range: r.range.conv_with(&line_index), kind: None }) 755 .map(|r| DocumentHighlight { range: r.range.conv_with(&line_index), kind: None })
744 .collect(), 756 .collect(),
745 )) 757 ))
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 27da751ab..51824e7a3 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -27,6 +27,7 @@ use crate::{
27pub struct Options { 27pub struct Options {
28 pub publish_decorations: bool, 28 pub publish_decorations: bool,
29 pub supports_location_link: bool, 29 pub supports_location_link: bool,
30 pub line_folding_only: bool,
30} 31}
31 32
32/// `WorldState` is the primary mutable state of the language server 33/// `WorldState` is the primary mutable state of the language server
@@ -98,8 +99,12 @@ impl WorldState {
98 } 99 }
99 100
100 // FIXME: Read default cfgs from config 101 // FIXME: Read default cfgs from config
101 let default_cfg_options = 102 let default_cfg_options = {
102 get_rustc_cfg_options().atom("test".into()).atom("debug_assertion".into()); 103 let mut opts = get_rustc_cfg_options();
104 opts.insert_atom("test".into());
105 opts.insert_atom("debug_assertion".into());
106 opts
107 };
103 108
104 // Create crate graph from all the workspaces 109 // Create crate graph from all the workspaces
105 let mut crate_graph = CrateGraph::default(); 110 let mut crate_graph = CrateGraph::default();