diff options
author | Aleksey Kladov <[email protected]> | 2021-02-12 21:44:28 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-02-16 16:17:32 +0000 |
commit | 0025836f262ee410050ba79b6ea09d75f76449ac (patch) | |
tree | 7559a66efac8a3b988f1e65341d54fca42378721 /crates/rust-analyzer/src/to_proto.rs | |
parent | 95209aa3f8e4b149da6adb374611ece76c2b82ca (diff) |
Make it easy to add additional context for offset conversion
Diffstat (limited to 'crates/rust-analyzer/src/to_proto.rs')
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 78 |
1 files changed, 35 insertions, 43 deletions
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index ec5e8aa73..43e29ef04 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -7,22 +7,23 @@ use std::{ | |||
7 | use ide::{ | 7 | use ide::{ |
8 | Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, | 8 | Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, |
9 | Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, | 9 | Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, |
10 | HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, | 10 | HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, Markup, NavigationTarget, |
11 | NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity, SourceChange, TextEdit, | 11 | ReferenceAccess, RenameError, Runnable, Severity, SourceChange, TextEdit, TextRange, TextSize, |
12 | TextRange, TextSize, | ||
13 | }; | 12 | }; |
14 | use ide_db::SymbolKind; | 13 | use ide_db::SymbolKind; |
15 | use itertools::Itertools; | 14 | use itertools::Itertools; |
16 | use serde_json::to_value; | 15 | use serde_json::to_value; |
17 | 16 | ||
18 | use crate::{ | 17 | use crate::{ |
19 | cargo_target_spec::CargoTargetSpec, global_state::GlobalStateSnapshot, | 18 | cargo_target_spec::CargoTargetSpec, |
20 | line_endings::LineEndings, lsp_ext, semantic_tokens, Result, | 19 | global_state::GlobalStateSnapshot, |
20 | line_endings::{LineEndings, LineIndex}, | ||
21 | lsp_ext, semantic_tokens, Result, | ||
21 | }; | 22 | }; |
22 | 23 | ||
23 | pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { | 24 | pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { |
24 | let line_col = line_index.line_col(offset); | 25 | let line_col = line_index.index.line_col(offset); |
25 | let line_col = line_index.to_utf16(line_col); | 26 | let line_col = line_index.index.to_utf16(line_col); |
26 | lsp_types::Position::new(line_col.line, line_col.col) | 27 | lsp_types::Position::new(line_col.line, line_col.col) |
27 | } | 28 | } |
28 | 29 | ||
@@ -123,13 +124,9 @@ pub(crate) fn completion_item_kind( | |||
123 | } | 124 | } |
124 | } | 125 | } |
125 | 126 | ||
126 | pub(crate) fn text_edit( | 127 | pub(crate) fn text_edit(line_index: &LineIndex, indel: Indel) -> lsp_types::TextEdit { |
127 | line_index: &LineIndex, | ||
128 | line_endings: LineEndings, | ||
129 | indel: Indel, | ||
130 | ) -> lsp_types::TextEdit { | ||
131 | let range = range(line_index, indel.delete); | 128 | let range = range(line_index, indel.delete); |
132 | let new_text = match line_endings { | 129 | let new_text = match line_index.endings { |
133 | LineEndings::Unix => indel.insert, | 130 | LineEndings::Unix => indel.insert, |
134 | LineEndings::Dos => indel.insert.replace('\n', "\r\n"), | 131 | LineEndings::Dos => indel.insert.replace('\n', "\r\n"), |
135 | }; | 132 | }; |
@@ -138,11 +135,10 @@ pub(crate) fn text_edit( | |||
138 | 135 | ||
139 | pub(crate) fn snippet_text_edit( | 136 | pub(crate) fn snippet_text_edit( |
140 | line_index: &LineIndex, | 137 | line_index: &LineIndex, |
141 | line_endings: LineEndings, | ||
142 | is_snippet: bool, | 138 | is_snippet: bool, |
143 | indel: Indel, | 139 | indel: Indel, |
144 | ) -> lsp_ext::SnippetTextEdit { | 140 | ) -> lsp_ext::SnippetTextEdit { |
145 | let text_edit = text_edit(line_index, line_endings, indel); | 141 | let text_edit = text_edit(line_index, indel); |
146 | let insert_text_format = | 142 | let insert_text_format = |
147 | if is_snippet { Some(lsp_types::InsertTextFormat::Snippet) } else { None }; | 143 | if is_snippet { Some(lsp_types::InsertTextFormat::Snippet) } else { None }; |
148 | lsp_ext::SnippetTextEdit { | 144 | lsp_ext::SnippetTextEdit { |
@@ -154,27 +150,24 @@ pub(crate) fn snippet_text_edit( | |||
154 | 150 | ||
155 | pub(crate) fn text_edit_vec( | 151 | pub(crate) fn text_edit_vec( |
156 | line_index: &LineIndex, | 152 | line_index: &LineIndex, |
157 | line_endings: LineEndings, | ||
158 | text_edit: TextEdit, | 153 | text_edit: TextEdit, |
159 | ) -> Vec<lsp_types::TextEdit> { | 154 | ) -> Vec<lsp_types::TextEdit> { |
160 | text_edit.into_iter().map(|indel| self::text_edit(line_index, line_endings, indel)).collect() | 155 | text_edit.into_iter().map(|indel| self::text_edit(line_index, indel)).collect() |
161 | } | 156 | } |
162 | 157 | ||
163 | pub(crate) fn snippet_text_edit_vec( | 158 | pub(crate) fn snippet_text_edit_vec( |
164 | line_index: &LineIndex, | 159 | line_index: &LineIndex, |
165 | line_endings: LineEndings, | ||
166 | is_snippet: bool, | 160 | is_snippet: bool, |
167 | text_edit: TextEdit, | 161 | text_edit: TextEdit, |
168 | ) -> Vec<lsp_ext::SnippetTextEdit> { | 162 | ) -> Vec<lsp_ext::SnippetTextEdit> { |
169 | text_edit | 163 | text_edit |
170 | .into_iter() | 164 | .into_iter() |
171 | .map(|indel| self::snippet_text_edit(line_index, line_endings, is_snippet, indel)) | 165 | .map(|indel| self::snippet_text_edit(line_index, is_snippet, indel)) |
172 | .collect() | 166 | .collect() |
173 | } | 167 | } |
174 | 168 | ||
175 | pub(crate) fn completion_item( | 169 | pub(crate) fn completion_item( |
176 | line_index: &LineIndex, | 170 | line_index: &LineIndex, |
177 | line_endings: LineEndings, | ||
178 | completion_item: CompletionItem, | 171 | completion_item: CompletionItem, |
179 | ) -> Vec<lsp_types::CompletionItem> { | 172 | ) -> Vec<lsp_types::CompletionItem> { |
180 | fn set_score(res: &mut lsp_types::CompletionItem, label: &str) { | 173 | fn set_score(res: &mut lsp_types::CompletionItem, label: &str) { |
@@ -191,19 +184,19 @@ pub(crate) fn completion_item( | |||
191 | for indel in completion_item.text_edit().iter() { | 184 | for indel in completion_item.text_edit().iter() { |
192 | if indel.delete.contains_range(source_range) { | 185 | if indel.delete.contains_range(source_range) { |
193 | text_edit = Some(if indel.delete == source_range { | 186 | text_edit = Some(if indel.delete == source_range { |
194 | self::text_edit(line_index, line_endings, indel.clone()) | 187 | self::text_edit(line_index, indel.clone()) |
195 | } else { | 188 | } else { |
196 | assert!(source_range.end() == indel.delete.end()); | 189 | assert!(source_range.end() == indel.delete.end()); |
197 | let range1 = TextRange::new(indel.delete.start(), source_range.start()); | 190 | let range1 = TextRange::new(indel.delete.start(), source_range.start()); |
198 | let range2 = source_range; | 191 | let range2 = source_range; |
199 | let indel1 = Indel::replace(range1, String::new()); | 192 | let indel1 = Indel::replace(range1, String::new()); |
200 | let indel2 = Indel::replace(range2, indel.insert.clone()); | 193 | let indel2 = Indel::replace(range2, indel.insert.clone()); |
201 | additional_text_edits.push(self::text_edit(line_index, line_endings, indel1)); | 194 | additional_text_edits.push(self::text_edit(line_index, indel1)); |
202 | self::text_edit(line_index, line_endings, indel2) | 195 | self::text_edit(line_index, indel2) |
203 | }) | 196 | }) |
204 | } else { | 197 | } else { |
205 | assert!(source_range.intersect(indel.delete).is_none()); | 198 | assert!(source_range.intersect(indel.delete).is_none()); |
206 | let text_edit = self::text_edit(line_index, line_endings, indel.clone()); | 199 | let text_edit = self::text_edit(line_index, indel.clone()); |
207 | additional_text_edits.push(text_edit); | 200 | additional_text_edits.push(text_edit); |
208 | } | 201 | } |
209 | } | 202 | } |
@@ -359,7 +352,7 @@ pub(crate) fn semantic_tokens( | |||
359 | let token_index = semantic_tokens::type_index(type_); | 352 | let token_index = semantic_tokens::type_index(type_); |
360 | let modifier_bitset = mods.0; | 353 | let modifier_bitset = mods.0; |
361 | 354 | ||
362 | for mut text_range in line_index.lines(highlight_range.range) { | 355 | for mut text_range in line_index.index.lines(highlight_range.range) { |
363 | if text[text_range].ends_with('\n') { | 356 | if text[text_range].ends_with('\n') { |
364 | text_range = | 357 | text_range = |
365 | TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n')); | 358 | TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n')); |
@@ -566,7 +559,7 @@ pub(crate) fn location( | |||
566 | frange: FileRange, | 559 | frange: FileRange, |
567 | ) -> Result<lsp_types::Location> { | 560 | ) -> Result<lsp_types::Location> { |
568 | let url = url(snap, frange.file_id); | 561 | let url = url(snap, frange.file_id); |
569 | let line_index = snap.analysis.file_line_index(frange.file_id)?; | 562 | let line_index = snap.file_line_index(frange.file_id)?; |
570 | let range = range(&line_index, frange.range); | 563 | let range = range(&line_index, frange.range); |
571 | let loc = lsp_types::Location::new(url, range); | 564 | let loc = lsp_types::Location::new(url, range); |
572 | Ok(loc) | 565 | Ok(loc) |
@@ -578,7 +571,7 @@ pub(crate) fn location_from_nav( | |||
578 | nav: NavigationTarget, | 571 | nav: NavigationTarget, |
579 | ) -> Result<lsp_types::Location> { | 572 | ) -> Result<lsp_types::Location> { |
580 | let url = url(snap, nav.file_id); | 573 | let url = url(snap, nav.file_id); |
581 | let line_index = snap.analysis.file_line_index(nav.file_id)?; | 574 | let line_index = snap.file_line_index(nav.file_id)?; |
582 | let range = range(&line_index, nav.full_range); | 575 | let range = range(&line_index, nav.full_range); |
583 | let loc = lsp_types::Location::new(url, range); | 576 | let loc = lsp_types::Location::new(url, range); |
584 | Ok(loc) | 577 | Ok(loc) |
@@ -591,7 +584,7 @@ pub(crate) fn location_link( | |||
591 | ) -> Result<lsp_types::LocationLink> { | 584 | ) -> Result<lsp_types::LocationLink> { |
592 | let origin_selection_range = match src { | 585 | let origin_selection_range = match src { |
593 | Some(src) => { | 586 | Some(src) => { |
594 | let line_index = snap.analysis.file_line_index(src.file_id)?; | 587 | let line_index = snap.file_line_index(src.file_id)?; |
595 | let range = range(&line_index, src.range); | 588 | let range = range(&line_index, src.range); |
596 | Some(range) | 589 | Some(range) |
597 | } | 590 | } |
@@ -611,7 +604,7 @@ fn location_info( | |||
611 | snap: &GlobalStateSnapshot, | 604 | snap: &GlobalStateSnapshot, |
612 | target: NavigationTarget, | 605 | target: NavigationTarget, |
613 | ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { | 606 | ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { |
614 | let line_index = snap.analysis.file_line_index(target.file_id)?; | 607 | let line_index = snap.file_line_index(target.file_id)?; |
615 | 608 | ||
616 | let target_uri = url(snap, target.file_id); | 609 | let target_uri = url(snap, target.file_id); |
617 | let target_range = range(&line_index, target.full_range); | 610 | let target_range = range(&line_index, target.full_range); |
@@ -649,12 +642,8 @@ pub(crate) fn snippet_text_document_edit( | |||
649 | edit: TextEdit, | 642 | edit: TextEdit, |
650 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { | 643 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { |
651 | let text_document = optional_versioned_text_document_identifier(snap, file_id); | 644 | let text_document = optional_versioned_text_document_identifier(snap, file_id); |
652 | let line_index = snap.analysis.file_line_index(file_id)?; | 645 | let line_index = snap.file_line_index(file_id)?; |
653 | let line_endings = snap.file_line_endings(file_id); | 646 | let edits = edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect(); |
654 | let edits = edit | ||
655 | .into_iter() | ||
656 | .map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it)) | ||
657 | .collect(); | ||
658 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) | 647 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) |
659 | } | 648 | } |
660 | 649 | ||
@@ -675,9 +664,8 @@ pub(crate) fn snippet_text_document_ops( | |||
675 | if !initial_contents.is_empty() { | 664 | if !initial_contents.is_empty() { |
676 | let text_document = | 665 | let text_document = |
677 | lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; | 666 | lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; |
678 | let range = range(&LineIndex::new(""), TextRange::empty(TextSize::from(0))); | ||
679 | let text_edit = lsp_ext::SnippetTextEdit { | 667 | let text_edit = lsp_ext::SnippetTextEdit { |
680 | range, | 668 | range: lsp_types::Range::default(), |
681 | new_text: initial_contents, | 669 | new_text: initial_contents, |
682 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), | 670 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), |
683 | }; | 671 | }; |
@@ -868,7 +856,7 @@ pub(crate) fn code_lens( | |||
868 | ) -> Result<lsp_types::CodeLens> { | 856 | ) -> Result<lsp_types::CodeLens> { |
869 | match annotation.kind { | 857 | match annotation.kind { |
870 | AnnotationKind::Runnable { debug, runnable: run } => { | 858 | AnnotationKind::Runnable { debug, runnable: run } => { |
871 | let line_index = snap.analysis.file_line_index(run.nav.file_id)?; | 859 | let line_index = snap.file_line_index(run.nav.file_id)?; |
872 | let annotation_range = range(&line_index, annotation.range); | 860 | let annotation_range = range(&line_index, annotation.range); |
873 | 861 | ||
874 | let action = run.action(); | 862 | let action = run.action(); |
@@ -884,7 +872,7 @@ pub(crate) fn code_lens( | |||
884 | Ok(lsp_types::CodeLens { range: annotation_range, command: Some(command), data: None }) | 872 | Ok(lsp_types::CodeLens { range: annotation_range, command: Some(command), data: None }) |
885 | } | 873 | } |
886 | AnnotationKind::HasImpls { position: file_position, data } => { | 874 | AnnotationKind::HasImpls { position: file_position, data } => { |
887 | let line_index = snap.analysis.file_line_index(file_position.file_id)?; | 875 | let line_index = snap.file_line_index(file_position.file_id)?; |
888 | let annotation_range = range(&line_index, annotation.range); | 876 | let annotation_range = range(&line_index, annotation.range); |
889 | let url = url(snap, file_position.file_id); | 877 | let url = url(snap, file_position.file_id); |
890 | 878 | ||
@@ -927,7 +915,7 @@ pub(crate) fn code_lens( | |||
927 | }) | 915 | }) |
928 | } | 916 | } |
929 | AnnotationKind::HasReferences { position: file_position, data } => { | 917 | AnnotationKind::HasReferences { position: file_position, data } => { |
930 | let line_index = snap.analysis.file_line_index(file_position.file_id)?; | 918 | let line_index = snap.file_line_index(file_position.file_id)?; |
931 | let annotation_range = range(&line_index, annotation.range); | 919 | let annotation_range = range(&line_index, annotation.range); |
932 | let url = url(snap, file_position.file_id); | 920 | let url = url(snap, file_position.file_id); |
933 | 921 | ||
@@ -1061,6 +1049,8 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { | |||
1061 | 1049 | ||
1062 | #[cfg(test)] | 1050 | #[cfg(test)] |
1063 | mod tests { | 1051 | mod tests { |
1052 | use std::sync::Arc; | ||
1053 | |||
1064 | use hir::PrefixKind; | 1054 | use hir::PrefixKind; |
1065 | use ide::Analysis; | 1055 | use ide::Analysis; |
1066 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; | 1056 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
@@ -1078,7 +1068,8 @@ mod tests { | |||
1078 | }"#; | 1068 | }"#; |
1079 | 1069 | ||
1080 | let (offset, text) = test_utils::extract_offset(fixture); | 1070 | let (offset, text) = test_utils::extract_offset(fixture); |
1081 | let line_index = LineIndex::new(&text); | 1071 | let line_index = |
1072 | LineIndex { index: Arc::new(ide::LineIndex::new(&text)), endings: LineEndings::Unix }; | ||
1082 | let (analysis, file_id) = Analysis::from_single_file(text); | 1073 | let (analysis, file_id) = Analysis::from_single_file(text); |
1083 | let completions: Vec<(String, Option<String>)> = analysis | 1074 | let completions: Vec<(String, Option<String>)> = analysis |
1084 | .completions( | 1075 | .completions( |
@@ -1096,7 +1087,7 @@ mod tests { | |||
1096 | .unwrap() | 1087 | .unwrap() |
1097 | .into_iter() | 1088 | .into_iter() |
1098 | .filter(|c| c.label().ends_with("arg")) | 1089 | .filter(|c| c.label().ends_with("arg")) |
1099 | .map(|c| completion_item(&line_index, LineEndings::Unix, c)) | 1090 | .map(|c| completion_item(&line_index, c)) |
1100 | .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text))) | 1091 | .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text))) |
1101 | .collect(); | 1092 | .collect(); |
1102 | expect_test::expect![[r#" | 1093 | expect_test::expect![[r#" |
@@ -1134,7 +1125,8 @@ fn main() { | |||
1134 | let folds = analysis.folding_ranges(file_id).unwrap(); | 1125 | let folds = analysis.folding_ranges(file_id).unwrap(); |
1135 | assert_eq!(folds.len(), 4); | 1126 | assert_eq!(folds.len(), 4); |
1136 | 1127 | ||
1137 | let line_index = LineIndex::new(&text); | 1128 | let line_index = |
1129 | LineIndex { index: Arc::new(ide::LineIndex::new(&text)), endings: LineEndings::Unix }; | ||
1138 | let converted: Vec<lsp_types::FoldingRange> = | 1130 | let converted: Vec<lsp_types::FoldingRange> = |
1139 | folds.into_iter().map(|it| folding_range(&text, &line_index, true, it)).collect(); | 1131 | folds.into_iter().map(|it| folding_range(&text, &line_index, true, it)).collect(); |
1140 | 1132 | ||