diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-02-16 16:34:22 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-02-16 16:34:22 +0000 |
commit | c9672a0539a59b626619724092077f57c70e6ffe (patch) | |
tree | 77097454dc598a5e0a0b1d98b8c9645b9e213289 /crates/rust-analyzer/src/to_proto.rs | |
parent | f7b7a09f752caba21f2b21ccb8f74421a599d2c6 (diff) | |
parent | 3f09e3fba62839f26da2f27ce27a2335b1dca7ef (diff) |
Merge #7657
7657: utf8 r=matklad a=matklad
- Prepare for utf-8 offsets
- reduce code duplication in tests
- Make utf8 default, implement utf16 in terms of it
- Make it easy to add additional context for offset conversion
- Implement utf8 offsets
closes #7453
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/rust-analyzer/src/to_proto.rs')
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 90 |
1 files changed, 47 insertions, 43 deletions
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index b0ddb603d..70cb7fbab 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -7,22 +7,29 @@ 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_index::{LineEndings, LineIndex, OffsetEncoding}, | ||
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 | lsp_types::Position::new(line_col.line, line_col.col_utf16) | 26 | match line_index.encoding { |
27 | OffsetEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col), | ||
28 | OffsetEncoding::Utf16 => { | ||
29 | let line_col = line_index.index.to_utf16(line_col); | ||
30 | lsp_types::Position::new(line_col.line, line_col.col) | ||
31 | } | ||
32 | } | ||
26 | } | 33 | } |
27 | 34 | ||
28 | pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range { | 35 | pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range { |
@@ -122,13 +129,9 @@ pub(crate) fn completion_item_kind( | |||
122 | } | 129 | } |
123 | } | 130 | } |
124 | 131 | ||
125 | pub(crate) fn text_edit( | 132 | pub(crate) fn text_edit(line_index: &LineIndex, indel: Indel) -> lsp_types::TextEdit { |
126 | line_index: &LineIndex, | ||
127 | line_endings: LineEndings, | ||
128 | indel: Indel, | ||
129 | ) -> lsp_types::TextEdit { | ||
130 | let range = range(line_index, indel.delete); | 133 | let range = range(line_index, indel.delete); |
131 | let new_text = match line_endings { | 134 | let new_text = match line_index.endings { |
132 | LineEndings::Unix => indel.insert, | 135 | LineEndings::Unix => indel.insert, |
133 | LineEndings::Dos => indel.insert.replace('\n', "\r\n"), | 136 | LineEndings::Dos => indel.insert.replace('\n', "\r\n"), |
134 | }; | 137 | }; |
@@ -137,11 +140,10 @@ pub(crate) fn text_edit( | |||
137 | 140 | ||
138 | pub(crate) fn snippet_text_edit( | 141 | pub(crate) fn snippet_text_edit( |
139 | line_index: &LineIndex, | 142 | line_index: &LineIndex, |
140 | line_endings: LineEndings, | ||
141 | is_snippet: bool, | 143 | is_snippet: bool, |
142 | indel: Indel, | 144 | indel: Indel, |
143 | ) -> lsp_ext::SnippetTextEdit { | 145 | ) -> lsp_ext::SnippetTextEdit { |
144 | let text_edit = text_edit(line_index, line_endings, indel); | 146 | let text_edit = text_edit(line_index, indel); |
145 | let insert_text_format = | 147 | let insert_text_format = |
146 | if is_snippet { Some(lsp_types::InsertTextFormat::Snippet) } else { None }; | 148 | if is_snippet { Some(lsp_types::InsertTextFormat::Snippet) } else { None }; |
147 | lsp_ext::SnippetTextEdit { | 149 | lsp_ext::SnippetTextEdit { |
@@ -153,27 +155,24 @@ pub(crate) fn snippet_text_edit( | |||
153 | 155 | ||
154 | pub(crate) fn text_edit_vec( | 156 | pub(crate) fn text_edit_vec( |
155 | line_index: &LineIndex, | 157 | line_index: &LineIndex, |
156 | line_endings: LineEndings, | ||
157 | text_edit: TextEdit, | 158 | text_edit: TextEdit, |
158 | ) -> Vec<lsp_types::TextEdit> { | 159 | ) -> Vec<lsp_types::TextEdit> { |
159 | text_edit.into_iter().map(|indel| self::text_edit(line_index, line_endings, indel)).collect() | 160 | text_edit.into_iter().map(|indel| self::text_edit(line_index, indel)).collect() |
160 | } | 161 | } |
161 | 162 | ||
162 | pub(crate) fn snippet_text_edit_vec( | 163 | pub(crate) fn snippet_text_edit_vec( |
163 | line_index: &LineIndex, | 164 | line_index: &LineIndex, |
164 | line_endings: LineEndings, | ||
165 | is_snippet: bool, | 165 | is_snippet: bool, |
166 | text_edit: TextEdit, | 166 | text_edit: TextEdit, |
167 | ) -> Vec<lsp_ext::SnippetTextEdit> { | 167 | ) -> Vec<lsp_ext::SnippetTextEdit> { |
168 | text_edit | 168 | text_edit |
169 | .into_iter() | 169 | .into_iter() |
170 | .map(|indel| self::snippet_text_edit(line_index, line_endings, is_snippet, indel)) | 170 | .map(|indel| self::snippet_text_edit(line_index, is_snippet, indel)) |
171 | .collect() | 171 | .collect() |
172 | } | 172 | } |
173 | 173 | ||
174 | pub(crate) fn completion_item( | 174 | pub(crate) fn completion_item( |
175 | line_index: &LineIndex, | 175 | line_index: &LineIndex, |
176 | line_endings: LineEndings, | ||
177 | completion_item: CompletionItem, | 176 | completion_item: CompletionItem, |
178 | ) -> Vec<lsp_types::CompletionItem> { | 177 | ) -> Vec<lsp_types::CompletionItem> { |
179 | fn set_score(res: &mut lsp_types::CompletionItem, label: &str) { | 178 | fn set_score(res: &mut lsp_types::CompletionItem, label: &str) { |
@@ -190,19 +189,19 @@ pub(crate) fn completion_item( | |||
190 | for indel in completion_item.text_edit().iter() { | 189 | for indel in completion_item.text_edit().iter() { |
191 | if indel.delete.contains_range(source_range) { | 190 | if indel.delete.contains_range(source_range) { |
192 | text_edit = Some(if indel.delete == source_range { | 191 | text_edit = Some(if indel.delete == source_range { |
193 | self::text_edit(line_index, line_endings, indel.clone()) | 192 | self::text_edit(line_index, indel.clone()) |
194 | } else { | 193 | } else { |
195 | assert!(source_range.end() == indel.delete.end()); | 194 | assert!(source_range.end() == indel.delete.end()); |
196 | let range1 = TextRange::new(indel.delete.start(), source_range.start()); | 195 | let range1 = TextRange::new(indel.delete.start(), source_range.start()); |
197 | let range2 = source_range; | 196 | let range2 = source_range; |
198 | let indel1 = Indel::replace(range1, String::new()); | 197 | let indel1 = Indel::replace(range1, String::new()); |
199 | let indel2 = Indel::replace(range2, indel.insert.clone()); | 198 | let indel2 = Indel::replace(range2, indel.insert.clone()); |
200 | additional_text_edits.push(self::text_edit(line_index, line_endings, indel1)); | 199 | additional_text_edits.push(self::text_edit(line_index, indel1)); |
201 | self::text_edit(line_index, line_endings, indel2) | 200 | self::text_edit(line_index, indel2) |
202 | }) | 201 | }) |
203 | } else { | 202 | } else { |
204 | assert!(source_range.intersect(indel.delete).is_none()); | 203 | assert!(source_range.intersect(indel.delete).is_none()); |
205 | let text_edit = self::text_edit(line_index, line_endings, indel.clone()); | 204 | let text_edit = self::text_edit(line_index, indel.clone()); |
206 | additional_text_edits.push(text_edit); | 205 | additional_text_edits.push(text_edit); |
207 | } | 206 | } |
208 | } | 207 | } |
@@ -358,7 +357,7 @@ pub(crate) fn semantic_tokens( | |||
358 | let token_index = semantic_tokens::type_index(type_); | 357 | let token_index = semantic_tokens::type_index(type_); |
359 | let modifier_bitset = mods.0; | 358 | let modifier_bitset = mods.0; |
360 | 359 | ||
361 | for mut text_range in line_index.lines(highlight_range.range) { | 360 | for mut text_range in line_index.index.lines(highlight_range.range) { |
362 | if text[text_range].ends_with('\n') { | 361 | if text[text_range].ends_with('\n') { |
363 | text_range = | 362 | text_range = |
364 | TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n')); | 363 | TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n')); |
@@ -565,7 +564,7 @@ pub(crate) fn location( | |||
565 | frange: FileRange, | 564 | frange: FileRange, |
566 | ) -> Result<lsp_types::Location> { | 565 | ) -> Result<lsp_types::Location> { |
567 | let url = url(snap, frange.file_id); | 566 | let url = url(snap, frange.file_id); |
568 | let line_index = snap.analysis.file_line_index(frange.file_id)?; | 567 | let line_index = snap.file_line_index(frange.file_id)?; |
569 | let range = range(&line_index, frange.range); | 568 | let range = range(&line_index, frange.range); |
570 | let loc = lsp_types::Location::new(url, range); | 569 | let loc = lsp_types::Location::new(url, range); |
571 | Ok(loc) | 570 | Ok(loc) |
@@ -577,7 +576,7 @@ pub(crate) fn location_from_nav( | |||
577 | nav: NavigationTarget, | 576 | nav: NavigationTarget, |
578 | ) -> Result<lsp_types::Location> { | 577 | ) -> Result<lsp_types::Location> { |
579 | let url = url(snap, nav.file_id); | 578 | let url = url(snap, nav.file_id); |
580 | let line_index = snap.analysis.file_line_index(nav.file_id)?; | 579 | let line_index = snap.file_line_index(nav.file_id)?; |
581 | let range = range(&line_index, nav.full_range); | 580 | let range = range(&line_index, nav.full_range); |
582 | let loc = lsp_types::Location::new(url, range); | 581 | let loc = lsp_types::Location::new(url, range); |
583 | Ok(loc) | 582 | Ok(loc) |
@@ -590,7 +589,7 @@ pub(crate) fn location_link( | |||
590 | ) -> Result<lsp_types::LocationLink> { | 589 | ) -> Result<lsp_types::LocationLink> { |
591 | let origin_selection_range = match src { | 590 | let origin_selection_range = match src { |
592 | Some(src) => { | 591 | Some(src) => { |
593 | let line_index = snap.analysis.file_line_index(src.file_id)?; | 592 | let line_index = snap.file_line_index(src.file_id)?; |
594 | let range = range(&line_index, src.range); | 593 | let range = range(&line_index, src.range); |
595 | Some(range) | 594 | Some(range) |
596 | } | 595 | } |
@@ -610,7 +609,7 @@ fn location_info( | |||
610 | snap: &GlobalStateSnapshot, | 609 | snap: &GlobalStateSnapshot, |
611 | target: NavigationTarget, | 610 | target: NavigationTarget, |
612 | ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { | 611 | ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { |
613 | let line_index = snap.analysis.file_line_index(target.file_id)?; | 612 | let line_index = snap.file_line_index(target.file_id)?; |
614 | 613 | ||
615 | let target_uri = url(snap, target.file_id); | 614 | let target_uri = url(snap, target.file_id); |
616 | let target_range = range(&line_index, target.full_range); | 615 | let target_range = range(&line_index, target.full_range); |
@@ -648,12 +647,8 @@ pub(crate) fn snippet_text_document_edit( | |||
648 | edit: TextEdit, | 647 | edit: TextEdit, |
649 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { | 648 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { |
650 | let text_document = optional_versioned_text_document_identifier(snap, file_id); | 649 | let text_document = optional_versioned_text_document_identifier(snap, file_id); |
651 | let line_index = snap.analysis.file_line_index(file_id)?; | 650 | let line_index = snap.file_line_index(file_id)?; |
652 | let line_endings = snap.file_line_endings(file_id); | 651 | let edits = edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect(); |
653 | let edits = edit | ||
654 | .into_iter() | ||
655 | .map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it)) | ||
656 | .collect(); | ||
657 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) | 652 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) |
658 | } | 653 | } |
659 | 654 | ||
@@ -674,9 +669,8 @@ pub(crate) fn snippet_text_document_ops( | |||
674 | if !initial_contents.is_empty() { | 669 | if !initial_contents.is_empty() { |
675 | let text_document = | 670 | let text_document = |
676 | lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; | 671 | lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; |
677 | let range = range(&LineIndex::new(""), TextRange::empty(TextSize::from(0))); | ||
678 | let text_edit = lsp_ext::SnippetTextEdit { | 672 | let text_edit = lsp_ext::SnippetTextEdit { |
679 | range, | 673 | range: lsp_types::Range::default(), |
680 | new_text: initial_contents, | 674 | new_text: initial_contents, |
681 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), | 675 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), |
682 | }; | 676 | }; |
@@ -867,7 +861,7 @@ pub(crate) fn code_lens( | |||
867 | ) -> Result<lsp_types::CodeLens> { | 861 | ) -> Result<lsp_types::CodeLens> { |
868 | match annotation.kind { | 862 | match annotation.kind { |
869 | AnnotationKind::Runnable { debug, runnable: run } => { | 863 | AnnotationKind::Runnable { debug, runnable: run } => { |
870 | let line_index = snap.analysis.file_line_index(run.nav.file_id)?; | 864 | let line_index = snap.file_line_index(run.nav.file_id)?; |
871 | let annotation_range = range(&line_index, annotation.range); | 865 | let annotation_range = range(&line_index, annotation.range); |
872 | 866 | ||
873 | let action = run.action(); | 867 | let action = run.action(); |
@@ -883,7 +877,7 @@ pub(crate) fn code_lens( | |||
883 | Ok(lsp_types::CodeLens { range: annotation_range, command: Some(command), data: None }) | 877 | Ok(lsp_types::CodeLens { range: annotation_range, command: Some(command), data: None }) |
884 | } | 878 | } |
885 | AnnotationKind::HasImpls { position: file_position, data } => { | 879 | AnnotationKind::HasImpls { position: file_position, data } => { |
886 | let line_index = snap.analysis.file_line_index(file_position.file_id)?; | 880 | let line_index = snap.file_line_index(file_position.file_id)?; |
887 | let annotation_range = range(&line_index, annotation.range); | 881 | let annotation_range = range(&line_index, annotation.range); |
888 | let url = url(snap, file_position.file_id); | 882 | let url = url(snap, file_position.file_id); |
889 | 883 | ||
@@ -926,7 +920,7 @@ pub(crate) fn code_lens( | |||
926 | }) | 920 | }) |
927 | } | 921 | } |
928 | AnnotationKind::HasReferences { position: file_position, data } => { | 922 | AnnotationKind::HasReferences { position: file_position, data } => { |
929 | let line_index = snap.analysis.file_line_index(file_position.file_id)?; | 923 | let line_index = snap.file_line_index(file_position.file_id)?; |
930 | let annotation_range = range(&line_index, annotation.range); | 924 | let annotation_range = range(&line_index, annotation.range); |
931 | let url = url(snap, file_position.file_id); | 925 | let url = url(snap, file_position.file_id); |
932 | 926 | ||
@@ -1060,6 +1054,8 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { | |||
1060 | 1054 | ||
1061 | #[cfg(test)] | 1055 | #[cfg(test)] |
1062 | mod tests { | 1056 | mod tests { |
1057 | use std::sync::Arc; | ||
1058 | |||
1063 | use hir::PrefixKind; | 1059 | use hir::PrefixKind; |
1064 | use ide::Analysis; | 1060 | use ide::Analysis; |
1065 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; | 1061 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
@@ -1077,7 +1073,11 @@ mod tests { | |||
1077 | }"#; | 1073 | }"#; |
1078 | 1074 | ||
1079 | let (offset, text) = test_utils::extract_offset(fixture); | 1075 | let (offset, text) = test_utils::extract_offset(fixture); |
1080 | let line_index = LineIndex::new(&text); | 1076 | let line_index = LineIndex { |
1077 | index: Arc::new(ide::LineIndex::new(&text)), | ||
1078 | endings: LineEndings::Unix, | ||
1079 | encoding: OffsetEncoding::Utf16, | ||
1080 | }; | ||
1081 | let (analysis, file_id) = Analysis::from_single_file(text); | 1081 | let (analysis, file_id) = Analysis::from_single_file(text); |
1082 | let completions: Vec<(String, Option<String>)> = analysis | 1082 | let completions: Vec<(String, Option<String>)> = analysis |
1083 | .completions( | 1083 | .completions( |
@@ -1095,7 +1095,7 @@ mod tests { | |||
1095 | .unwrap() | 1095 | .unwrap() |
1096 | .into_iter() | 1096 | .into_iter() |
1097 | .filter(|c| c.label().ends_with("arg")) | 1097 | .filter(|c| c.label().ends_with("arg")) |
1098 | .map(|c| completion_item(&line_index, LineEndings::Unix, c)) | 1098 | .map(|c| completion_item(&line_index, c)) |
1099 | .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text))) | 1099 | .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text))) |
1100 | .collect(); | 1100 | .collect(); |
1101 | expect_test::expect![[r#" | 1101 | expect_test::expect![[r#" |
@@ -1133,7 +1133,11 @@ fn main() { | |||
1133 | let folds = analysis.folding_ranges(file_id).unwrap(); | 1133 | let folds = analysis.folding_ranges(file_id).unwrap(); |
1134 | assert_eq!(folds.len(), 4); | 1134 | assert_eq!(folds.len(), 4); |
1135 | 1135 | ||
1136 | let line_index = LineIndex::new(&text); | 1136 | let line_index = LineIndex { |
1137 | index: Arc::new(ide::LineIndex::new(&text)), | ||
1138 | endings: LineEndings::Unix, | ||
1139 | encoding: OffsetEncoding::Utf16, | ||
1140 | }; | ||
1137 | let converted: Vec<lsp_types::FoldingRange> = | 1141 | let converted: Vec<lsp_types::FoldingRange> = |
1138 | folds.into_iter().map(|it| folding_range(&text, &line_index, true, it)).collect(); | 1142 | folds.into_iter().map(|it| folding_range(&text, &line_index, true, it)).collect(); |
1139 | 1143 | ||