diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index de995412c64..c671b5f649c 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -1,12 +1,14 @@ //! Conversion lsp_types types to rust-analyzer specific ones. use std::convert::TryFrom; -use ide::{Annotation, AnnotationKind, AssistKind, LineColUtf16, LineIndex}; +use ide::{Annotation, AnnotationKind, AssistKind, LineColUtf16}; use ide_db::base_db::{FileId, FilePosition, FileRange}; use syntax::{TextRange, TextSize}; use vfs::AbsPathBuf; -use crate::{from_json, global_state::GlobalStateSnapshot, lsp_ext, Result}; +use crate::{ + from_json, global_state::GlobalStateSnapshot, line_endings::LineIndex, lsp_ext, Result, +}; pub(crate) fn abs_path(url: &lsp_types::Url) -> Result { 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 { pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize { let line_col = LineColUtf16 { line: position.line as u32, col: position.character as u32 }; - let line_col = line_index.to_utf8(line_col); - line_index.offset(line_col) + let line_col = line_index.index.to_utf8(line_col); + line_index.index.offset(line_col) } pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange { @@ -38,8 +40,8 @@ pub(crate) fn file_position( tdpp: lsp_types::TextDocumentPositionParams, ) -> Result { let file_id = file_id(world, &tdpp.text_document.uri)?; - let line_index = world.analysis.file_line_index(file_id)?; - let offset = offset(&*line_index, tdpp.position); + let line_index = world.file_line_index(file_id)?; + let offset = offset(&line_index, tdpp.position); Ok(FilePosition { file_id, offset }) } @@ -49,7 +51,7 @@ pub(crate) fn file_range( range: lsp_types::Range, ) -> Result { let file_id = file_id(world, &text_document_identifier.uri)?; - let line_index = world.analysis.file_line_index(file_id)?; + let line_index = world.file_line_index(file_id)?; let range = text_range(&line_index, range); Ok(FileRange { file_id, range }) } @@ -79,7 +81,7 @@ pub(crate) fn annotation( lsp_ext::CodeLensResolveData::Impls(params) => { let file_id = world.url_to_file_id(¶ms.text_document_position_params.text_document.uri)?; - let line_index = world.analysis.file_line_index(file_id)?; + let line_index = world.file_line_index(file_id)?; Ok(Annotation { range: text_range(&line_index, code_lens.range), @@ -91,7 +93,7 @@ pub(crate) fn annotation( } lsp_ext::CodeLensResolveData::References(params) => { let file_id = world.url_to_file_id(¶ms.text_document.uri)?; - let line_index = world.analysis.file_line_index(file_id)?; + let line_index = world.file_line_index(file_id)?; Ok(Annotation { 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 c3bc8791d4b..ffef33430ca 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}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; -use ide::{Analysis, AnalysisHost, Change, FileId}; +use ide::{Analysis, AnalysisHost, Cancelable, Change, FileId}; use ide_db::base_db::{CrateId, VfsPath}; use lsp_types::{SemanticTokens, Url}; use parking_lot::{Mutex, RwLock}; @@ -22,7 +22,7 @@ use crate::{ diagnostics::{CheckFixes, DiagnosticCollection}, document::DocumentData, from_proto, - line_endings::LineEndings, + line_endings::{LineEndings, LineIndex}, main_loop::Task, op_queue::OpQueue, reload::SourceRootConfig, @@ -271,8 +271,11 @@ impl GlobalStateSnapshot { file_id_to_url(&self.vfs.read().0, id) } - pub(crate) fn file_line_endings(&self, id: FileId) -> LineEndings { - self.vfs.read().1[&id] + pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancelable { + let endings = self.vfs.read().1[&file_id]; + let index = self.analysis.file_line_index(file_id)?; + let res = LineIndex { index, endings }; + Ok(res) } pub(crate) fn url_file_version(&self, url: &Url) -> Option { diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 2d697c75f50..d8b00e9c582 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -5,12 +5,11 @@ use std::{ io::Write as _, process::{self, Stdio}, - sync::Arc, }; use ide::{ - AnnotationConfig, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, - Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit, + AnnotationConfig, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, Query, + RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit, }; use ide_db::SymbolKind; use itertools::Itertools; @@ -38,6 +37,7 @@ use crate::{ from_proto, global_state::{GlobalState, GlobalStateSnapshot}, line_endings::LineEndings, + line_endings::LineIndex, lsp_ext::{self, InlayHint, InlayHintsParams}, lsp_utils::all_edits_are_disjoint, to_proto, LspError, Result, @@ -100,7 +100,7 @@ pub(crate) fn handle_syntax_tree( ) -> Result { let _p = profile::span("handle_syntax_tree"); let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(id)?; + let line_index = snap.file_line_index(id)?; let text_range = params.range.map(|r| from_proto::text_range(&line_index, r)); let res = snap.analysis.syntax_tree(id, text_range)?; Ok(res) @@ -122,7 +122,7 @@ pub(crate) fn handle_expand_macro( ) -> Result> { let _p = profile::span("handle_expand_macro"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let offset = from_proto::offset(&line_index, params.position); let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?; @@ -135,7 +135,7 @@ pub(crate) fn handle_selection_range( ) -> Result>> { let _p = profile::span("handle_selection_range"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let res: Result> = params .positions .into_iter() @@ -178,7 +178,7 @@ pub(crate) fn handle_matching_brace( ) -> Result> { let _p = profile::span("handle_matching_brace"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let res = params .positions .into_iter() @@ -200,8 +200,7 @@ pub(crate) fn handle_join_lines( ) -> Result> { let _p = profile::span("handle_join_lines"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; - let line_endings = snap.file_line_endings(file_id); + let line_index = snap.file_line_index(file_id)?; let mut res = TextEdit::default(); for range in params.ranges { let range = from_proto::text_range(&line_index, range); @@ -213,7 +212,7 @@ pub(crate) fn handle_join_lines( } } } - let res = to_proto::text_edit_vec(&line_index, line_endings, res); + let res = to_proto::text_edit_vec(&line_index, res); Ok(res) } @@ -227,9 +226,8 @@ pub(crate) fn handle_on_enter( None => return Ok(None), Some(it) => it, }; - let line_index = snap.analysis.file_line_index(position.file_id)?; - let line_endings = snap.file_line_endings(position.file_id); - let edit = to_proto::snippet_text_edit_vec(&line_index, line_endings, true, edit); + let line_index = snap.file_line_index(position.file_id)?; + let edit = to_proto::snippet_text_edit_vec(&line_index, true, edit); Ok(Some(edit)) } @@ -240,8 +238,7 @@ pub(crate) fn handle_on_type_formatting( ) -> Result>> { let _p = profile::span("handle_on_type_formatting"); let mut position = from_proto::file_position(&snap, params.text_document_position)?; - let line_index = snap.analysis.file_line_index(position.file_id)?; - let line_endings = snap.file_line_endings(position.file_id); + let line_index = snap.file_line_index(position.file_id)?; // in `ide`, the `on_type` invariant is that // `text.char_at(position) == typed_char`. @@ -269,7 +266,7 @@ pub(crate) fn handle_on_type_formatting( // This should be a single-file edit let (_, edit) = edit.source_file_edits.into_iter().next().unwrap(); - let change = to_proto::text_edit_vec(&line_index, line_endings, edit); + let change = to_proto::text_edit_vec(&line_index, edit); Ok(Some(change)) } @@ -279,7 +276,7 @@ pub(crate) fn handle_document_symbol( ) -> Result> { let _p = profile::span("handle_document_symbol"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let mut parents: Vec<(lsp_types::DocumentSymbol, Option)> = Vec::new(); @@ -535,7 +532,7 @@ pub(crate) fn handle_runnables( ) -> Result> { let _p = profile::span("handle_runnables"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let offset = params.position.map(|it| from_proto::offset(&line_index, it)); let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; @@ -645,14 +642,12 @@ pub(crate) fn handle_completion( None => return Ok(None), Some(items) => items, }; - let line_index = snap.analysis.file_line_index(position.file_id)?; - let line_endings = snap.file_line_endings(position.file_id); + let line_index = snap.file_line_index(position.file_id)?; let items: Vec = items .into_iter() .flat_map(|item| { - let mut new_completion_items = - to_proto::completion_item(&line_index, line_endings, item.clone()); + let mut new_completion_items = to_proto::completion_item(&line_index, item.clone()); if completion_config.enable_imports_on_the_fly { for new_item in &mut new_completion_items { @@ -693,8 +688,7 @@ pub(crate) fn handle_completion_resolve( }; let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; - let line_endings = snap.file_line_endings(file_id); + let line_index = snap.file_line_index(file_id)?; let offset = from_proto::offset(&line_index, resolve_data.position.position); let additional_edits = snap @@ -707,9 +701,7 @@ pub(crate) fn handle_completion_resolve( resolve_data.import_for_trait_assoc_item, )? .into_iter() - .flat_map(|edit| { - edit.into_iter().map(|indel| to_proto::text_edit(&line_index, line_endings, indel)) - }) + .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) .collect_vec(); if !all_edits_are_disjoint(&original_completion, &additional_edits) { @@ -738,7 +730,7 @@ pub(crate) fn handle_folding_range( let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let folds = snap.analysis.folding_ranges(file_id)?; let text = snap.analysis.file_text(file_id)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let line_folding_only = snap.config.line_folding_only(); let res = folds .into_iter() @@ -775,7 +767,7 @@ pub(crate) fn handle_hover( None => return Ok(None), Some(info) => info, }; - let line_index = snap.analysis.file_line_index(position.file_id)?; + let line_index = snap.file_line_index(position.file_id)?; let range = to_proto::range(&line_index, info.range); let hover = lsp_ext::Hover { hover: lsp_types::Hover { @@ -797,7 +789,7 @@ pub(crate) fn handle_prepare_rename( let change = snap.analysis.prepare_rename(position)?.map_err(to_proto::rename_error)?; - let line_index = snap.analysis.file_line_index(position.file_id)?; + let line_index = snap.file_line_index(position.file_id)?; let range = to_proto::range(&line_index, change.range); Ok(Some(PrepareRenameResponse::Range(range))) } @@ -857,8 +849,7 @@ pub(crate) fn handle_formatting( let file = snap.analysis.file_text(file_id)?; let crate_ids = snap.analysis.crate_for(file_id)?; - let file_line_index = snap.analysis.file_line_index(file_id)?; - let file_line_endings = snap.file_line_endings(file_id); + let line_index = snap.file_line_index(file_id)?; let mut rustfmt = match snap.config.rustfmt() { RustfmtConfig::Rustfmt { extra_args } => { @@ -935,24 +926,19 @@ pub(crate) fn handle_formatting( let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout); - if file_line_endings != new_line_endings { + if line_index.endings != new_line_endings { // If line endings are different, send the entire file. // Diffing would not work here, as the line endings might be the only // difference. Ok(Some(to_proto::text_edit_vec( - &file_line_index, - new_line_endings, + &line_index, TextEdit::replace(TextRange::up_to(TextSize::of(&*file)), new_text), ))) } else if *file == new_text { // The document is already formatted correctly -- no edits needed. Ok(None) } else { - Ok(Some(to_proto::text_edit_vec( - &file_line_index, - file_line_endings, - diff(&file, &new_text), - ))) + Ok(Some(to_proto::text_edit_vec(&line_index, diff(&file, &new_text)))) } } @@ -969,7 +955,7 @@ pub(crate) fn handle_code_action( } let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let range = from_proto::text_range(&line_index, params.range); let frange = FileRange { file_id, range }; @@ -1010,7 +996,7 @@ pub(crate) fn handle_code_action( fn add_quick_fixes( snap: &GlobalStateSnapshot, frange: FileRange, - line_index: &Arc, + line_index: &LineIndex, acc: &mut Vec, ) -> Result<()> { let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics(), frange.file_id)?; @@ -1052,7 +1038,7 @@ pub(crate) fn handle_code_action_resolve( }; let file_id = from_proto::file_id(&snap, ¶ms.code_action_params.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let range = from_proto::text_range(&line_index, params.code_action_params.range); let frange = FileRange { file_id, range }; @@ -1131,7 +1117,7 @@ pub(crate) fn handle_document_highlight( ) -> Result>> { let _p = profile::span("handle_document_highlight"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; - let line_index = snap.analysis.file_line_index(position.file_id)?; + let line_index = snap.file_line_index(position.file_id)?; let refs = match snap .analysis @@ -1192,7 +1178,7 @@ pub(crate) fn publish_diagnostics( file_id: FileId, ) -> Result> { let _p = profile::span("publish_diagnostics"); - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let diagnostics: Vec = snap .analysis @@ -1226,7 +1212,7 @@ pub(crate) fn handle_inlay_hints( ) -> Result> { let _p = profile::span("handle_inlay_hints"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; Ok(snap .analysis .inlay_hints(file_id, &snap.config.inlay_hints())? @@ -1277,7 +1263,7 @@ pub(crate) fn handle_call_hierarchy_incoming( for call_item in call_items.into_iter() { let file_id = call_item.target.file_id; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; res.push(CallHierarchyIncomingCall { from: item, @@ -1312,7 +1298,7 @@ pub(crate) fn handle_call_hierarchy_outgoing( for call_item in call_items.into_iter() { let file_id = call_item.target.file_id; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; res.push(CallHierarchyOutgoingCall { to: item, @@ -1335,7 +1321,7 @@ pub(crate) fn handle_semantic_tokens_full( let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let text = snap.analysis.file_text(file_id)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let highlights = snap.analysis.highlight(file_id)?; let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); @@ -1354,7 +1340,7 @@ pub(crate) fn handle_semantic_tokens_full_delta( let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let text = snap.analysis.file_text(file_id)?; - let line_index = snap.analysis.file_line_index(file_id)?; + let line_index = snap.file_line_index(file_id)?; let highlights = snap.analysis.highlight(file_id)?; @@ -1384,7 +1370,7 @@ pub(crate) fn handle_semantic_tokens_range( let frange = from_proto::file_range(&snap, params.text_document, params.range)?; let text = snap.analysis.file_text(frange.file_id)?; - let line_index = snap.analysis.file_line_index(frange.file_id)?; + let line_index = snap.file_line_index(frange.file_id)?; let highlights = snap.analysis.highlight_range(frange)?; let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); @@ -1432,7 +1418,7 @@ fn show_impl_command_link( if snap.config.hover().implementations { if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { let uri = to_proto::url(snap, position.file_id); - let line_index = snap.analysis.file_line_index(position.file_id).ok()?; + let line_index = snap.file_line_index(position.file_id).ok()?; let position = to_proto::position(&line_index, position.offset); let locations: Vec<_> = nav_data .info diff --git a/crates/rust-analyzer/src/line_endings.rs b/crates/rust-analyzer/src/line_endings.rs index bf0e255d9d9..cc152c529d1 100644 --- a/crates/rust-analyzer/src/line_endings.rs +++ b/crates/rust-analyzer/src/line_endings.rs @@ -2,6 +2,13 @@ //! This module does line ending conversion and detection (so that we can //! convert back to `\r\n` on the way out). +use std::sync::Arc; + +pub(crate) struct LineIndex { + pub(crate) index: Arc, + pub(crate) endings: LineEndings, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) enum LineEndings { Unix, diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 2d06fe538d7..25162185e04 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -1,11 +1,14 @@ //! Utilities for LSP-related boilerplate code. -use std::{error::Error, ops::Range}; +use std::{error::Error, ops::Range, sync::Arc}; -use ide::LineIndex; use ide_db::base_db::Canceled; use lsp_server::Notification; -use crate::{from_proto, global_state::GlobalState}; +use crate::{ + from_proto, + global_state::GlobalState, + line_endings::{LineEndings, LineIndex}, +}; pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool { e.downcast_ref::().is_some() @@ -90,7 +93,12 @@ pub(crate) fn apply_document_changes( old_text: &mut String, content_changes: Vec, ) { - let mut line_index = LineIndex::new(old_text); + let mut line_index = LineIndex { + index: Arc::new(ide::LineIndex::new(old_text)), + // We don't care about line endings here. + endings: LineEndings::Unix, + }; + // The changes we got must be applied sequentially, but can cross lines so we // have to keep our line index updated. // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we @@ -115,7 +123,7 @@ pub(crate) fn apply_document_changes( match change.range { Some(range) => { if !index_valid.covers(range.end.line) { - line_index = LineIndex::new(&old_text); + line_index.index = Arc::new(ide::LineIndex::new(&old_text)); } index_valid = IndexValid::UpToLineExclusive(range.start.line); 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 ec5e8aa73c3..43e29ef04ef 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -7,22 +7,23 @@ use std::{ use ide::{ Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, - HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, - NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity, SourceChange, TextEdit, - TextRange, TextSize, + HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, Markup, NavigationTarget, + ReferenceAccess, RenameError, Runnable, Severity, SourceChange, TextEdit, TextRange, TextSize, }; use ide_db::SymbolKind; use itertools::Itertools; use serde_json::to_value; use crate::{ - cargo_target_spec::CargoTargetSpec, global_state::GlobalStateSnapshot, - line_endings::LineEndings, lsp_ext, semantic_tokens, Result, + cargo_target_spec::CargoTargetSpec, + global_state::GlobalStateSnapshot, + line_endings::{LineEndings, LineIndex}, + lsp_ext, semantic_tokens, Result, }; pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { - let line_col = line_index.line_col(offset); - let line_col = line_index.to_utf16(line_col); + let line_col = line_index.index.line_col(offset); + let line_col = line_index.index.to_utf16(line_col); lsp_types::Position::new(line_col.line, line_col.col) } @@ -123,13 +124,9 @@ pub(crate) fn completion_item_kind( } } -pub(crate) fn text_edit( - line_index: &LineIndex, - line_endings: LineEndings, - indel: Indel, -) -> lsp_types::TextEdit { +pub(crate) fn text_edit(line_index: &LineIndex, indel: Indel) -> lsp_types::TextEdit { let range = range(line_index, indel.delete); - let new_text = match line_endings { + let new_text = match line_index.endings { LineEndings::Unix => indel.insert, LineEndings::Dos => indel.insert.replace('\n', "\r\n"), }; @@ -138,11 +135,10 @@ pub(crate) fn text_edit( pub(crate) fn snippet_text_edit( line_index: &LineIndex, - line_endings: LineEndings, is_snippet: bool, indel: Indel, ) -> lsp_ext::SnippetTextEdit { - let text_edit = text_edit(line_index, line_endings, indel); + let text_edit = text_edit(line_index, indel); let insert_text_format = if is_snippet { Some(lsp_types::InsertTextFormat::Snippet) } else { None }; lsp_ext::SnippetTextEdit { @@ -154,27 +150,24 @@ pub(crate) fn snippet_text_edit( pub(crate) fn text_edit_vec( line_index: &LineIndex, - line_endings: LineEndings, text_edit: TextEdit, ) -> Vec { - text_edit.into_iter().map(|indel| self::text_edit(line_index, line_endings, indel)).collect() + text_edit.into_iter().map(|indel| self::text_edit(line_index, indel)).collect() } pub(crate) fn snippet_text_edit_vec( line_index: &LineIndex, - line_endings: LineEndings, is_snippet: bool, text_edit: TextEdit, ) -> Vec { text_edit .into_iter() - .map(|indel| self::snippet_text_edit(line_index, line_endings, is_snippet, indel)) + .map(|indel| self::snippet_text_edit(line_index, is_snippet, indel)) .collect() } pub(crate) fn completion_item( line_index: &LineIndex, - line_endings: LineEndings, completion_item: CompletionItem, ) -> Vec { fn set_score(res: &mut lsp_types::CompletionItem, label: &str) { @@ -191,19 +184,19 @@ pub(crate) fn completion_item( for indel in completion_item.text_edit().iter() { if indel.delete.contains_range(source_range) { text_edit = Some(if indel.delete == source_range { - self::text_edit(line_index, line_endings, indel.clone()) + self::text_edit(line_index, indel.clone()) } else { assert!(source_range.end() == indel.delete.end()); let range1 = TextRange::new(indel.delete.start(), source_range.start()); let range2 = source_range; let indel1 = Indel::replace(range1, String::new()); let indel2 = Indel::replace(range2, indel.insert.clone()); - additional_text_edits.push(self::text_edit(line_index, line_endings, indel1)); - self::text_edit(line_index, line_endings, indel2) + additional_text_edits.push(self::text_edit(line_index, indel1)); + self::text_edit(line_index, indel2) }) } else { assert!(source_range.intersect(indel.delete).is_none()); - let text_edit = self::text_edit(line_index, line_endings, indel.clone()); + let text_edit = self::text_edit(line_index, indel.clone()); additional_text_edits.push(text_edit); } } @@ -359,7 +352,7 @@ pub(crate) fn semantic_tokens( let token_index = semantic_tokens::type_index(type_); let modifier_bitset = mods.0; - for mut text_range in line_index.lines(highlight_range.range) { + for mut text_range in line_index.index.lines(highlight_range.range) { if text[text_range].ends_with('\n') { text_range = TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n')); @@ -566,7 +559,7 @@ pub(crate) fn location( frange: FileRange, ) -> Result { let url = url(snap, frange.file_id); - let line_index = snap.analysis.file_line_index(frange.file_id)?; + let line_index = snap.file_line_index(frange.file_id)?; let range = range(&line_index, frange.range); let loc = lsp_types::Location::new(url, range); Ok(loc) @@ -578,7 +571,7 @@ pub(crate) fn location_from_nav( nav: NavigationTarget, ) -> Result { let url = url(snap, nav.file_id); - let line_index = snap.analysis.file_line_index(nav.file_id)?; + let line_index = snap.file_line_index(nav.file_id)?; let range = range(&line_index, nav.full_range); let loc = lsp_types::Location::new(url, range); Ok(loc) @@ -591,7 +584,7 @@ pub(crate) fn location_link( ) -> Result { let origin_selection_range = match src { Some(src) => { - let line_index = snap.analysis.file_line_index(src.file_id)?; + let line_index = snap.file_line_index(src.file_id)?; let range = range(&line_index, src.range); Some(range) } @@ -611,7 +604,7 @@ fn location_info( snap: &GlobalStateSnapshot, target: NavigationTarget, ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { - let line_index = snap.analysis.file_line_index(target.file_id)?; + let line_index = snap.file_line_index(target.file_id)?; let target_uri = url(snap, target.file_id); let target_range = range(&line_index, target.full_range); @@ -649,12 +642,8 @@ pub(crate) fn snippet_text_document_edit( edit: TextEdit, ) -> Result { let text_document = optional_versioned_text_document_identifier(snap, file_id); - let line_index = snap.analysis.file_line_index(file_id)?; - let line_endings = snap.file_line_endings(file_id); - let edits = edit - .into_iter() - .map(|it| snippet_text_edit(&line_index, line_endings, is_snippet, it)) - .collect(); + let line_index = snap.file_line_index(file_id)?; + let edits = edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect(); Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) } @@ -675,9 +664,8 @@ pub(crate) fn snippet_text_document_ops( if !initial_contents.is_empty() { let text_document = lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; - let range = range(&LineIndex::new(""), TextRange::empty(TextSize::from(0))); let text_edit = lsp_ext::SnippetTextEdit { - range, + range: lsp_types::Range::default(), new_text: initial_contents, insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), }; @@ -868,7 +856,7 @@ pub(crate) fn code_lens( ) -> Result { match annotation.kind { AnnotationKind::Runnable { debug, runnable: run } => { - let line_index = snap.analysis.file_line_index(run.nav.file_id)?; + let line_index = snap.file_line_index(run.nav.file_id)?; let annotation_range = range(&line_index, annotation.range); let action = run.action(); @@ -884,7 +872,7 @@ pub(crate) fn code_lens( Ok(lsp_types::CodeLens { range: annotation_range, command: Some(command), data: None }) } AnnotationKind::HasImpls { position: file_position, data } => { - let line_index = snap.analysis.file_line_index(file_position.file_id)?; + let line_index = snap.file_line_index(file_position.file_id)?; let annotation_range = range(&line_index, annotation.range); let url = url(snap, file_position.file_id); @@ -927,7 +915,7 @@ pub(crate) fn code_lens( }) } AnnotationKind::HasReferences { position: file_position, data } => { - let line_index = snap.analysis.file_line_index(file_position.file_id)?; + let line_index = snap.file_line_index(file_position.file_id)?; let annotation_range = range(&line_index, annotation.range); let url = url(snap, file_position.file_id); @@ -1061,6 +1049,8 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { #[cfg(test)] mod tests { + use std::sync::Arc; + use hir::PrefixKind; use ide::Analysis; use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; @@ -1078,7 +1068,8 @@ mod tests { }"#; let (offset, text) = test_utils::extract_offset(fixture); - let line_index = LineIndex::new(&text); + let line_index = + LineIndex { index: Arc::new(ide::LineIndex::new(&text)), endings: LineEndings::Unix }; let (analysis, file_id) = Analysis::from_single_file(text); let completions: Vec<(String, Option)> = analysis .completions( @@ -1096,7 +1087,7 @@ mod tests { .unwrap() .into_iter() .filter(|c| c.label().ends_with("arg")) - .map(|c| completion_item(&line_index, LineEndings::Unix, c)) + .map(|c| completion_item(&line_index, c)) .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text))) .collect(); expect_test::expect![[r#" @@ -1134,7 +1125,8 @@ fn main() { let folds = analysis.folding_ranges(file_id).unwrap(); assert_eq!(folds.len(), 4); - let line_index = LineIndex::new(&text); + let line_index = + LineIndex { index: Arc::new(ide::LineIndex::new(&text)), endings: LineEndings::Unix }; let converted: Vec = folds.into_iter().map(|it| folding_range(&text, &line_index, true, it)).collect();