From 2cb4ac9eb4cb02e7d14ec50a9e7d8e9fe49a4ec1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 12 Feb 2021 21:24:10 +0300 Subject: Prepare for utf-8 offsets --- crates/ide/src/lib.rs | 2 +- crates/ide_db/src/line_index.rs | 12 +++++------ crates/ide_db/src/line_index/tests.rs | 28 +++++++++++++------------- crates/rust-analyzer/src/cli/analysis_bench.rs | 4 ++-- crates/rust-analyzer/src/cli/analysis_stats.rs | 8 ++++---- crates/rust-analyzer/src/from_proto.rs | 4 ++-- crates/rust-analyzer/src/to_proto.rs | 2 +- 7 files changed, 30 insertions(+), 30 deletions(-) (limited to 'crates') diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 89e7bef7d..68756f78a 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -95,7 +95,7 @@ pub use ide_db::{ }, call_info::CallInfo, label::Label, - line_index::{LineCol, LineIndex}, + line_index::{LineColUtf16, LineIndex}, search::{ReferenceAccess, SearchScope}, source_change::{FileSystemEdit, SourceChange}, symbol_index::Query, diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs index 41226305e..490c172e3 100644 --- a/crates/ide_db/src/line_index.rs +++ b/crates/ide_db/src/line_index.rs @@ -15,11 +15,11 @@ pub struct LineIndex { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct LineCol { +pub struct LineColUtf16 { /// Zero-based pub line: u32, /// Zero-based - pub col_utf16: u32, + pub col: u32, } #[derive(Clone, Debug, Hash, PartialEq, Eq)] @@ -88,17 +88,17 @@ impl LineIndex { LineIndex { newlines, utf16_lines } } - pub fn line_col(&self, offset: TextSize) -> LineCol { + pub fn line_col(&self, offset: TextSize) -> LineColUtf16 { let line = partition_point(&self.newlines, |&it| it <= offset) - 1; let line_start_offset = self.newlines[line]; let col = offset - line_start_offset; - LineCol { line: line as u32, col_utf16: self.utf8_to_utf16_col(line as u32, col) as u32 } + LineColUtf16 { line: line as u32, col: self.utf8_to_utf16_col(line as u32, col) as u32 } } - pub fn offset(&self, line_col: LineCol) -> TextSize { + pub fn offset(&self, line_col: LineColUtf16) -> TextSize { //FIXME: return Result - let col = self.utf16_to_utf8_col(line_col.line, line_col.col_utf16); + let col = self.utf16_to_utf8_col(line_col.line, line_col.col); self.newlines[line_col.line as usize] + col } diff --git a/crates/ide_db/src/line_index/tests.rs b/crates/ide_db/src/line_index/tests.rs index 05f7484e8..1a109654e 100644 --- a/crates/ide_db/src/line_index/tests.rs +++ b/crates/ide_db/src/line_index/tests.rs @@ -4,23 +4,23 @@ use super::*; fn test_line_index() { let text = "hello\nworld"; let index = LineIndex::new(text); - assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 }); - assert_eq!(index.line_col(1.into()), LineCol { line: 0, col_utf16: 1 }); - assert_eq!(index.line_col(5.into()), LineCol { line: 0, col_utf16: 5 }); - assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 0 }); - assert_eq!(index.line_col(7.into()), LineCol { line: 1, col_utf16: 1 }); - assert_eq!(index.line_col(8.into()), LineCol { line: 1, col_utf16: 2 }); - assert_eq!(index.line_col(10.into()), LineCol { line: 1, col_utf16: 4 }); - assert_eq!(index.line_col(11.into()), LineCol { line: 1, col_utf16: 5 }); - assert_eq!(index.line_col(12.into()), LineCol { line: 1, col_utf16: 6 }); + assert_eq!(index.line_col(0.into()), LineColUtf16 { line: 0, col: 0 }); + assert_eq!(index.line_col(1.into()), LineColUtf16 { line: 0, col: 1 }); + assert_eq!(index.line_col(5.into()), LineColUtf16 { line: 0, col: 5 }); + assert_eq!(index.line_col(6.into()), LineColUtf16 { line: 1, col: 0 }); + assert_eq!(index.line_col(7.into()), LineColUtf16 { line: 1, col: 1 }); + assert_eq!(index.line_col(8.into()), LineColUtf16 { line: 1, col: 2 }); + assert_eq!(index.line_col(10.into()), LineColUtf16 { line: 1, col: 4 }); + assert_eq!(index.line_col(11.into()), LineColUtf16 { line: 1, col: 5 }); + assert_eq!(index.line_col(12.into()), LineColUtf16 { line: 1, col: 6 }); let text = "\nhello\nworld"; let index = LineIndex::new(text); - assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 }); - assert_eq!(index.line_col(1.into()), LineCol { line: 1, col_utf16: 0 }); - assert_eq!(index.line_col(2.into()), LineCol { line: 1, col_utf16: 1 }); - assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 5 }); - assert_eq!(index.line_col(7.into()), LineCol { line: 2, col_utf16: 0 }); + assert_eq!(index.line_col(0.into()), LineColUtf16 { line: 0, col: 0 }); + assert_eq!(index.line_col(1.into()), LineColUtf16 { line: 1, col: 0 }); + assert_eq!(index.line_col(2.into()), LineColUtf16 { line: 1, col: 1 }); + assert_eq!(index.line_col(6.into()), LineColUtf16 { line: 1, col: 5 }); + assert_eq!(index.line_col(7.into()), LineColUtf16 { line: 2, col: 0 }); } #[test] diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index 6735b6388..edf12faa4 100644 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ b/crates/rust-analyzer/src/cli/analysis_bench.rs @@ -5,7 +5,7 @@ use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; use anyhow::{bail, format_err, Result}; use hir::PrefixKind; use ide::{ - Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, + Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineColUtf16, }; use ide_db::{ base_db::{ @@ -97,7 +97,7 @@ impl BenchCmd { let offset = host .analysis() .file_line_index(file_id)? - .offset(LineCol { line: pos.line - 1, col_utf16: pos.column }); + .offset(LineColUtf16 { line: pos.line - 1, col: pos.column }); let file_position = FilePosition { file_id, offset }; if is_completion { diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 3417af687..6d6f398f4 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -218,9 +218,9 @@ impl AnalysisStatsCmd { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, - start.col_utf16, + start.col, end.line + 1, - end.col_utf16, + end.col, ty.display(db) )); } else { @@ -250,9 +250,9 @@ impl AnalysisStatsCmd { "{} {}:{}-{}:{}: Expected {}, got {}", path, start.line + 1, - start.col_utf16, + start.col, end.line + 1, - end.col_utf16, + end.col, mismatch.expected.display(db), mismatch.actual.display(db) )); diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 6676eebf4..82e7cfa81 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -1,7 +1,7 @@ //! Conversion lsp_types types to rust-analyzer specific ones. use std::convert::TryFrom; -use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineIndex}; +use ide::{Annotation, AnnotationKind, AssistKind, LineColUtf16, LineIndex}; use ide_db::base_db::{FileId, FilePosition, FileRange}; use syntax::{TextRange, TextSize}; use vfs::AbsPathBuf; @@ -18,7 +18,7 @@ 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 = LineCol { line: position.line as u32, col_utf16: position.character as u32 }; + let line_col = LineColUtf16 { line: position.line as u32, col: position.character as u32 }; line_index.offset(line_col) } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 8a2b4d9bd..599b5207c 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -22,7 +22,7 @@ use crate::{ pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { let line_col = line_index.line_col(offset); - lsp_types::Position::new(line_col.line, line_col.col_utf16) + lsp_types::Position::new(line_col.line, line_col.col) } pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range { -- cgit v1.2.3 From 00cc778c8c62e8f68531c1cadcce8b05b7287d84 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 12 Feb 2021 21:31:32 +0300 Subject: reduce code duplication in tests --- crates/ide_db/src/line_index/tests.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ide_db/src/line_index/tests.rs b/crates/ide_db/src/line_index/tests.rs index 1a109654e..af51d7348 100644 --- a/crates/ide_db/src/line_index/tests.rs +++ b/crates/ide_db/src/line_index/tests.rs @@ -3,24 +3,29 @@ use super::*; #[test] fn test_line_index() { let text = "hello\nworld"; + let table = [ + (00, 0, 0), + (01, 0, 1), + (05, 0, 5), + (06, 1, 0), + (07, 1, 1), + (08, 1, 2), + (10, 1, 4), + (11, 1, 5), + (12, 1, 6), + ]; + let index = LineIndex::new(text); - assert_eq!(index.line_col(0.into()), LineColUtf16 { line: 0, col: 0 }); - assert_eq!(index.line_col(1.into()), LineColUtf16 { line: 0, col: 1 }); - assert_eq!(index.line_col(5.into()), LineColUtf16 { line: 0, col: 5 }); - assert_eq!(index.line_col(6.into()), LineColUtf16 { line: 1, col: 0 }); - assert_eq!(index.line_col(7.into()), LineColUtf16 { line: 1, col: 1 }); - assert_eq!(index.line_col(8.into()), LineColUtf16 { line: 1, col: 2 }); - assert_eq!(index.line_col(10.into()), LineColUtf16 { line: 1, col: 4 }); - assert_eq!(index.line_col(11.into()), LineColUtf16 { line: 1, col: 5 }); - assert_eq!(index.line_col(12.into()), LineColUtf16 { line: 1, col: 6 }); + for &(offset, line, col) in &table { + assert_eq!(index.line_col(offset.into()), LineColUtf16 { line, col }); + } let text = "\nhello\nworld"; + let table = [(0, 0, 0), (1, 1, 0), (2, 1, 1), (6, 1, 5), (7, 2, 0)]; let index = LineIndex::new(text); - assert_eq!(index.line_col(0.into()), LineColUtf16 { line: 0, col: 0 }); - assert_eq!(index.line_col(1.into()), LineColUtf16 { line: 1, col: 0 }); - assert_eq!(index.line_col(2.into()), LineColUtf16 { line: 1, col: 1 }); - assert_eq!(index.line_col(6.into()), LineColUtf16 { line: 1, col: 5 }); - assert_eq!(index.line_col(7.into()), LineColUtf16 { line: 2, col: 0 }); + for &(offset, line, col) in &table { + assert_eq!(index.line_col(offset.into()), LineColUtf16 { line, col }); + } } #[test] -- cgit v1.2.3 From 95209aa3f8e4b149da6adb374611ece76c2b82ca Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 12 Feb 2021 22:09:53 +0300 Subject: Make utf8 default, implement utf16 in terms of it --- crates/ide/src/lib.rs | 2 +- crates/ide_db/src/line_index.rs | 25 ++++++++++++++++++++----- crates/ide_db/src/line_index/tests.rs | 4 ++-- crates/rust-analyzer/src/cli/analysis_bench.rs | 4 ++-- crates/rust-analyzer/src/from_proto.rs | 1 + crates/rust-analyzer/src/to_proto.rs | 1 + 6 files changed, 27 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 68756f78a..a2c8db505 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -95,7 +95,7 @@ pub use ide_db::{ }, call_info::CallInfo, label::Label, - line_index::{LineColUtf16, LineIndex}, + line_index::{LineCol, LineColUtf16, LineIndex}, search::{ReferenceAccess, SearchScope}, source_change::{FileSystemEdit, SourceChange}, symbol_index::Query, diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs index 490c172e3..8e9d8cca2 100644 --- a/crates/ide_db/src/line_index.rs +++ b/crates/ide_db/src/line_index.rs @@ -22,6 +22,14 @@ pub struct LineColUtf16 { pub col: u32, } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct LineCol { + /// Zero-based + pub line: u32, + /// Zero-based utf8 offset + pub col: u32, +} + #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub(crate) struct Utf16Char { /// Start offset of a character inside a line, zero-based @@ -88,18 +96,25 @@ impl LineIndex { LineIndex { newlines, utf16_lines } } - pub fn line_col(&self, offset: TextSize) -> LineColUtf16 { + pub fn line_col(&self, offset: TextSize) -> LineCol { let line = partition_point(&self.newlines, |&it| it <= offset) - 1; let line_start_offset = self.newlines[line]; let col = offset - line_start_offset; + LineCol { line: line as u32, col: col.into() } + } + + pub fn offset(&self, line_col: LineCol) -> TextSize { + self.newlines[line_col.line as usize] + TextSize::from(line_col.col) + } - LineColUtf16 { line: line as u32, col: self.utf8_to_utf16_col(line as u32, col) as u32 } + pub fn to_utf16(&self, line_col: LineCol) -> LineColUtf16 { + let col = self.utf8_to_utf16_col(line_col.line, line_col.col.into()); + LineColUtf16 { line: line_col.line, col: col as u32 } } - pub fn offset(&self, line_col: LineColUtf16) -> TextSize { - //FIXME: return Result + pub fn to_utf8(&self, line_col: LineColUtf16) -> LineCol { let col = self.utf16_to_utf8_col(line_col.line, line_col.col); - self.newlines[line_col.line as usize] + col + LineCol { line: line_col.line, col: col.into() } } pub fn lines(&self, range: TextRange) -> impl Iterator + '_ { diff --git a/crates/ide_db/src/line_index/tests.rs b/crates/ide_db/src/line_index/tests.rs index af51d7348..09f3bca62 100644 --- a/crates/ide_db/src/line_index/tests.rs +++ b/crates/ide_db/src/line_index/tests.rs @@ -17,14 +17,14 @@ fn test_line_index() { let index = LineIndex::new(text); for &(offset, line, col) in &table { - assert_eq!(index.line_col(offset.into()), LineColUtf16 { line, col }); + assert_eq!(index.line_col(offset.into()), LineCol { line, col }); } let text = "\nhello\nworld"; let table = [(0, 0, 0), (1, 1, 0), (2, 1, 1), (6, 1, 5), (7, 2, 0)]; let index = LineIndex::new(text); for &(offset, line, col) in &table { - assert_eq!(index.line_col(offset.into()), LineColUtf16 { line, col }); + assert_eq!(index.line_col(offset.into()), LineCol { line, col }); } } diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index edf12faa4..877abd12b 100644 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ b/crates/rust-analyzer/src/cli/analysis_bench.rs @@ -5,7 +5,7 @@ use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; use anyhow::{bail, format_err, Result}; use hir::PrefixKind; use ide::{ - Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineColUtf16, + Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, }; use ide_db::{ base_db::{ @@ -97,7 +97,7 @@ impl BenchCmd { let offset = host .analysis() .file_line_index(file_id)? - .offset(LineColUtf16 { line: pos.line - 1, col: pos.column }); + .offset(LineCol { line: pos.line - 1, col: pos.column }); let file_position = FilePosition { file_id, offset }; if is_completion { diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 82e7cfa81..de995412c 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -19,6 +19,7 @@ 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) } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 599b5207c..ec5e8aa73 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -22,6 +22,7 @@ use crate::{ 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); lsp_types::Position::new(line_col.line, line_col.col) } -- cgit v1.2.3 From 0025836f262ee410050ba79b6ea09d75f76449ac Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Feb 2021 00:44:28 +0300 Subject: Make it easy to add additional context for offset conversion --- crates/rust-analyzer/src/from_proto.rs | 20 +++---- crates/rust-analyzer/src/global_state.rs | 11 ++-- crates/rust-analyzer/src/handlers.rs | 90 ++++++++++++++------------------ crates/rust-analyzer/src/line_endings.rs | 7 +++ crates/rust-analyzer/src/lsp_utils.rs | 18 +++++-- crates/rust-analyzer/src/to_proto.rs | 78 +++++++++++++-------------- 6 files changed, 111 insertions(+), 113 deletions(-) (limited to 'crates') 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 @@ //! 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 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}; 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 2d697c75f..d8b00e9c5 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 bf0e255d9..cc152c529 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 2d06fe538..25162185e 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 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::{ 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(); -- cgit v1.2.3 From c8b9ec8e62d9f560a6557496bc4b579019ccb509 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Feb 2021 00:55:27 +0300 Subject: Implement utf8 offsets --- crates/rust-analyzer/src/from_proto.rs | 19 +++++++++++++++---- crates/rust-analyzer/src/global_state.rs | 4 ++-- crates/rust-analyzer/src/line_endings.rs | 7 +++++++ crates/rust-analyzer/src/lsp_utils.rs | 5 +++-- crates/rust-analyzer/src/to_proto.rs | 25 ++++++++++++++++++------- 5 files changed, 45 insertions(+), 15 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index c671b5f64..4f3ae8cc3 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -1,13 +1,16 @@ //! Conversion lsp_types types to rust-analyzer specific ones. use std::convert::TryFrom; -use ide::{Annotation, AnnotationKind, AssistKind, LineColUtf16}; +use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineColUtf16}; use ide_db::base_db::{FileId, FilePosition, FileRange}; use syntax::{TextRange, TextSize}; use vfs::AbsPathBuf; use crate::{ - from_json, global_state::GlobalStateSnapshot, line_endings::LineIndex, lsp_ext, Result, + from_json, + global_state::GlobalStateSnapshot, + line_endings::{LineIndex, OffsetEncoding}, + lsp_ext, Result, }; pub(crate) fn abs_path(url: &lsp_types::Url) -> Result { @@ -20,8 +23,16 @@ 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.index.to_utf8(line_col); + let line_col = match line_index.encoding { + OffsetEncoding::Utf8 => { + LineCol { line: position.line as u32, col: position.character as u32 } + } + OffsetEncoding::Utf16 => { + let line_col = + LineColUtf16 { line: position.line as u32, col: position.character as u32 }; + line_index.index.to_utf8(line_col) + } + }; line_index.index.offset(line_col) } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index ffef33430..d26e5ef48 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -22,7 +22,7 @@ use crate::{ diagnostics::{CheckFixes, DiagnosticCollection}, document::DocumentData, from_proto, - line_endings::{LineEndings, LineIndex}, + line_endings::{LineEndings, LineIndex, OffsetEncoding}, main_loop::Task, op_queue::OpQueue, reload::SourceRootConfig, @@ -274,7 +274,7 @@ impl GlobalStateSnapshot { 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 }; + let res = LineIndex { index, endings, encoding: OffsetEncoding::Utf16 }; Ok(res) } diff --git a/crates/rust-analyzer/src/line_endings.rs b/crates/rust-analyzer/src/line_endings.rs index cc152c529..7b6cba43e 100644 --- a/crates/rust-analyzer/src/line_endings.rs +++ b/crates/rust-analyzer/src/line_endings.rs @@ -4,9 +4,16 @@ use std::sync::Arc; +pub(crate) enum OffsetEncoding { + #[allow(unused)] + Utf8, + Utf16, +} + pub(crate) struct LineIndex { pub(crate) index: Arc, pub(crate) endings: LineEndings, + pub(crate) encoding: OffsetEncoding, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 25162185e..6b8e347b9 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -7,7 +7,7 @@ use lsp_server::Notification; use crate::{ from_proto, global_state::GlobalState, - line_endings::{LineEndings, LineIndex}, + line_endings::{LineEndings, LineIndex, OffsetEncoding}, }; pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool { @@ -95,8 +95,9 @@ pub(crate) fn apply_document_changes( ) { let mut line_index = LineIndex { index: Arc::new(ide::LineIndex::new(old_text)), - // We don't care about line endings here. + // We don't care about line endings or offset encoding here. endings: LineEndings::Unix, + encoding: OffsetEncoding::Utf16, }; // The changes we got must be applied sequentially, but can cross lines so we diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 43e29ef04..368d916e7 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -17,14 +17,19 @@ use serde_json::to_value; use crate::{ cargo_target_spec::CargoTargetSpec, global_state::GlobalStateSnapshot, - line_endings::{LineEndings, LineIndex}, + line_endings::{LineEndings, LineIndex, OffsetEncoding}, lsp_ext, semantic_tokens, Result, }; pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { 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) + match line_index.encoding { + OffsetEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col), + OffsetEncoding::Utf16 => { + let line_col = line_index.index.to_utf16(line_col); + lsp_types::Position::new(line_col.line, line_col.col) + } + } } pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Range { @@ -1068,8 +1073,11 @@ mod tests { }"#; let (offset, text) = test_utils::extract_offset(fixture); - let line_index = - LineIndex { index: Arc::new(ide::LineIndex::new(&text)), endings: LineEndings::Unix }; + let line_index = LineIndex { + index: Arc::new(ide::LineIndex::new(&text)), + endings: LineEndings::Unix, + encoding: OffsetEncoding::Utf16, + }; let (analysis, file_id) = Analysis::from_single_file(text); let completions: Vec<(String, Option)> = analysis .completions( @@ -1125,8 +1133,11 @@ fn main() { let folds = analysis.folding_ranges(file_id).unwrap(); assert_eq!(folds.len(), 4); - let line_index = - LineIndex { index: Arc::new(ide::LineIndex::new(&text)), endings: LineEndings::Unix }; + let line_index = LineIndex { + index: Arc::new(ide::LineIndex::new(&text)), + endings: LineEndings::Unix, + encoding: OffsetEncoding::Utf16, + }; let converted: Vec = folds.into_iter().map(|it| folding_range(&text, &line_index, true, it)).collect(); -- cgit v1.2.3 From f3d56b89c54110aaafab14eeaa4c803abe10b7df Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Feb 2021 01:26:01 +0300 Subject: Enable offset-encoding capability --- crates/rust-analyzer/src/bin/main.rs | 8 ++++++-- crates/rust-analyzer/src/config.rs | 12 +++++++++++- crates/rust-analyzer/src/global_state.rs | 4 ++-- crates/rust-analyzer/src/line_endings.rs | 3 +-- crates/rust-analyzer/src/lsp_ext.rs | 4 ++++ 5 files changed, 24 insertions(+), 7 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 93d0ad4ec..89482b952 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -8,7 +8,7 @@ use std::{convert::TryFrom, env, fs, path::PathBuf, process}; use lsp_server::Connection; use project_model::ProjectManifest; -use rust_analyzer::{cli, config::Config, from_json, Result}; +use rust_analyzer::{cli, config::Config, from_json, lsp_ext::supports_utf8, Result}; use vfs::AbsPathBuf; #[cfg(all(feature = "mimalloc"))] @@ -127,7 +127,11 @@ fn run_server() -> Result<()> { name: String::from("rust-analyzer"), version: Some(String::from(env!("REV"))), }), - offset_encoding: None, + offset_encoding: if supports_utf8(&initialize_params.capabilities) { + Some("utf-8".to_string()) + } else { + None + }, }; let initialize_result = serde_json::to_value(initialize_result).unwrap(); diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index f9098968a..425ef145c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -23,7 +23,10 @@ use rustc_hash::FxHashSet; use serde::{de::DeserializeOwned, Deserialize}; use vfs::AbsPathBuf; -use crate::{caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig}; +use crate::{ + caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig, + line_endings::OffsetEncoding, lsp_ext::supports_utf8, +}; config_data! { struct ConfigData { @@ -415,6 +418,13 @@ impl Config { false ) } + pub fn offset_encoding(&self) -> OffsetEncoding { + if supports_utf8(&self.caps) { + OffsetEncoding::Utf8 + } else { + OffsetEncoding::Utf16 + } + } fn experimental(&self, index: &'static str) -> bool { try_or!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?, false) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index d26e5ef48..85c87645c 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -22,7 +22,7 @@ use crate::{ diagnostics::{CheckFixes, DiagnosticCollection}, document::DocumentData, from_proto, - line_endings::{LineEndings, LineIndex, OffsetEncoding}, + line_endings::{LineEndings, LineIndex}, main_loop::Task, op_queue::OpQueue, reload::SourceRootConfig, @@ -274,7 +274,7 @@ impl GlobalStateSnapshot { 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, encoding: OffsetEncoding::Utf16 }; + let res = LineIndex { index, endings, encoding: self.config.offset_encoding() }; Ok(res) } diff --git a/crates/rust-analyzer/src/line_endings.rs b/crates/rust-analyzer/src/line_endings.rs index 7b6cba43e..dd8901152 100644 --- a/crates/rust-analyzer/src/line_endings.rs +++ b/crates/rust-analyzer/src/line_endings.rs @@ -4,8 +4,7 @@ use std::sync::Arc; -pub(crate) enum OffsetEncoding { - #[allow(unused)] +pub enum OffsetEncoding { Utf8, Utf16, } diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index a1ad855c3..0d2c8f7ff 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -385,3 +385,7 @@ pub(crate) enum CodeLensResolveData { Impls(lsp_types::request::GotoImplementationParams), References(lsp_types::TextDocumentPositionParams), } + +pub fn supports_utf8(caps: &lsp_types::ClientCapabilities) -> bool { + caps.offset_encoding.as_deref().unwrap_or_default().iter().any(|it| it == "utf-8") +} -- cgit v1.2.3 From 1fcf687657c7029e7e36dc2cc17bdec7a391d63f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 13 Feb 2021 01:28:48 +0300 Subject: Fix bitrotted module name --- crates/rust-analyzer/src/config.rs | 2 +- crates/rust-analyzer/src/from_proto.rs | 2 +- crates/rust-analyzer/src/global_state.rs | 2 +- crates/rust-analyzer/src/handlers.rs | 3 +- crates/rust-analyzer/src/lib.rs | 2 +- crates/rust-analyzer/src/line_endings.rs | 65 ------------------------------ crates/rust-analyzer/src/line_index.rs | 68 ++++++++++++++++++++++++++++++++ crates/rust-analyzer/src/lsp_utils.rs | 2 +- crates/rust-analyzer/src/to_proto.rs | 2 +- 9 files changed, 75 insertions(+), 73 deletions(-) delete mode 100644 crates/rust-analyzer/src/line_endings.rs create mode 100644 crates/rust-analyzer/src/line_index.rs (limited to 'crates') diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 425ef145c..9c873c097 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -25,7 +25,7 @@ use vfs::AbsPathBuf; use crate::{ caps::completion_item_edit_resolve, diagnostics::DiagnosticsMapConfig, - line_endings::OffsetEncoding, lsp_ext::supports_utf8, + line_index::OffsetEncoding, lsp_ext::supports_utf8, }; config_data! { diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 4f3ae8cc3..5b02b2598 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -9,7 +9,7 @@ use vfs::AbsPathBuf; use crate::{ from_json, global_state::GlobalStateSnapshot, - line_endings::{LineIndex, OffsetEncoding}, + line_index::{LineIndex, OffsetEncoding}, lsp_ext, Result, }; diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 85c87645c..52c249713 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -22,7 +22,7 @@ use crate::{ diagnostics::{CheckFixes, DiagnosticCollection}, document::DocumentData, from_proto, - line_endings::{LineEndings, LineIndex}, + line_index::{LineEndings, LineIndex}, main_loop::Task, op_queue::OpQueue, reload::SourceRootConfig, diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index d8b00e9c5..4f6f250d6 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -36,8 +36,7 @@ use crate::{ diff::diff, from_proto, global_state::{GlobalState, GlobalStateSnapshot}, - line_endings::LineEndings, - line_endings::LineIndex, + line_index::{LineEndings, LineIndex}, lsp_ext::{self, InlayHint, InlayHintsParams}, lsp_utils::all_edits_are_disjoint, to_proto, LspError, Result, diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 2207b9a87..8b874239c 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -29,7 +29,7 @@ mod from_proto; mod semantic_tokens; mod markdown; mod diagnostics; -mod line_endings; +mod line_index; mod request_metrics; mod lsp_utils; mod thread_pool; diff --git a/crates/rust-analyzer/src/line_endings.rs b/crates/rust-analyzer/src/line_endings.rs deleted file mode 100644 index dd8901152..000000000 --- a/crates/rust-analyzer/src/line_endings.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! We maintain invariant that all internal strings use `\n` as line separator. -//! 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 enum OffsetEncoding { - Utf8, - Utf16, -} - -pub(crate) struct LineIndex { - pub(crate) index: Arc, - pub(crate) endings: LineEndings, - pub(crate) encoding: OffsetEncoding, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) enum LineEndings { - Unix, - Dos, -} - -impl LineEndings { - /// Replaces `\r\n` with `\n` in-place in `src`. - pub(crate) fn normalize(src: String) -> (String, LineEndings) { - if !src.as_bytes().contains(&b'\r') { - return (src, LineEndings::Unix); - } - - // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding. - // While we *can* call `as_mut_vec` and do surgery on the live string - // directly, let's rather steal the contents of `src`. This makes the code - // safe even if a panic occurs. - - let mut buf = src.into_bytes(); - let mut gap_len = 0; - let mut tail = buf.as_mut_slice(); - loop { - let idx = match find_crlf(&tail[gap_len..]) { - None => tail.len(), - Some(idx) => idx + gap_len, - }; - tail.copy_within(gap_len..idx, 0); - tail = &mut tail[idx - gap_len..]; - if tail.len() == gap_len { - break; - } - gap_len += 1; - } - - // Account for removed `\r`. - // After `set_len`, `buf` is guaranteed to contain utf-8 again. - let new_len = buf.len() - gap_len; - let src = unsafe { - buf.set_len(new_len); - String::from_utf8_unchecked(buf) - }; - return (src, LineEndings::Dos); - - fn find_crlf(src: &[u8]) -> Option { - src.windows(2).position(|it| it == b"\r\n") - } - } -} diff --git a/crates/rust-analyzer/src/line_index.rs b/crates/rust-analyzer/src/line_index.rs new file mode 100644 index 000000000..c116414da --- /dev/null +++ b/crates/rust-analyzer/src/line_index.rs @@ -0,0 +1,68 @@ +//! Enhances `ide::LineIndex` with additional info required to convert offsets +//! into lsp positions. +//! +//! We maintain invariant that all internal strings use `\n` as line separator. +//! 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 enum OffsetEncoding { + Utf8, + Utf16, +} + +pub(crate) struct LineIndex { + pub(crate) index: Arc, + pub(crate) endings: LineEndings, + pub(crate) encoding: OffsetEncoding, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) enum LineEndings { + Unix, + Dos, +} + +impl LineEndings { + /// Replaces `\r\n` with `\n` in-place in `src`. + pub(crate) fn normalize(src: String) -> (String, LineEndings) { + if !src.as_bytes().contains(&b'\r') { + return (src, LineEndings::Unix); + } + + // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding. + // While we *can* call `as_mut_vec` and do surgery on the live string + // directly, let's rather steal the contents of `src`. This makes the code + // safe even if a panic occurs. + + let mut buf = src.into_bytes(); + let mut gap_len = 0; + let mut tail = buf.as_mut_slice(); + loop { + let idx = match find_crlf(&tail[gap_len..]) { + None => tail.len(), + Some(idx) => idx + gap_len, + }; + tail.copy_within(gap_len..idx, 0); + tail = &mut tail[idx - gap_len..]; + if tail.len() == gap_len { + break; + } + gap_len += 1; + } + + // Account for removed `\r`. + // After `set_len`, `buf` is guaranteed to contain utf-8 again. + let new_len = buf.len() - gap_len; + let src = unsafe { + buf.set_len(new_len); + String::from_utf8_unchecked(buf) + }; + return (src, LineEndings::Dos); + + fn find_crlf(src: &[u8]) -> Option { + src.windows(2).position(|it| it == b"\r\n") + } + } +} diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 6b8e347b9..84f78b5b8 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -7,7 +7,7 @@ use lsp_server::Notification; use crate::{ from_proto, global_state::GlobalState, - line_endings::{LineEndings, LineIndex, OffsetEncoding}, + line_index::{LineEndings, LineIndex, OffsetEncoding}, }; pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool { diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 368d916e7..6aff65575 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -17,7 +17,7 @@ use serde_json::to_value; use crate::{ cargo_target_spec::CargoTargetSpec, global_state::GlobalStateSnapshot, - line_endings::{LineEndings, LineIndex, OffsetEncoding}, + line_index::{LineEndings, LineIndex, OffsetEncoding}, lsp_ext, semantic_tokens, Result, }; -- cgit v1.2.3