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 | |
parent | 95209aa3f8e4b149da6adb374611ece76c2b82ca (diff) |
Make it easy to add additional context for offset conversion
Diffstat (limited to 'crates')
-rw-r--r-- | crates/rust-analyzer/src/from_proto.rs | 20 | ||||
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 11 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 90 | ||||
-rw-r--r-- | crates/rust-analyzer/src/line_endings.rs | 7 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lsp_utils.rs | 18 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 78 |
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. |
2 | use std::convert::TryFrom; | 2 | use std::convert::TryFrom; |
3 | 3 | ||
4 | use ide::{Annotation, AnnotationKind, AssistKind, LineColUtf16, LineIndex}; | 4 | use ide::{Annotation, AnnotationKind, AssistKind, LineColUtf16}; |
5 | use ide_db::base_db::{FileId, FilePosition, FileRange}; | 5 | use ide_db::base_db::{FileId, FilePosition, FileRange}; |
6 | use syntax::{TextRange, TextSize}; | 6 | use syntax::{TextRange, TextSize}; |
7 | use vfs::AbsPathBuf; | 7 | use vfs::AbsPathBuf; |
8 | 8 | ||
9 | use crate::{from_json, global_state::GlobalStateSnapshot, lsp_ext, Result}; | 9 | use crate::{ |
10 | from_json, global_state::GlobalStateSnapshot, line_endings::LineIndex, lsp_ext, Result, | ||
11 | }; | ||
10 | 12 | ||
11 | pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> { | 13 | pub(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 | ||
20 | pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize { | 22 | pub(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 | ||
26 | pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange { | 28 | pub(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(¶ms.text_document_position_params.text_document.uri)?; | 83 | world.url_to_file_id(¶ms.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(¶ms.text_document.uri)?; | 95 | let file_id = world.url_to_file_id(¶ms.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 | ||
8 | use crossbeam_channel::{unbounded, Receiver, Sender}; | 8 | use crossbeam_channel::{unbounded, Receiver, Sender}; |
9 | use flycheck::FlycheckHandle; | 9 | use flycheck::FlycheckHandle; |
10 | use ide::{Analysis, AnalysisHost, Change, FileId}; | 10 | use ide::{Analysis, AnalysisHost, Cancelable, Change, FileId}; |
11 | use ide_db::base_db::{CrateId, VfsPath}; | 11 | use ide_db::base_db::{CrateId, VfsPath}; |
12 | use lsp_types::{SemanticTokens, Url}; | 12 | use lsp_types::{SemanticTokens, Url}; |
13 | use parking_lot::{Mutex, RwLock}; | 13 | use 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 @@ | |||
5 | use std::{ | 5 | use std::{ |
6 | io::Write as _, | 6 | io::Write as _, |
7 | process::{self, Stdio}, | 7 | process::{self, Stdio}, |
8 | sync::Arc, | ||
9 | }; | 8 | }; |
10 | 9 | ||
11 | use ide::{ | 10 | use 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 | }; |
15 | use ide_db::SymbolKind; | 14 | use ide_db::SymbolKind; |
16 | use itertools::Itertools; | 15 | use 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, ¶ms.text_document.uri)?; | 102 | let id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 124 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 137 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 180 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 202 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 278 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 534 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 730 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 957 | let file_id = from_proto::file_id(&snap, ¶ms.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( | |||
1010 | fn add_quick_fixes( | 996 | fn 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, ¶ms.code_action_params.text_document.uri)?; | 1040 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 1214 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 1322 | let file_id = from_proto::file_id(&snap, ¶ms.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, ¶ms.text_document.uri)?; | 1341 | let file_id = from_proto::file_id(&snap, ¶ms.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 | ||
5 | use std::sync::Arc; | ||
6 | |||
7 | pub(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)] |
6 | pub(crate) enum LineEndings { | 13 | pub(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. |
2 | use std::{error::Error, ops::Range}; | 2 | use std::{error::Error, ops::Range, sync::Arc}; |
3 | 3 | ||
4 | use ide::LineIndex; | ||
5 | use ide_db::base_db::Canceled; | 4 | use ide_db::base_db::Canceled; |
6 | use lsp_server::Notification; | 5 | use lsp_server::Notification; |
7 | 6 | ||
8 | use crate::{from_proto, global_state::GlobalState}; | 7 | use crate::{ |
8 | from_proto, | ||
9 | global_state::GlobalState, | ||
10 | line_endings::{LineEndings, LineIndex}, | ||
11 | }; | ||
9 | 12 | ||
10 | pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool { | 13 | pub(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::{ | |||
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 | ||