aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/to_proto.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-02-16 16:34:22 +0000
committerGitHub <[email protected]>2021-02-16 16:34:22 +0000
commitc9672a0539a59b626619724092077f57c70e6ffe (patch)
tree77097454dc598a5e0a0b1d98b8c9645b9e213289 /crates/rust-analyzer/src/to_proto.rs
parentf7b7a09f752caba21f2b21ccb8f74421a599d2c6 (diff)
parent3f09e3fba62839f26da2f27ce27a2335b1dca7ef (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.rs90
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::{
7use ide::{ 7use 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};
14use ide_db::SymbolKind; 13use ide_db::SymbolKind;
15use itertools::Itertools; 14use itertools::Itertools;
16use serde_json::to_value; 15use serde_json::to_value;
17 16
18use crate::{ 17use 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
23pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { 24pub(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
28pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range { 35pub(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
125pub(crate) fn text_edit( 132pub(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
138pub(crate) fn snippet_text_edit( 141pub(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
154pub(crate) fn text_edit_vec( 156pub(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
162pub(crate) fn snippet_text_edit_vec( 163pub(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
174pub(crate) fn completion_item( 174pub(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)]
1062mod tests { 1056mod 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