aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/rust-analyzer/src/from_proto.rs20
-rw-r--r--crates/rust-analyzer/src/global_state.rs11
-rw-r--r--crates/rust-analyzer/src/handlers.rs90
-rw-r--r--crates/rust-analyzer/src/line_endings.rs7
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs18
-rw-r--r--crates/rust-analyzer/src/to_proto.rs78
6 files changed, 111 insertions, 113 deletions
diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs
index de995412c..c671b5f64 100644
--- a/crates/rust-analyzer/src/from_proto.rs
+++ b/crates/rust-analyzer/src/from_proto.rs
@@ -1,12 +1,14 @@
1//! Conversion lsp_types types to rust-analyzer specific ones. 1//! Conversion lsp_types types to rust-analyzer specific ones.
2use std::convert::TryFrom; 2use std::convert::TryFrom;
3 3
4use ide::{Annotation, AnnotationKind, AssistKind, LineColUtf16, LineIndex}; 4use ide::{Annotation, AnnotationKind, AssistKind, LineColUtf16};
5use ide_db::base_db::{FileId, FilePosition, FileRange}; 5use ide_db::base_db::{FileId, FilePosition, FileRange};
6use syntax::{TextRange, TextSize}; 6use syntax::{TextRange, TextSize};
7use vfs::AbsPathBuf; 7use vfs::AbsPathBuf;
8 8
9use crate::{from_json, global_state::GlobalStateSnapshot, lsp_ext, Result}; 9use crate::{
10 from_json, global_state::GlobalStateSnapshot, line_endings::LineIndex, lsp_ext, Result,
11};
10 12
11pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> { 13pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> {
12 let path = url.to_file_path().map_err(|()| "url is not a file")?; 14 let path = url.to_file_path().map_err(|()| "url is not a file")?;
@@ -19,8 +21,8 @@ pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath> {
19 21
20pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize { 22pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize {
21 let line_col = LineColUtf16 { line: position.line as u32, col: position.character as u32 }; 23 let line_col = LineColUtf16 { line: position.line as u32, col: position.character as u32 };
22 let line_col = line_index.to_utf8(line_col); 24 let line_col = line_index.index.to_utf8(line_col);
23 line_index.offset(line_col) 25 line_index.index.offset(line_col)
24} 26}
25 27
26pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange { 28pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange {
@@ -38,8 +40,8 @@ pub(crate) fn file_position(
38 tdpp: lsp_types::TextDocumentPositionParams, 40 tdpp: lsp_types::TextDocumentPositionParams,
39) -> Result<FilePosition> { 41) -> Result<FilePosition> {
40 let file_id = file_id(world, &tdpp.text_document.uri)?; 42 let file_id = file_id(world, &tdpp.text_document.uri)?;
41 let line_index = world.analysis.file_line_index(file_id)?; 43 let line_index = world.file_line_index(file_id)?;
42 let offset = offset(&*line_index, tdpp.position); 44 let offset = offset(&line_index, tdpp.position);
43 Ok(FilePosition { file_id, offset }) 45 Ok(FilePosition { file_id, offset })
44} 46}
45 47
@@ -49,7 +51,7 @@ pub(crate) fn file_range(
49 range: lsp_types::Range, 51 range: lsp_types::Range,
50) -> Result<FileRange> { 52) -> Result<FileRange> {
51 let file_id = file_id(world, &text_document_identifier.uri)?; 53 let file_id = file_id(world, &text_document_identifier.uri)?;
52 let line_index = world.analysis.file_line_index(file_id)?; 54 let line_index = world.file_line_index(file_id)?;
53 let range = text_range(&line_index, range); 55 let range = text_range(&line_index, range);
54 Ok(FileRange { file_id, range }) 56 Ok(FileRange { file_id, range })
55} 57}
@@ -79,7 +81,7 @@ pub(crate) fn annotation(
79 lsp_ext::CodeLensResolveData::Impls(params) => { 81 lsp_ext::CodeLensResolveData::Impls(params) => {
80 let file_id = 82 let file_id =
81 world.url_to_file_id(&params.text_document_position_params.text_document.uri)?; 83 world.url_to_file_id(&params.text_document_position_params.text_document.uri)?;
82 let line_index = world.analysis.file_line_index(file_id)?; 84 let line_index = world.file_line_index(file_id)?;
83 85
84 Ok(Annotation { 86 Ok(Annotation {
85 range: text_range(&line_index, code_lens.range), 87 range: text_range(&line_index, code_lens.range),
@@ -91,7 +93,7 @@ pub(crate) fn annotation(
91 } 93 }
92 lsp_ext::CodeLensResolveData::References(params) => { 94 lsp_ext::CodeLensResolveData::References(params) => {
93 let file_id = world.url_to_file_id(&params.text_document.uri)?; 95 let file_id = world.url_to_file_id(&params.text_document.uri)?;
94 let line_index = world.analysis.file_line_index(file_id)?; 96 let line_index = world.file_line_index(file_id)?;
95 97
96 Ok(Annotation { 98 Ok(Annotation {
97 range: text_range(&line_index, code_lens.range), 99 range: text_range(&line_index, code_lens.range),
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index c3bc8791d..ffef33430 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -7,7 +7,7 @@ use std::{sync::Arc, time::Instant};
7 7
8use crossbeam_channel::{unbounded, Receiver, Sender}; 8use crossbeam_channel::{unbounded, Receiver, Sender};
9use flycheck::FlycheckHandle; 9use flycheck::FlycheckHandle;
10use ide::{Analysis, AnalysisHost, Change, FileId}; 10use ide::{Analysis, AnalysisHost, Cancelable, Change, FileId};
11use ide_db::base_db::{CrateId, VfsPath}; 11use ide_db::base_db::{CrateId, VfsPath};
12use lsp_types::{SemanticTokens, Url}; 12use lsp_types::{SemanticTokens, Url};
13use parking_lot::{Mutex, RwLock}; 13use parking_lot::{Mutex, RwLock};
@@ -22,7 +22,7 @@ use crate::{
22 diagnostics::{CheckFixes, DiagnosticCollection}, 22 diagnostics::{CheckFixes, DiagnosticCollection},
23 document::DocumentData, 23 document::DocumentData,
24 from_proto, 24 from_proto,
25 line_endings::LineEndings, 25 line_endings::{LineEndings, LineIndex},
26 main_loop::Task, 26 main_loop::Task,
27 op_queue::OpQueue, 27 op_queue::OpQueue,
28 reload::SourceRootConfig, 28 reload::SourceRootConfig,
@@ -271,8 +271,11 @@ impl GlobalStateSnapshot {
271 file_id_to_url(&self.vfs.read().0, id) 271 file_id_to_url(&self.vfs.read().0, id)
272 } 272 }
273 273
274 pub(crate) fn file_line_endings(&self, id: FileId) -> LineEndings { 274 pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancelable<LineIndex> {
275 self.vfs.read().1[&id] 275 let endings = self.vfs.read().1[&file_id];
276 let index = self.analysis.file_line_index(file_id)?;
277 let res = LineIndex { index, endings };
278 Ok(res)
276 } 279 }
277 280
278 pub(crate) fn url_file_version(&self, url: &Url) -> Option<i32> { 281 pub(crate) fn url_file_version(&self, url: &Url) -> Option<i32> {
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 2d697c75f..d8b00e9c5 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -5,12 +5,11 @@
5use std::{ 5use std::{
6 io::Write as _, 6 io::Write as _,
7 process::{self, Stdio}, 7 process::{self, Stdio},
8 sync::Arc,
9}; 8};
10 9
11use ide::{ 10use ide::{
12 AnnotationConfig, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, 11 AnnotationConfig, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, Query,
13 Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit, 12 RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit,
14}; 13};
15use ide_db::SymbolKind; 14use ide_db::SymbolKind;
16use itertools::Itertools; 15use itertools::Itertools;
@@ -38,6 +37,7 @@ use crate::{
38 from_proto, 37 from_proto,
39 global_state::{GlobalState, GlobalStateSnapshot}, 38 global_state::{GlobalState, GlobalStateSnapshot},
40 line_endings::LineEndings, 39 line_endings::LineEndings,
40 line_endings::LineIndex,
41 lsp_ext::{self, InlayHint, InlayHintsParams}, 41 lsp_ext::{self, InlayHint, InlayHintsParams},
42 lsp_utils::all_edits_are_disjoint, 42 lsp_utils::all_edits_are_disjoint,
43 to_proto, LspError, Result, 43 to_proto, LspError, Result,
@@ -100,7 +100,7 @@ pub(crate) fn handle_syntax_tree(
100) -> Result<String> { 100) -> Result<String> {
101 let _p = profile::span("handle_syntax_tree"); 101 let _p = profile::span("handle_syntax_tree");
102 let id = from_proto::file_id(&snap, &params.text_document.uri)?; 102 let id = from_proto::file_id(&snap, &params.text_document.uri)?;
103 let line_index = snap.analysis.file_line_index(id)?; 103 let line_index = snap.file_line_index(id)?;
104 let text_range = params.range.map(|r| from_proto::text_range(&line_index, r)); 104 let text_range = params.range.map(|r| from_proto::text_range(&line_index, r));
105 let res = snap.analysis.syntax_tree(id, text_range)?; 105 let res = snap.analysis.syntax_tree(id, text_range)?;
106 Ok(res) 106 Ok(res)
@@ -122,7 +122,7 @@ pub(crate) fn handle_expand_macro(
122) -> Result<Option<lsp_ext::ExpandedMacro>> { 122) -> Result<Option<lsp_ext::ExpandedMacro>> {
123 let _p = profile::span("handle_expand_macro"); 123 let _p = profile::span("handle_expand_macro");
124 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 124 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
125 let line_index = snap.analysis.file_line_index(file_id)?; 125 let line_index = snap.file_line_index(file_id)?;
126 let offset = from_proto::offset(&line_index, params.position); 126 let offset = from_proto::offset(&line_index, params.position);
127 127
128 let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?; 128 let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?;
@@ -135,7 +135,7 @@ pub(crate) fn handle_selection_range(
135) -> Result<Option<Vec<lsp_types::SelectionRange>>> { 135) -> Result<Option<Vec<lsp_types::SelectionRange>>> {
136 let _p = profile::span("handle_selection_range"); 136 let _p = profile::span("handle_selection_range");
137 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 137 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
138 let line_index = snap.analysis.file_line_index(file_id)?; 138 let line_index = snap.file_line_index(file_id)?;
139 let res: Result<Vec<lsp_types::SelectionRange>> = params 139 let res: Result<Vec<lsp_types::SelectionRange>> = params
140 .positions 140 .positions
141 .into_iter() 141 .into_iter()
@@ -178,7 +178,7 @@ pub(crate) fn handle_matching_brace(
178) -> Result<Vec<Position>> { 178) -> Result<Vec<Position>> {
179 let _p = profile::span("handle_matching_brace"); 179 let _p = profile::span("handle_matching_brace");
180 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 180 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
181 let line_index = snap.analysis.file_line_index(file_id)?; 181 let line_index = snap.file_line_index(file_id)?;
182 let res = params 182 let res = params
183 .positions 183 .positions
184 .into_iter() 184 .into_iter()
@@ -200,8 +200,7 @@ pub(crate) fn handle_join_lines(
200) -> Result<Vec<lsp_types::TextEdit>> { 200) -> Result<Vec<lsp_types::TextEdit>> {
201 let _p = profile::span("handle_join_lines"); 201 let _p = profile::span("handle_join_lines");
202 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 202 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
203 let line_index = snap.analysis.file_line_index(file_id)?; 203 let line_index = snap.file_line_index(file_id)?;
204 let line_endings = snap.file_line_endings(file_id);
205 let mut res = TextEdit::default(); 204 let mut res = TextEdit::default();
206 for range in params.ranges { 205 for range in params.ranges {
207 let range = from_proto::text_range(&line_index, range); 206 let range = from_proto::text_range(&line_index, range);
@@ -213,7 +212,7 @@ pub(crate) fn handle_join_lines(
213 } 212 }
214 } 213 }
215 } 214 }
216 let res = to_proto::text_edit_vec(&line_index, line_endings, res); 215 let res = to_proto::text_edit_vec(&line_index, res);
217 Ok(res) 216 Ok(res)
218} 217}
219 218
@@ -227,9 +226,8 @@ pub(crate) fn handle_on_enter(
227 None => return Ok(None), 226 None => return Ok(None),
228 Some(it) => it, 227 Some(it) => it,
229 }; 228 };
230 let line_index = snap.analysis.file_line_index(position.file_id)?; 229 let line_index = snap.file_line_index(position.file_id)?;
231 let line_endings = snap.file_line_endings(position.file_id); 230 let edit = to_proto::snippet_text_edit_vec(&line_index, true, edit);
232 let edit = to_proto::snippet_text_edit_vec(&line_index, line_endings, true, edit);
233 Ok(Some(edit)) 231 Ok(Some(edit))
234} 232}
235 233
@@ -240,8 +238,7 @@ pub(crate) fn handle_on_type_formatting(
240) -> Result<Option<Vec<lsp_types::TextEdit>>> { 238) -> Result<Option<Vec<lsp_types::TextEdit>>> {
241 let _p = profile::span("handle_on_type_formatting"); 239 let _p = profile::span("handle_on_type_formatting");
242 let mut position = from_proto::file_position(&snap, params.text_document_position)?; 240 let mut position = from_proto::file_position(&snap, params.text_document_position)?;
243 let line_index = snap.analysis.file_line_index(position.file_id)?; 241 let line_index = snap.file_line_index(position.file_id)?;
244 let line_endings = snap.file_line_endings(position.file_id);
245 242
246 // in `ide`, the `on_type` invariant is that 243 // in `ide`, the `on_type` invariant is that
247 // `text.char_at(position) == typed_char`. 244 // `text.char_at(position) == typed_char`.
@@ -269,7 +266,7 @@ pub(crate) fn handle_on_type_formatting(
269 // This should be a single-file edit 266 // This should be a single-file edit
270 let (_, edit) = edit.source_file_edits.into_iter().next().unwrap(); 267 let (_, edit) = edit.source_file_edits.into_iter().next().unwrap();
271 268
272 let change = to_proto::text_edit_vec(&line_index, line_endings, edit); 269 let change = to_proto::text_edit_vec(&line_index, edit);
273 Ok(Some(change)) 270 Ok(Some(change))
274} 271}
275 272
@@ -279,7 +276,7 @@ pub(crate) fn handle_document_symbol(
279) -> Result<Option<lsp_types::DocumentSymbolResponse>> { 276) -> Result<Option<lsp_types::DocumentSymbolResponse>> {
280 let _p = profile::span("handle_document_symbol"); 277 let _p = profile::span("handle_document_symbol");
281 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 278 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
282 let line_index = snap.analysis.file_line_index(file_id)?; 279 let line_index = snap.file_line_index(file_id)?;
283 280
284 let mut parents: Vec<(lsp_types::DocumentSymbol, Option<usize>)> = Vec::new(); 281 let mut parents: Vec<(lsp_types::DocumentSymbol, Option<usize>)> = Vec::new();
285 282
@@ -535,7 +532,7 @@ pub(crate) fn handle_runnables(
535) -> Result<Vec<lsp_ext::Runnable>> { 532) -> Result<Vec<lsp_ext::Runnable>> {
536 let _p = profile::span("handle_runnables"); 533 let _p = profile::span("handle_runnables");
537 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 534 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
538 let line_index = snap.analysis.file_line_index(file_id)?; 535 let line_index = snap.file_line_index(file_id)?;
539 let offset = params.position.map(|it| from_proto::offset(&line_index, it)); 536 let offset = params.position.map(|it| from_proto::offset(&line_index, it));
540 let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; 537 let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
541 538
@@ -645,14 +642,12 @@ pub(crate) fn handle_completion(
645 None => return Ok(None), 642 None => return Ok(None),
646 Some(items) => items, 643 Some(items) => items,
647 }; 644 };
648 let line_index = snap.analysis.file_line_index(position.file_id)?; 645 let line_index = snap.file_line_index(position.file_id)?;
649 let line_endings = snap.file_line_endings(position.file_id);
650 646
651 let items: Vec<CompletionItem> = items 647 let items: Vec<CompletionItem> = items
652 .into_iter() 648 .into_iter()
653 .flat_map(|item| { 649 .flat_map(|item| {
654 let mut new_completion_items = 650 let mut new_completion_items = to_proto::completion_item(&line_index, item.clone());
655 to_proto::completion_item(&line_index, line_endings, item.clone());
656 651
657 if completion_config.enable_imports_on_the_fly { 652 if completion_config.enable_imports_on_the_fly {
658 for new_item in &mut new_completion_items { 653 for new_item in &mut new_completion_items {
@@ -693,8 +688,7 @@ pub(crate) fn handle_completion_resolve(
693 }; 688 };
694 689
695 let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?; 690 let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
696 let line_index = snap.analysis.file_line_index(file_id)?; 691 let line_index = snap.file_line_index(file_id)?;
697 let line_endings = snap.file_line_endings(file_id);
698 let offset = from_proto::offset(&line_index, resolve_data.position.position); 692 let offset = from_proto::offset(&line_index, resolve_data.position.position);
699 693
700 let additional_edits = snap 694 let additional_edits = snap
@@ -707,9 +701,7 @@ pub(crate) fn handle_completion_resolve(
707 resolve_data.import_for_trait_assoc_item, 701 resolve_data.import_for_trait_assoc_item,
708 )? 702 )?
709 .into_iter() 703 .into_iter()
710 .flat_map(|edit| { 704 .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
711 edit.into_iter().map(|indel| to_proto::text_edit(&line_index, line_endings, indel))
712 })
713 .collect_vec(); 705 .collect_vec();
714 706
715 if !all_edits_are_disjoint(&original_completion, &additional_edits) { 707 if !all_edits_are_disjoint(&original_completion, &additional_edits) {
@@ -738,7 +730,7 @@ pub(crate) fn handle_folding_range(
738 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 730 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
739 let folds = snap.analysis.folding_ranges(file_id)?; 731 let folds = snap.analysis.folding_ranges(file_id)?;
740 let text = snap.analysis.file_text(file_id)?; 732 let text = snap.analysis.file_text(file_id)?;
741 let line_index = snap.analysis.file_line_index(file_id)?; 733 let line_index = snap.file_line_index(file_id)?;
742 let line_folding_only = snap.config.line_folding_only(); 734 let line_folding_only = snap.config.line_folding_only();
743 let res = folds 735 let res = folds
744 .into_iter() 736 .into_iter()
@@ -775,7 +767,7 @@ pub(crate) fn handle_hover(
775 None => return Ok(None), 767 None => return Ok(None),
776 Some(info) => info, 768 Some(info) => info,
777 }; 769 };
778 let line_index = snap.analysis.file_line_index(position.file_id)?; 770 let line_index = snap.file_line_index(position.file_id)?;
779 let range = to_proto::range(&line_index, info.range); 771 let range = to_proto::range(&line_index, info.range);
780 let hover = lsp_ext::Hover { 772 let hover = lsp_ext::Hover {
781 hover: lsp_types::Hover { 773 hover: lsp_types::Hover {
@@ -797,7 +789,7 @@ pub(crate) fn handle_prepare_rename(
797 789
798 let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?; 790 let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?;
799 791
800 let line_index = snap.analysis.file_line_index(position.file_id)?; 792 let line_index = snap.file_line_index(position.file_id)?;
801 let range = to_proto::range(&line_index, change.range); 793 let range = to_proto::range(&line_index, change.range);
802 Ok(Some(PrepareRenameResponse::Range(range))) 794 Ok(Some(PrepareRenameResponse::Range(range)))
803} 795}
@@ -857,8 +849,7 @@ pub(crate) fn handle_formatting(
857 let file = snap.analysis.file_text(file_id)?; 849 let file = snap.analysis.file_text(file_id)?;
858 let crate_ids = snap.analysis.crate_for(file_id)?; 850 let crate_ids = snap.analysis.crate_for(file_id)?;
859 851
860 let file_line_index = snap.analysis.file_line_index(file_id)?; 852 let line_index = snap.file_line_index(file_id)?;
861 let file_line_endings = snap.file_line_endings(file_id);
862 853
863 let mut rustfmt = match snap.config.rustfmt() { 854 let mut rustfmt = match snap.config.rustfmt() {
864 RustfmtConfig::Rustfmt { extra_args } => { 855 RustfmtConfig::Rustfmt { extra_args } => {
@@ -935,24 +926,19 @@ pub(crate) fn handle_formatting(
935 926
936 let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout); 927 let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout);
937 928
938 if file_line_endings != new_line_endings { 929 if line_index.endings != new_line_endings {
939 // If line endings are different, send the entire file. 930 // If line endings are different, send the entire file.
940 // Diffing would not work here, as the line endings might be the only 931 // Diffing would not work here, as the line endings might be the only
941 // difference. 932 // difference.
942 Ok(Some(to_proto::text_edit_vec( 933 Ok(Some(to_proto::text_edit_vec(
943 &file_line_index, 934 &line_index,
944 new_line_endings,
945 TextEdit::replace(TextRange::up_to(TextSize::of(&*file)), new_text), 935 TextEdit::replace(TextRange::up_to(TextSize::of(&*file)), new_text),
946 ))) 936 )))
947 } else if *file == new_text { 937 } else if *file == new_text {
948 // The document is already formatted correctly -- no edits needed. 938 // The document is already formatted correctly -- no edits needed.
949 Ok(None) 939 Ok(None)
950 } else { 940 } else {
951 Ok(Some(to_proto::text_edit_vec( 941 Ok(Some(to_proto::text_edit_vec(&line_index, diff(&file, &new_text))))
952 &file_line_index,
953 file_line_endings,
954 diff(&file, &new_text),
955 )))
956 } 942 }
957} 943}
958 944
@@ -969,7 +955,7 @@ pub(crate) fn handle_code_action(
969 } 955 }
970 956
971 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 957 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
972 let line_index = snap.analysis.file_line_index(file_id)?; 958 let line_index = snap.file_line_index(file_id)?;
973 let range = from_proto::text_range(&line_index, params.range); 959 let range = from_proto::text_range(&line_index, params.range);
974 let frange = FileRange { file_id, range }; 960 let frange = FileRange { file_id, range };
975 961
@@ -1010,7 +996,7 @@ pub(crate) fn handle_code_action(
1010fn add_quick_fixes( 996fn add_quick_fixes(
1011 snap: &GlobalStateSnapshot, 997 snap: &GlobalStateSnapshot,
1012 frange: FileRange, 998 frange: FileRange,
1013 line_index: &Arc<LineIndex>, 999 line_index: &LineIndex,
1014 acc: &mut Vec<lsp_ext::CodeAction>, 1000 acc: &mut Vec<lsp_ext::CodeAction>,
1015) -> Result<()> { 1001) -> Result<()> {
1016 let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics(), frange.file_id)?; 1002 let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics(), frange.file_id)?;
@@ -1052,7 +1038,7 @@ pub(crate) fn handle_code_action_resolve(
1052 }; 1038 };
1053 1039
1054 let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?; 1040 let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
1055 let line_index = snap.analysis.file_line_index(file_id)?; 1041 let line_index = snap.file_line_index(file_id)?;
1056 let range = from_proto::text_range(&line_index, params.code_action_params.range); 1042 let range = from_proto::text_range(&line_index, params.code_action_params.range);
1057 let frange = FileRange { file_id, range }; 1043 let frange = FileRange { file_id, range };
1058 1044
@@ -1131,7 +1117,7 @@ pub(crate) fn handle_document_highlight(
1131) -> Result<Option<Vec<DocumentHighlight>>> { 1117) -> Result<Option<Vec<DocumentHighlight>>> {
1132 let _p = profile::span("handle_document_highlight"); 1118 let _p = profile::span("handle_document_highlight");
1133 let position = from_proto::file_position(&snap, params.text_document_position_params)?; 1119 let position = from_proto::file_position(&snap, params.text_document_position_params)?;
1134 let line_index = snap.analysis.file_line_index(position.file_id)?; 1120 let line_index = snap.file_line_index(position.file_id)?;
1135 1121
1136 let refs = match snap 1122 let refs = match snap
1137 .analysis 1123 .analysis
@@ -1192,7 +1178,7 @@ pub(crate) fn publish_diagnostics(
1192 file_id: FileId, 1178 file_id: FileId,
1193) -> Result<Vec<Diagnostic>> { 1179) -> Result<Vec<Diagnostic>> {
1194 let _p = profile::span("publish_diagnostics"); 1180 let _p = profile::span("publish_diagnostics");
1195 let line_index = snap.analysis.file_line_index(file_id)?; 1181 let line_index = snap.file_line_index(file_id)?;
1196 1182
1197 let diagnostics: Vec<Diagnostic> = snap 1183 let diagnostics: Vec<Diagnostic> = snap
1198 .analysis 1184 .analysis
@@ -1226,7 +1212,7 @@ pub(crate) fn handle_inlay_hints(
1226) -> Result<Vec<InlayHint>> { 1212) -> Result<Vec<InlayHint>> {
1227 let _p = profile::span("handle_inlay_hints"); 1213 let _p = profile::span("handle_inlay_hints");
1228 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 1214 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
1229 let line_index = snap.analysis.file_line_index(file_id)?; 1215 let line_index = snap.file_line_index(file_id)?;
1230 Ok(snap 1216 Ok(snap
1231 .analysis 1217 .analysis
1232 .inlay_hints(file_id, &snap.config.inlay_hints())? 1218 .inlay_hints(file_id, &snap.config.inlay_hints())?
@@ -1277,7 +1263,7 @@ pub(crate) fn handle_call_hierarchy_incoming(
1277 1263
1278 for call_item in call_items.into_iter() { 1264 for call_item in call_items.into_iter() {
1279 let file_id = call_item.target.file_id; 1265 let file_id = call_item.target.file_id;
1280 let line_index = snap.analysis.file_line_index(file_id)?; 1266 let line_index = snap.file_line_index(file_id)?;
1281 let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; 1267 let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
1282 res.push(CallHierarchyIncomingCall { 1268 res.push(CallHierarchyIncomingCall {
1283 from: item, 1269 from: item,
@@ -1312,7 +1298,7 @@ pub(crate) fn handle_call_hierarchy_outgoing(
1312 1298
1313 for call_item in call_items.into_iter() { 1299 for call_item in call_items.into_iter() {
1314 let file_id = call_item.target.file_id; 1300 let file_id = call_item.target.file_id;
1315 let line_index = snap.analysis.file_line_index(file_id)?; 1301 let line_index = snap.file_line_index(file_id)?;
1316 let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; 1302 let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
1317 res.push(CallHierarchyOutgoingCall { 1303 res.push(CallHierarchyOutgoingCall {
1318 to: item, 1304 to: item,
@@ -1335,7 +1321,7 @@ pub(crate) fn handle_semantic_tokens_full(
1335 1321
1336 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 1322 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
1337 let text = snap.analysis.file_text(file_id)?; 1323 let text = snap.analysis.file_text(file_id)?;
1338 let line_index = snap.analysis.file_line_index(file_id)?; 1324 let line_index = snap.file_line_index(file_id)?;
1339 1325
1340 let highlights = snap.analysis.highlight(file_id)?; 1326 let highlights = snap.analysis.highlight(file_id)?;
1341 let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); 1327 let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
@@ -1354,7 +1340,7 @@ pub(crate) fn handle_semantic_tokens_full_delta(
1354 1340
1355 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 1341 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
1356 let text = snap.analysis.file_text(file_id)?; 1342 let text = snap.analysis.file_text(file_id)?;
1357 let line_index = snap.analysis.file_line_index(file_id)?; 1343 let line_index = snap.file_line_index(file_id)?;
1358 1344
1359 let highlights = snap.analysis.highlight(file_id)?; 1345 let highlights = snap.analysis.highlight(file_id)?;
1360 1346
@@ -1384,7 +1370,7 @@ pub(crate) fn handle_semantic_tokens_range(
1384 1370
1385 let frange = from_proto::file_range(&snap, params.text_document, params.range)?; 1371 let frange = from_proto::file_range(&snap, params.text_document, params.range)?;
1386 let text = snap.analysis.file_text(frange.file_id)?; 1372 let text = snap.analysis.file_text(frange.file_id)?;
1387 let line_index = snap.analysis.file_line_index(frange.file_id)?; 1373 let line_index = snap.file_line_index(frange.file_id)?;
1388 1374
1389 let highlights = snap.analysis.highlight_range(frange)?; 1375 let highlights = snap.analysis.highlight_range(frange)?;
1390 let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); 1376 let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
@@ -1432,7 +1418,7 @@ fn show_impl_command_link(
1432 if snap.config.hover().implementations { 1418 if snap.config.hover().implementations {
1433 if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { 1419 if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
1434 let uri = to_proto::url(snap, position.file_id); 1420 let uri = to_proto::url(snap, position.file_id);
1435 let line_index = snap.analysis.file_line_index(position.file_id).ok()?; 1421 let line_index = snap.file_line_index(position.file_id).ok()?;
1436 let position = to_proto::position(&line_index, position.offset); 1422 let position = to_proto::position(&line_index, position.offset);
1437 let locations: Vec<_> = nav_data 1423 let locations: Vec<_> = nav_data
1438 .info 1424 .info
diff --git a/crates/rust-analyzer/src/line_endings.rs b/crates/rust-analyzer/src/line_endings.rs
index bf0e255d9..cc152c529 100644
--- a/crates/rust-analyzer/src/line_endings.rs
+++ b/crates/rust-analyzer/src/line_endings.rs
@@ -2,6 +2,13 @@
2//! This module does line ending conversion and detection (so that we can 2//! This module does line ending conversion and detection (so that we can
3//! convert back to `\r\n` on the way out). 3//! convert back to `\r\n` on the way out).
4 4
5use std::sync::Arc;
6
7pub(crate) struct LineIndex {
8 pub(crate) index: Arc<ide::LineIndex>,
9 pub(crate) endings: LineEndings,
10}
11
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub(crate) enum LineEndings { 13pub(crate) enum LineEndings {
7 Unix, 14 Unix,
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index 2d06fe538..25162185e 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -1,11 +1,14 @@
1//! Utilities for LSP-related boilerplate code. 1//! Utilities for LSP-related boilerplate code.
2use std::{error::Error, ops::Range}; 2use std::{error::Error, ops::Range, sync::Arc};
3 3
4use ide::LineIndex;
5use ide_db::base_db::Canceled; 4use ide_db::base_db::Canceled;
6use lsp_server::Notification; 5use lsp_server::Notification;
7 6
8use crate::{from_proto, global_state::GlobalState}; 7use crate::{
8 from_proto,
9 global_state::GlobalState,
10 line_endings::{LineEndings, LineIndex},
11};
9 12
10pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool { 13pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool {
11 e.downcast_ref::<Canceled>().is_some() 14 e.downcast_ref::<Canceled>().is_some()
@@ -90,7 +93,12 @@ pub(crate) fn apply_document_changes(
90 old_text: &mut String, 93 old_text: &mut String,
91 content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>, 94 content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
92) { 95) {
93 let mut line_index = LineIndex::new(old_text); 96 let mut line_index = LineIndex {
97 index: Arc::new(ide::LineIndex::new(old_text)),
98 // We don't care about line endings here.
99 endings: LineEndings::Unix,
100 };
101
94 // The changes we got must be applied sequentially, but can cross lines so we 102 // The changes we got must be applied sequentially, but can cross lines so we
95 // have to keep our line index updated. 103 // have to keep our line index updated.
96 // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we 104 // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we
@@ -115,7 +123,7 @@ pub(crate) fn apply_document_changes(
115 match change.range { 123 match change.range {
116 Some(range) => { 124 Some(range) => {
117 if !index_valid.covers(range.end.line) { 125 if !index_valid.covers(range.end.line) {
118 line_index = LineIndex::new(&old_text); 126 line_index.index = Arc::new(ide::LineIndex::new(&old_text));
119 } 127 }
120 index_valid = IndexValid::UpToLineExclusive(range.start.line); 128 index_valid = IndexValid::UpToLineExclusive(range.start.line);
121 let range = from_proto::text_range(&line_index, range); 129 let range = from_proto::text_range(&line_index, range);
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::{
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_endings::{LineEndings, LineIndex},
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 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
126pub(crate) fn text_edit( 127pub(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
139pub(crate) fn snippet_text_edit( 136pub(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
155pub(crate) fn text_edit_vec( 151pub(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
163pub(crate) fn snippet_text_edit_vec( 158pub(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
175pub(crate) fn completion_item( 169pub(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)]
1063mod tests { 1051mod 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