mirror of https://github.com/astral-sh/ruff
[ty] Refactor `Range` to/from `TextRange` conversion as prep for notebook support (#21230)
This commit is contained in:
parent
f79044478c
commit
7009d60260
|
|
@ -1,12 +1,9 @@
|
||||||
use crate::PositionEncoding;
|
use crate::PositionEncoding;
|
||||||
use crate::document::{FileRangeExt, ToRangeExt};
|
use crate::document::{FileRangeExt, ToRangeExt};
|
||||||
use crate::system::file_to_url;
|
|
||||||
use lsp_types::Location;
|
use lsp_types::Location;
|
||||||
use ruff_db::files::FileRange;
|
use ruff_db::files::FileRange;
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
use ty_ide::{NavigationTarget, ReferenceTarget};
|
use ty_ide::{NavigationTarget, ReferenceTarget};
|
||||||
use ty_project::Db;
|
use ty_python_semantic::Db;
|
||||||
|
|
||||||
pub(crate) trait ToLink {
|
pub(crate) trait ToLink {
|
||||||
fn to_location(&self, db: &dyn Db, encoding: PositionEncoding) -> Option<Location>;
|
fn to_location(&self, db: &dyn Db, encoding: PositionEncoding) -> Option<Location>;
|
||||||
|
|
@ -21,7 +18,9 @@ pub(crate) trait ToLink {
|
||||||
|
|
||||||
impl ToLink for NavigationTarget {
|
impl ToLink for NavigationTarget {
|
||||||
fn to_location(&self, db: &dyn Db, encoding: PositionEncoding) -> Option<Location> {
|
fn to_location(&self, db: &dyn Db, encoding: PositionEncoding) -> Option<Location> {
|
||||||
FileRange::new(self.file(), self.focus_range()).to_location(db, encoding)
|
FileRange::new(self.file(), self.focus_range())
|
||||||
|
.as_lsp_range(db, encoding)
|
||||||
|
.to_location()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_link(
|
fn to_link(
|
||||||
|
|
@ -31,22 +30,24 @@ impl ToLink for NavigationTarget {
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> Option<lsp_types::LocationLink> {
|
) -> Option<lsp_types::LocationLink> {
|
||||||
let file = self.file();
|
let file = self.file();
|
||||||
let uri = file_to_url(db, file)?;
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let index = line_index(db, file);
|
|
||||||
|
|
||||||
let target_range = self.full_range().to_lsp_range(&source, &index, encoding);
|
// Get target_range and URI together to ensure they're consistent (same cell for notebooks)
|
||||||
let selection_range = self.focus_range().to_lsp_range(&source, &index, encoding);
|
let target_location = self
|
||||||
|
.full_range()
|
||||||
|
.as_lsp_range(db, file, encoding)
|
||||||
|
.to_location()?;
|
||||||
|
let target_range = target_location.range;
|
||||||
|
|
||||||
let src = src.map(|src| {
|
// For selection_range, we can use as_local_range since we know it's in the same document/cell
|
||||||
let source = source_text(db, src.file());
|
let selection_range = self
|
||||||
let index = line_index(db, src.file());
|
.focus_range()
|
||||||
|
.as_lsp_range(db, file, encoding)
|
||||||
|
.to_local_range();
|
||||||
|
|
||||||
src.range().to_lsp_range(&source, &index, encoding)
|
let src = src.map(|src| src.as_lsp_range(db, encoding).to_local_range());
|
||||||
});
|
|
||||||
|
|
||||||
Some(lsp_types::LocationLink {
|
Some(lsp_types::LocationLink {
|
||||||
target_uri: uri,
|
target_uri: target_location.uri,
|
||||||
target_range,
|
target_range,
|
||||||
target_selection_range: selection_range,
|
target_selection_range: selection_range,
|
||||||
origin_selection_range: src,
|
origin_selection_range: src,
|
||||||
|
|
@ -56,7 +57,7 @@ impl ToLink for NavigationTarget {
|
||||||
|
|
||||||
impl ToLink for ReferenceTarget {
|
impl ToLink for ReferenceTarget {
|
||||||
fn to_location(&self, db: &dyn Db, encoding: PositionEncoding) -> Option<Location> {
|
fn to_location(&self, db: &dyn Db, encoding: PositionEncoding) -> Option<Location> {
|
||||||
self.file_range().to_location(db, encoding)
|
self.file_range().as_lsp_range(db, encoding).to_location()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_link(
|
fn to_link(
|
||||||
|
|
@ -65,22 +66,18 @@ impl ToLink for ReferenceTarget {
|
||||||
src: Option<FileRange>,
|
src: Option<FileRange>,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> Option<lsp_types::LocationLink> {
|
) -> Option<lsp_types::LocationLink> {
|
||||||
let uri = file_to_url(db, self.file())?;
|
// Get target_range and URI together to ensure they're consistent (same cell for notebooks)
|
||||||
let source = source_text(db, self.file());
|
let target_location = self
|
||||||
let index = line_index(db, self.file());
|
.range()
|
||||||
|
.as_lsp_range(db, self.file(), encoding)
|
||||||
let target_range = self.range().to_lsp_range(&source, &index, encoding);
|
.to_location()?;
|
||||||
|
let target_range = target_location.range;
|
||||||
let selection_range = target_range;
|
let selection_range = target_range;
|
||||||
|
|
||||||
let src = src.map(|src| {
|
let src = src.map(|src| src.as_lsp_range(db, encoding).to_local_range());
|
||||||
let source = source_text(db, src.file());
|
|
||||||
let index = line_index(db, src.file());
|
|
||||||
|
|
||||||
src.range().to_lsp_range(&source, &index, encoding)
|
|
||||||
});
|
|
||||||
|
|
||||||
Some(lsp_types::LocationLink {
|
Some(lsp_types::LocationLink {
|
||||||
target_uri: uri,
|
target_uri: target_location.uri,
|
||||||
target_range,
|
target_range,
|
||||||
target_selection_range: selection_range,
|
target_selection_range: selection_range,
|
||||||
origin_selection_range: src,
|
origin_selection_range: src,
|
||||||
|
|
|
||||||
|
|
@ -1,148 +1,288 @@
|
||||||
use super::PositionEncoding;
|
use super::PositionEncoding;
|
||||||
use super::notebook;
|
|
||||||
use crate::system::file_to_url;
|
use crate::system::file_to_url;
|
||||||
|
use ty_python_semantic::Db;
|
||||||
|
|
||||||
use lsp_types as types;
|
use lsp_types as types;
|
||||||
use lsp_types::Location;
|
use lsp_types::{Location, Position, Url};
|
||||||
|
use ruff_db::files::{File, FileRange};
|
||||||
use ruff_db::files::FileRange;
|
|
||||||
use ruff_db::source::{line_index, source_text};
|
use ruff_db::source::{line_index, source_text};
|
||||||
use ruff_notebook::NotebookIndex;
|
|
||||||
use ruff_source_file::LineIndex;
|
use ruff_source_file::LineIndex;
|
||||||
use ruff_source_file::{OneIndexed, SourceLocation};
|
use ruff_source_file::{OneIndexed, SourceLocation};
|
||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
use ty_python_semantic::Db;
|
|
||||||
|
|
||||||
#[expect(dead_code)]
|
/// Represents a range that has been prepared for LSP conversion but requires
|
||||||
pub(crate) struct NotebookRange {
|
/// a decision about how to use it - either as a local range within the same
|
||||||
pub(crate) cell: notebook::CellId,
|
/// document/cell, or as a location that can reference any document in the project.
|
||||||
pub(crate) range: types::Range,
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct LspRange<'db> {
|
||||||
|
file: File,
|
||||||
|
range: TextRange,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for LspRange<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("LspRange")
|
||||||
|
.field("range", &self.range)
|
||||||
|
.field("file", &self.file)
|
||||||
|
.field("encoding", &self.encoding)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LspRange<'_> {
|
||||||
|
/// Convert to an LSP Range for use within the same document/cell.
|
||||||
|
/// Returns only the LSP Range without any URI information.
|
||||||
|
///
|
||||||
|
/// Use this when you already have a URI context and this range is guaranteed
|
||||||
|
/// to be within the same document/cell:
|
||||||
|
/// - Selection ranges within a `LocationLink` (where `target_uri` provides context)
|
||||||
|
/// - Additional ranges in the same cell (e.g., `selection_range` when you already have `target_range`)
|
||||||
|
///
|
||||||
|
/// Do NOT use this for standalone ranges - use `to_location()` instead to ensure
|
||||||
|
/// the URI and range are consistent.
|
||||||
|
pub(crate) fn to_local_range(&self) -> types::Range {
|
||||||
|
self.to_uri_and_range().1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert to a Location that can reference any document.
|
||||||
|
/// Returns a Location with both URI and Range.
|
||||||
|
///
|
||||||
|
/// Use this for:
|
||||||
|
/// - Go-to-definition targets
|
||||||
|
/// - References
|
||||||
|
/// - Diagnostics related information
|
||||||
|
/// - Any cross-file navigation
|
||||||
|
pub(crate) fn to_location(&self) -> Option<Location> {
|
||||||
|
let (uri, range) = self.to_uri_and_range();
|
||||||
|
Some(Location { uri: uri?, range })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_uri_and_range(&self) -> (Option<Url>, lsp_types::Range) {
|
||||||
|
let source = source_text(self.db, self.file);
|
||||||
|
let index = line_index(self.db, self.file);
|
||||||
|
|
||||||
|
let uri = file_to_url(self.db, self.file);
|
||||||
|
let range = text_range_to_lsp_range(self.range, &source, &index, self.encoding);
|
||||||
|
(uri, range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a position that has been prepared for LSP conversion but requires
|
||||||
|
/// a decision about how to use it - either as a local position within the same
|
||||||
|
/// document/cell, or as a location with a single-point range that can reference
|
||||||
|
/// any document in the project.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct LspPosition<'db> {
|
||||||
|
file: File,
|
||||||
|
position: TextSize,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for LspPosition<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("LspPosition")
|
||||||
|
.field("position", &self.position)
|
||||||
|
.field("file", &self.file)
|
||||||
|
.field("encoding", &self.encoding)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LspPosition<'_> {
|
||||||
|
/// Convert to an LSP Position for use within the same document/cell.
|
||||||
|
/// Returns only the LSP Position without any URI information.
|
||||||
|
///
|
||||||
|
/// Use this when you already have a URI context and this position is guaranteed
|
||||||
|
/// to be within the same document/cell:
|
||||||
|
/// - Inlay hints (where the document URI is already known)
|
||||||
|
/// - Positions within the same cell as a parent range
|
||||||
|
///
|
||||||
|
/// Do NOT use this for standalone positions that might need a URI - use
|
||||||
|
/// `to_location()` instead to ensure the URI and position are consistent.
|
||||||
|
pub(crate) fn to_local_position(&self) -> types::Position {
|
||||||
|
self.to_location().1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert to a Location with a single-point range that can reference any document.
|
||||||
|
/// Returns a Location with both URI and a range where start == end.
|
||||||
|
///
|
||||||
|
/// Use this for any cross-file navigation where you need both URI and position.
|
||||||
|
pub(crate) fn to_location(&self) -> (Option<lsp_types::Url>, Position) {
|
||||||
|
let source = source_text(self.db, self.file);
|
||||||
|
let index = line_index(self.db, self.file);
|
||||||
|
|
||||||
|
let uri = file_to_url(self.db, self.file);
|
||||||
|
let position = text_size_to_lsp_position(self.position, &source, &index, self.encoding);
|
||||||
|
(uri, position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait RangeExt {
|
pub(crate) trait RangeExt {
|
||||||
fn to_text_range(&self, text: &str, index: &LineIndex, encoding: PositionEncoding)
|
/// Convert an LSP Range to internal `TextRange`.
|
||||||
-> TextRange;
|
fn to_text_range(
|
||||||
|
&self,
|
||||||
|
db: &dyn Db,
|
||||||
|
file: File,
|
||||||
|
url: &lsp_types::Url,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
) -> TextRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RangeExt for lsp_types::Range {
|
||||||
|
fn to_text_range(
|
||||||
|
&self,
|
||||||
|
db: &dyn Db,
|
||||||
|
file: File,
|
||||||
|
url: &lsp_types::Url,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
) -> TextRange {
|
||||||
|
let start = self.start.to_text_size(db, file, url, encoding);
|
||||||
|
let end = self.end.to_text_size(db, file, url, encoding);
|
||||||
|
|
||||||
|
TextRange::new(start, end)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait PositionExt {
|
pub(crate) trait PositionExt {
|
||||||
fn to_text_size(&self, text: &str, index: &LineIndex, encoding: PositionEncoding) -> TextSize;
|
/// Convert an LSP Position to internal `TextSize`.
|
||||||
|
fn to_text_size(
|
||||||
|
&self,
|
||||||
|
db: &dyn Db,
|
||||||
|
file: File,
|
||||||
|
url: &lsp_types::Url,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
) -> TextSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PositionExt for lsp_types::Position {
|
||||||
|
fn to_text_size(
|
||||||
|
&self,
|
||||||
|
db: &dyn Db,
|
||||||
|
file: File,
|
||||||
|
_url: &lsp_types::Url,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
) -> TextSize {
|
||||||
|
let source = source_text(db, file);
|
||||||
|
let index = line_index(db, file);
|
||||||
|
|
||||||
|
lsp_position_to_text_size(*self, &source, &index, encoding)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait TextSizeExt {
|
pub(crate) trait TextSizeExt {
|
||||||
fn to_position(
|
/// Converts this position to an `LspPosition`, which then requires an explicit
|
||||||
self,
|
/// decision about how to use it (as a local position or as a location).
|
||||||
text: &str,
|
fn as_lsp_position<'db>(
|
||||||
index: &LineIndex,
|
&self,
|
||||||
|
db: &'db dyn Db,
|
||||||
|
file: File,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> types::Position
|
) -> LspPosition<'db>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextSizeExt for TextSize {
|
impl TextSizeExt for TextSize {
|
||||||
fn to_position(
|
fn as_lsp_position<'db>(
|
||||||
self,
|
&self,
|
||||||
text: &str,
|
db: &'db dyn Db,
|
||||||
index: &LineIndex,
|
file: File,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> types::Position {
|
) -> LspPosition<'db> {
|
||||||
let source_location = index.source_location(self, text, encoding.into());
|
LspPosition {
|
||||||
source_location_to_position(&source_location)
|
file,
|
||||||
|
position: *self,
|
||||||
|
db,
|
||||||
|
encoding,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait ToRangeExt {
|
pub(crate) trait ToRangeExt {
|
||||||
fn to_lsp_range(
|
/// Converts this range to an `LspRange`, which then requires an explicit
|
||||||
|
/// decision about how to use it (as a local range or as a location).
|
||||||
|
fn as_lsp_range<'db>(
|
||||||
&self,
|
&self,
|
||||||
text: &str,
|
db: &'db dyn Db,
|
||||||
index: &LineIndex,
|
file: File,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> types::Range;
|
) -> LspRange<'db>;
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
fn to_notebook_range(
|
|
||||||
&self,
|
|
||||||
text: &str,
|
|
||||||
source_index: &LineIndex,
|
|
||||||
notebook_index: &NotebookIndex,
|
|
||||||
encoding: PositionEncoding,
|
|
||||||
) -> NotebookRange;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn u32_index_to_usize(index: u32) -> usize {
|
fn u32_index_to_usize(index: u32) -> usize {
|
||||||
usize::try_from(index).expect("u32 fits in usize")
|
usize::try_from(index).expect("u32 fits in usize")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PositionExt for lsp_types::Position {
|
fn text_size_to_lsp_position(
|
||||||
fn to_text_size(&self, text: &str, index: &LineIndex, encoding: PositionEncoding) -> TextSize {
|
offset: TextSize,
|
||||||
index.offset(
|
text: &str,
|
||||||
SourceLocation {
|
index: &LineIndex,
|
||||||
line: OneIndexed::from_zero_indexed(u32_index_to_usize(self.line)),
|
encoding: PositionEncoding,
|
||||||
character_offset: OneIndexed::from_zero_indexed(u32_index_to_usize(self.character)),
|
) -> types::Position {
|
||||||
},
|
let source_location = index.source_location(offset, text, encoding.into());
|
||||||
text,
|
source_location_to_position(&source_location)
|
||||||
encoding.into(),
|
}
|
||||||
)
|
|
||||||
|
fn text_range_to_lsp_range(
|
||||||
|
range: TextRange,
|
||||||
|
text: &str,
|
||||||
|
index: &LineIndex,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
) -> types::Range {
|
||||||
|
types::Range {
|
||||||
|
start: text_size_to_lsp_position(range.start(), text, index, encoding),
|
||||||
|
end: text_size_to_lsp_position(range.end(), text, index, encoding),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RangeExt for lsp_types::Range {
|
/// Helper function to convert an LSP Position to internal `TextSize`.
|
||||||
fn to_text_range(
|
/// This is used internally by the `PositionExt` trait and other helpers.
|
||||||
&self,
|
fn lsp_position_to_text_size(
|
||||||
text: &str,
|
position: lsp_types::Position,
|
||||||
index: &LineIndex,
|
text: &str,
|
||||||
encoding: PositionEncoding,
|
index: &LineIndex,
|
||||||
) -> TextRange {
|
encoding: PositionEncoding,
|
||||||
TextRange::new(
|
) -> TextSize {
|
||||||
self.start.to_text_size(text, index, encoding),
|
index.offset(
|
||||||
self.end.to_text_size(text, index, encoding),
|
SourceLocation {
|
||||||
)
|
line: OneIndexed::from_zero_indexed(u32_index_to_usize(position.line)),
|
||||||
}
|
character_offset: OneIndexed::from_zero_indexed(u32_index_to_usize(position.character)),
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
encoding.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to convert an LSP Range to internal `TextRange`.
|
||||||
|
/// This is used internally by the `RangeExt` trait and in special cases
|
||||||
|
/// where `db` and `file` are not available (e.g., when applying document changes).
|
||||||
|
pub(crate) fn lsp_range_to_text_range(
|
||||||
|
range: lsp_types::Range,
|
||||||
|
text: &str,
|
||||||
|
index: &LineIndex,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
) -> TextRange {
|
||||||
|
TextRange::new(
|
||||||
|
lsp_position_to_text_size(range.start, text, index, encoding),
|
||||||
|
lsp_position_to_text_size(range.end, text, index, encoding),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToRangeExt for TextRange {
|
impl ToRangeExt for TextRange {
|
||||||
fn to_lsp_range(
|
fn as_lsp_range<'db>(
|
||||||
&self,
|
&self,
|
||||||
text: &str,
|
db: &'db dyn Db,
|
||||||
index: &LineIndex,
|
file: File,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> types::Range {
|
) -> LspRange<'db> {
|
||||||
types::Range {
|
LspRange {
|
||||||
start: self.start().to_position(text, index, encoding),
|
file,
|
||||||
end: self.end().to_position(text, index, encoding),
|
range: *self,
|
||||||
}
|
db,
|
||||||
}
|
encoding,
|
||||||
|
|
||||||
fn to_notebook_range(
|
|
||||||
&self,
|
|
||||||
text: &str,
|
|
||||||
source_index: &LineIndex,
|
|
||||||
notebook_index: &NotebookIndex,
|
|
||||||
encoding: PositionEncoding,
|
|
||||||
) -> NotebookRange {
|
|
||||||
let start = source_index.source_location(self.start(), text, encoding.into());
|
|
||||||
let mut end = source_index.source_location(self.end(), text, encoding.into());
|
|
||||||
let starting_cell = notebook_index.cell(start.line);
|
|
||||||
|
|
||||||
// weird edge case here - if the end of the range is where the newline after the cell got added (making it 'out of bounds')
|
|
||||||
// we need to move it one character back (which should place it at the end of the last line).
|
|
||||||
// we test this by checking if the ending offset is in a different (or nonexistent) cell compared to the cell of the starting offset.
|
|
||||||
if notebook_index.cell(end.line) != starting_cell {
|
|
||||||
end.line = end.line.saturating_sub(1);
|
|
||||||
let offset = self.end().checked_sub(1.into()).unwrap_or_default();
|
|
||||||
end.character_offset = source_index
|
|
||||||
.source_location(offset, text, encoding.into())
|
|
||||||
.character_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
let start = source_location_to_position(¬ebook_index.translate_source_location(&start));
|
|
||||||
let end = source_location_to_position(¬ebook_index.translate_source_location(&end));
|
|
||||||
|
|
||||||
NotebookRange {
|
|
||||||
cell: starting_cell
|
|
||||||
.map(OneIndexed::to_zero_indexed)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
range: types::Range { start, end },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -156,17 +296,18 @@ fn source_location_to_position(location: &SourceLocation) -> types::Position {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait FileRangeExt {
|
pub(crate) trait FileRangeExt {
|
||||||
fn to_location(&self, db: &dyn Db, encoding: PositionEncoding) -> Option<Location>;
|
/// Converts this file range to an `LspRange`, which then requires an explicit
|
||||||
|
/// decision about how to use it (as a local range or as a location).
|
||||||
|
fn as_lsp_range<'db>(&self, db: &'db dyn Db, encoding: PositionEncoding) -> LspRange<'db>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileRangeExt for FileRange {
|
impl FileRangeExt for FileRange {
|
||||||
fn to_location(&self, db: &dyn Db, encoding: PositionEncoding) -> Option<Location> {
|
fn as_lsp_range<'db>(&self, db: &'db dyn Db, encoding: PositionEncoding) -> LspRange<'db> {
|
||||||
let file = self.file();
|
LspRange {
|
||||||
let uri = file_to_url(db, file)?;
|
file: self.file(),
|
||||||
let source = source_text(db, file);
|
range: self.range(),
|
||||||
let line_index = line_index(db, file);
|
db,
|
||||||
|
encoding,
|
||||||
let range = self.range().to_lsp_range(&source, &line_index, encoding);
|
}
|
||||||
Some(Location { uri, range })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use ruff_source_file::LineIndex;
|
||||||
|
|
||||||
use crate::PositionEncoding;
|
use crate::PositionEncoding;
|
||||||
|
|
||||||
use super::RangeExt;
|
use super::range::lsp_range_to_text_range;
|
||||||
|
|
||||||
pub(crate) type DocumentVersion = i32;
|
pub(crate) type DocumentVersion = i32;
|
||||||
|
|
||||||
|
|
@ -114,7 +114,7 @@ impl TextDocument {
|
||||||
} in changes
|
} in changes
|
||||||
{
|
{
|
||||||
if let Some(range) = range {
|
if let Some(range) = range {
|
||||||
let range = range.to_text_range(&new_contents, &active_index, encoding);
|
let range = lsp_range_to_text_range(range, &new_contents, &active_index, encoding);
|
||||||
|
|
||||||
new_contents.replace_range(
|
new_contents.replace_range(
|
||||||
usize::from(range.start())..usize::from(range.end()),
|
usize::from(range.start())..usize::from(range.end()),
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ruff_db::diagnostic::{Annotation, Severity, SubDiagnostic};
|
use ruff_db::diagnostic::{Annotation, Severity, SubDiagnostic};
|
||||||
use ruff_db::files::FileRange;
|
use ruff_db::files::FileRange;
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ruff_db::system::SystemPathBuf;
|
use ruff_db::system::SystemPathBuf;
|
||||||
use ty_project::{Db, ProjectDatabase};
|
use ty_project::{Db, ProjectDatabase};
|
||||||
|
|
||||||
|
|
@ -279,11 +278,9 @@ pub(super) fn to_lsp_diagnostic(
|
||||||
) -> Diagnostic {
|
) -> Diagnostic {
|
||||||
let range = if let Some(span) = diagnostic.primary_span() {
|
let range = if let Some(span) = diagnostic.primary_span() {
|
||||||
let file = span.expect_ty_file();
|
let file = span.expect_ty_file();
|
||||||
let index = line_index(db, file);
|
|
||||||
let source = source_text(db, file);
|
|
||||||
|
|
||||||
span.range()
|
span.range()
|
||||||
.map(|range| range.to_lsp_range(&source, &index, encoding))
|
.map(|range| range.as_lsp_range(db, file, encoding).to_local_range())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
} else {
|
} else {
|
||||||
Range::default()
|
Range::default()
|
||||||
|
|
@ -365,7 +362,7 @@ fn annotation_to_related_information(
|
||||||
|
|
||||||
let annotation_message = annotation.get_message()?;
|
let annotation_message = annotation.get_message()?;
|
||||||
let range = FileRange::try_from(span).ok()?;
|
let range = FileRange::try_from(span).ok()?;
|
||||||
let location = range.to_location(db, encoding)?;
|
let location = range.as_lsp_range(db, encoding).to_location()?;
|
||||||
|
|
||||||
Some(DiagnosticRelatedInformation {
|
Some(DiagnosticRelatedInformation {
|
||||||
location,
|
location,
|
||||||
|
|
@ -383,7 +380,7 @@ fn sub_diagnostic_to_related_information(
|
||||||
|
|
||||||
let span = primary_annotation.get_span();
|
let span = primary_annotation.get_span();
|
||||||
let range = FileRange::try_from(span).ok()?;
|
let range = FileRange::try_from(span).ok()?;
|
||||||
let location = range.to_location(db, encoding)?;
|
let location = range.as_lsp_range(db, encoding).to_location()?;
|
||||||
|
|
||||||
Some(DiagnosticRelatedInformation {
|
Some(DiagnosticRelatedInformation {
|
||||||
location,
|
location,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use lsp_types::{
|
||||||
CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList,
|
CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList,
|
||||||
CompletionParams, CompletionResponse, Documentation, TextEdit, Url,
|
CompletionParams, CompletionResponse, Documentation, TextEdit, Url,
|
||||||
};
|
};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ruff_source_file::OneIndexed;
|
use ruff_source_file::OneIndexed;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
use ty_ide::{CompletionKind, CompletionSettings, completion};
|
use ty_ide::{CompletionKind, CompletionSettings, completion};
|
||||||
|
|
@ -49,11 +48,10 @@ impl BackgroundDocumentRequestHandler for CompletionRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position.position.to_text_size(
|
let offset = params.text_document_position.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
let settings = CompletionSettings {
|
let settings = CompletionSettings {
|
||||||
|
|
@ -73,9 +71,10 @@ impl BackgroundDocumentRequestHandler for CompletionRequestHandler {
|
||||||
let kind = comp.kind(db).map(ty_kind_to_lsp_kind);
|
let kind = comp.kind(db).map(ty_kind_to_lsp_kind);
|
||||||
let type_display = comp.ty.map(|ty| ty.display(db).to_string());
|
let type_display = comp.ty.map(|ty| ty.display(db).to_string());
|
||||||
let import_edit = comp.import.as_ref().map(|edit| {
|
let import_edit = comp.import.as_ref().map(|edit| {
|
||||||
let range =
|
let range = edit
|
||||||
edit.range()
|
.range()
|
||||||
.to_lsp_range(&source, &line_index, snapshot.encoding());
|
.as_lsp_range(db, file, snapshot.encoding())
|
||||||
|
.to_local_range();
|
||||||
TextEdit {
|
TextEdit {
|
||||||
range,
|
range,
|
||||||
new_text: edit.content().map(ToString::to_string).unwrap_or_default(),
|
new_text: edit.content().map(ToString::to_string).unwrap_or_default(),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use lsp_types::request::DocumentHighlightRequest;
|
use lsp_types::request::DocumentHighlightRequest;
|
||||||
use lsp_types::{DocumentHighlight, DocumentHighlightKind, DocumentHighlightParams, Url};
|
use lsp_types::{DocumentHighlight, DocumentHighlightKind, DocumentHighlightParams, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::{ReferenceKind, document_highlights};
|
use ty_ide::{ReferenceKind, document_highlights};
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -41,11 +40,10 @@ impl BackgroundDocumentRequestHandler for DocumentHighlightRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position_params.position.to_text_size(
|
let offset = params.text_document_position_params.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -58,7 +56,8 @@ impl BackgroundDocumentRequestHandler for DocumentHighlightRequestHandler {
|
||||||
.map(|target| {
|
.map(|target| {
|
||||||
let range = target
|
let range = target
|
||||||
.range()
|
.range()
|
||||||
.to_lsp_range(&source, &line_index, snapshot.encoding());
|
.as_lsp_range(db, file, snapshot.encoding())
|
||||||
|
.to_local_range();
|
||||||
|
|
||||||
let kind = match target.kind() {
|
let kind = match target.kind() {
|
||||||
ReferenceKind::Read => Some(DocumentHighlightKind::READ),
|
ReferenceKind::Read => Some(DocumentHighlightKind::READ),
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use lsp_types::request::DocumentSymbolRequest;
|
use lsp_types::request::DocumentSymbolRequest;
|
||||||
use lsp_types::{DocumentSymbol, DocumentSymbolParams, SymbolInformation, Url};
|
use lsp_types::{DocumentSymbol, DocumentSymbolParams, SymbolInformation, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
use ruff_db::files::File;
|
||||||
use ruff_source_file::LineIndex;
|
|
||||||
use ty_ide::{HierarchicalSymbols, SymbolId, SymbolInfo, document_symbols};
|
use ty_ide::{HierarchicalSymbols, SymbolId, SymbolInfo, document_symbols};
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::{Db, ProjectDatabase};
|
||||||
|
|
||||||
use crate::document::{PositionEncoding, ToRangeExt};
|
use crate::document::{PositionEncoding, ToRangeExt};
|
||||||
use crate::server::api::symbols::{convert_symbol_kind, convert_to_lsp_symbol_information};
|
use crate::server::api::symbols::{convert_symbol_kind, convert_to_lsp_symbol_information};
|
||||||
|
|
@ -30,7 +29,7 @@ impl BackgroundDocumentRequestHandler for DocumentSymbolRequestHandler {
|
||||||
db: &ProjectDatabase,
|
db: &ProjectDatabase,
|
||||||
snapshot: &DocumentSnapshot,
|
snapshot: &DocumentSnapshot,
|
||||||
_client: &Client,
|
_client: &Client,
|
||||||
params: DocumentSymbolParams,
|
_params: DocumentSymbolParams,
|
||||||
) -> crate::server::Result<Option<lsp_types::DocumentSymbolResponse>> {
|
) -> crate::server::Result<Option<lsp_types::DocumentSymbolResponse>> {
|
||||||
if snapshot
|
if snapshot
|
||||||
.workspace_settings()
|
.workspace_settings()
|
||||||
|
|
@ -43,9 +42,6 @@ impl BackgroundDocumentRequestHandler for DocumentSymbolRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
|
|
||||||
// Check if the client supports hierarchical document symbols
|
// Check if the client supports hierarchical document symbols
|
||||||
let supports_hierarchical = snapshot
|
let supports_hierarchical = snapshot
|
||||||
.resolved_client_capabilities()
|
.resolved_client_capabilities()
|
||||||
|
|
@ -62,11 +58,11 @@ impl BackgroundDocumentRequestHandler for DocumentSymbolRequestHandler {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(id, symbol)| {
|
.map(|(id, symbol)| {
|
||||||
convert_to_lsp_document_symbol(
|
convert_to_lsp_document_symbol(
|
||||||
|
db,
|
||||||
|
file,
|
||||||
&symbols,
|
&symbols,
|
||||||
id,
|
id,
|
||||||
symbol,
|
symbol,
|
||||||
&source,
|
|
||||||
&line_index,
|
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -77,14 +73,8 @@ impl BackgroundDocumentRequestHandler for DocumentSymbolRequestHandler {
|
||||||
// Return flattened symbols as SymbolInformation
|
// Return flattened symbols as SymbolInformation
|
||||||
let lsp_symbols: Vec<SymbolInformation> = symbols
|
let lsp_symbols: Vec<SymbolInformation> = symbols
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, symbol)| {
|
.filter_map(|(_, symbol)| {
|
||||||
convert_to_lsp_symbol_information(
|
convert_to_lsp_symbol_information(db, file, symbol, snapshot.encoding())
|
||||||
symbol,
|
|
||||||
¶ms.text_document.uri,
|
|
||||||
&source,
|
|
||||||
&line_index,
|
|
||||||
snapshot.encoding(),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
@ -96,11 +86,11 @@ impl BackgroundDocumentRequestHandler for DocumentSymbolRequestHandler {
|
||||||
impl RetriableRequestHandler for DocumentSymbolRequestHandler {}
|
impl RetriableRequestHandler for DocumentSymbolRequestHandler {}
|
||||||
|
|
||||||
fn convert_to_lsp_document_symbol(
|
fn convert_to_lsp_document_symbol(
|
||||||
|
db: &dyn Db,
|
||||||
|
file: File,
|
||||||
symbols: &HierarchicalSymbols,
|
symbols: &HierarchicalSymbols,
|
||||||
id: SymbolId,
|
id: SymbolId,
|
||||||
symbol: SymbolInfo<'_>,
|
symbol: SymbolInfo<'_>,
|
||||||
source: &str,
|
|
||||||
line_index: &LineIndex,
|
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> DocumentSymbol {
|
) -> DocumentSymbol {
|
||||||
let symbol_kind = convert_symbol_kind(symbol.kind);
|
let symbol_kind = convert_symbol_kind(symbol.kind);
|
||||||
|
|
@ -112,15 +102,19 @@ fn convert_to_lsp_document_symbol(
|
||||||
tags: None,
|
tags: None,
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
deprecated: None,
|
deprecated: None,
|
||||||
range: symbol.full_range.to_lsp_range(source, line_index, encoding),
|
range: symbol
|
||||||
selection_range: symbol.name_range.to_lsp_range(source, line_index, encoding),
|
.full_range
|
||||||
|
.as_lsp_range(db, file, encoding)
|
||||||
|
.to_local_range(),
|
||||||
|
selection_range: symbol
|
||||||
|
.name_range
|
||||||
|
.as_lsp_range(db, file, encoding)
|
||||||
|
.to_local_range(),
|
||||||
children: Some(
|
children: Some(
|
||||||
symbols
|
symbols
|
||||||
.children(id)
|
.children(id)
|
||||||
.map(|(child_id, child)| {
|
.map(|(child_id, child)| {
|
||||||
convert_to_lsp_document_symbol(
|
convert_to_lsp_document_symbol(db, file, symbols, child_id, child, encoding)
|
||||||
symbols, child_id, child, source, line_index, encoding,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use lsp_types::request::{GotoDeclaration, GotoDeclarationParams};
|
use lsp_types::request::{GotoDeclaration, GotoDeclarationParams};
|
||||||
use lsp_types::{GotoDefinitionResponse, Url};
|
use lsp_types::{GotoDefinitionResponse, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::goto_declaration;
|
use ty_ide::goto_declaration;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -41,11 +40,10 @@ impl BackgroundDocumentRequestHandler for GotoDeclarationRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position_params.position.to_text_size(
|
let offset = params.text_document_position_params.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use lsp_types::request::GotoDefinition;
|
use lsp_types::request::GotoDefinition;
|
||||||
use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse, Url};
|
use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::goto_definition;
|
use ty_ide::goto_definition;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -41,11 +40,10 @@ impl BackgroundDocumentRequestHandler for GotoDefinitionRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position_params.position.to_text_size(
|
let offset = params.text_document_position_params.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use lsp_types::request::References;
|
use lsp_types::request::References;
|
||||||
use lsp_types::{Location, ReferenceParams, Url};
|
use lsp_types::{Location, ReferenceParams, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::goto_references;
|
use ty_ide::goto_references;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -41,11 +40,10 @@ impl BackgroundDocumentRequestHandler for ReferencesRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position.position.to_text_size(
|
let offset = params.text_document_position.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use lsp_types::request::{GotoTypeDefinition, GotoTypeDefinitionParams};
|
use lsp_types::request::{GotoTypeDefinition, GotoTypeDefinitionParams};
|
||||||
use lsp_types::{GotoDefinitionResponse, Url};
|
use lsp_types::{GotoDefinitionResponse, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::goto_type_definition;
|
use ty_ide::goto_type_definition;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -41,11 +40,10 @@ impl BackgroundDocumentRequestHandler for GotoTypeDefinitionRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position_params.position.to_text_size(
|
let offset = params.text_document_position_params.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::document::{PositionExt, ToRangeExt};
|
use crate::document::{FileRangeExt, PositionExt};
|
||||||
use crate::server::api::traits::{
|
use crate::server::api::traits::{
|
||||||
BackgroundDocumentRequestHandler, RequestHandler, RetriableRequestHandler,
|
BackgroundDocumentRequestHandler, RequestHandler, RetriableRequestHandler,
|
||||||
};
|
};
|
||||||
|
|
@ -8,8 +8,6 @@ use crate::session::DocumentSnapshot;
|
||||||
use crate::session::client::Client;
|
use crate::session::client::Client;
|
||||||
use lsp_types::request::HoverRequest;
|
use lsp_types::request::HoverRequest;
|
||||||
use lsp_types::{HoverContents, HoverParams, MarkupContent, Url};
|
use lsp_types::{HoverContents, HoverParams, MarkupContent, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ruff_text_size::Ranged;
|
|
||||||
use ty_ide::{MarkupKind, hover};
|
use ty_ide::{MarkupKind, hover};
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -41,11 +39,10 @@ impl BackgroundDocumentRequestHandler for HoverRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position_params.position.to_text_size(
|
let offset = params.text_document_position_params.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -69,11 +66,12 @@ impl BackgroundDocumentRequestHandler for HoverRequestHandler {
|
||||||
kind: lsp_markup_kind,
|
kind: lsp_markup_kind,
|
||||||
value: contents,
|
value: contents,
|
||||||
}),
|
}),
|
||||||
range: Some(range_info.file_range().range().to_lsp_range(
|
range: Some(
|
||||||
&source,
|
range_info
|
||||||
&line_index,
|
.file_range()
|
||||||
snapshot.encoding(),
|
.as_lsp_range(db, snapshot.encoding())
|
||||||
)),
|
.to_local_range(),
|
||||||
|
),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ use crate::session::DocumentSnapshot;
|
||||||
use crate::session::client::Client;
|
use crate::session::client::Client;
|
||||||
use lsp_types::request::InlayHintRequest;
|
use lsp_types::request::InlayHintRequest;
|
||||||
use lsp_types::{InlayHintParams, Url};
|
use lsp_types::{InlayHintParams, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::{InlayHintKind, InlayHintLabel, inlay_hints};
|
use ty_ide::{InlayHintKind, InlayHintLabel, inlay_hints};
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -40,12 +39,9 @@ impl BackgroundDocumentRequestHandler for InlayHintRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let index = line_index(db, file);
|
|
||||||
let source = source_text(db, file);
|
|
||||||
|
|
||||||
let range = params
|
let range = params
|
||||||
.range
|
.range
|
||||||
.to_text_range(&source, &index, snapshot.encoding());
|
.to_text_range(db, file, snapshot.url(), snapshot.encoding());
|
||||||
|
|
||||||
let inlay_hints = inlay_hints(db, file, range, workspace_settings.inlay_hints());
|
let inlay_hints = inlay_hints(db, file, range, workspace_settings.inlay_hints());
|
||||||
|
|
||||||
|
|
@ -54,7 +50,8 @@ impl BackgroundDocumentRequestHandler for InlayHintRequestHandler {
|
||||||
.map(|hint| lsp_types::InlayHint {
|
.map(|hint| lsp_types::InlayHint {
|
||||||
position: hint
|
position: hint
|
||||||
.position
|
.position
|
||||||
.to_position(&source, &index, snapshot.encoding()),
|
.as_lsp_position(db, file, snapshot.encoding())
|
||||||
|
.to_local_position(),
|
||||||
label: inlay_hint_label(&hint.label),
|
label: inlay_hint_label(&hint.label),
|
||||||
kind: Some(inlay_hint_kind(&hint.kind)),
|
kind: Some(inlay_hint_kind(&hint.kind)),
|
||||||
tooltip: None,
|
tooltip: None,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use lsp_types::request::PrepareRenameRequest;
|
use lsp_types::request::PrepareRenameRequest;
|
||||||
use lsp_types::{PrepareRenameResponse, TextDocumentPositionParams, Url};
|
use lsp_types::{PrepareRenameResponse, TextDocumentPositionParams, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::can_rename;
|
use ty_ide::can_rename;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -41,17 +40,17 @@ impl BackgroundDocumentRequestHandler for PrepareRenameRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params
|
let offset = params
|
||||||
.position
|
.position
|
||||||
.to_text_size(&source, &line_index, snapshot.encoding());
|
.to_text_size(db, file, snapshot.url(), snapshot.encoding());
|
||||||
|
|
||||||
let Some(range) = can_rename(db, file, offset) else {
|
let Some(range) = can_rename(db, file, offset) else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let lsp_range = range.to_lsp_range(&source, &line_index, snapshot.encoding());
|
let lsp_range = range
|
||||||
|
.as_lsp_range(db, file, snapshot.encoding())
|
||||||
|
.to_local_range();
|
||||||
|
|
||||||
Ok(Some(PrepareRenameResponse::Range(lsp_range)))
|
Ok(Some(PrepareRenameResponse::Range(lsp_range)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use lsp_types::request::Rename;
|
use lsp_types::request::Rename;
|
||||||
use lsp_types::{RenameParams, TextEdit, Url, WorkspaceEdit};
|
use lsp_types::{RenameParams, TextEdit, Url, WorkspaceEdit};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::rename;
|
use ty_ide::rename;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -42,11 +41,10 @@ impl BackgroundDocumentRequestHandler for RenameRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position.position.to_text_size(
|
let offset = params.text_document_position.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use lsp_types::request::SelectionRangeRequest;
|
use lsp_types::request::SelectionRangeRequest;
|
||||||
use lsp_types::{SelectionRange as LspSelectionRange, SelectionRangeParams, Url};
|
use lsp_types::{SelectionRange as LspSelectionRange, SelectionRangeParams, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::selection_range;
|
use ty_ide::selection_range;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -41,13 +40,10 @@ impl BackgroundDocumentRequestHandler for SelectionRangeRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
|
||||||
for position in params.positions {
|
for position in params.positions {
|
||||||
let offset = position.to_text_size(&source, &line_index, snapshot.encoding());
|
let offset = position.to_text_size(db, file, snapshot.url(), snapshot.encoding());
|
||||||
|
|
||||||
let ranges = selection_range(db, file, offset);
|
let ranges = selection_range(db, file, offset);
|
||||||
if !ranges.is_empty() {
|
if !ranges.is_empty() {
|
||||||
|
|
@ -55,7 +51,9 @@ impl BackgroundDocumentRequestHandler for SelectionRangeRequestHandler {
|
||||||
let mut lsp_range = None;
|
let mut lsp_range = None;
|
||||||
for &range in &ranges {
|
for &range in &ranges {
|
||||||
lsp_range = Some(LspSelectionRange {
|
lsp_range = Some(LspSelectionRange {
|
||||||
range: range.to_lsp_range(&source, &line_index, snapshot.encoding()),
|
range: range
|
||||||
|
.as_lsp_range(db, file, snapshot.encoding())
|
||||||
|
.to_local_range(),
|
||||||
parent: lsp_range.map(Box::new),
|
parent: lsp_range.map(Box::new),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ use crate::server::api::traits::{
|
||||||
use crate::session::DocumentSnapshot;
|
use crate::session::DocumentSnapshot;
|
||||||
use crate::session::client::Client;
|
use crate::session::client::Client;
|
||||||
use lsp_types::{SemanticTokens, SemanticTokensRangeParams, SemanticTokensRangeResult, Url};
|
use lsp_types::{SemanticTokens, SemanticTokensRangeParams, SemanticTokensRangeResult, Url};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
pub(crate) struct SemanticTokensRangeRequestHandler;
|
pub(crate) struct SemanticTokensRangeRequestHandler;
|
||||||
|
|
@ -39,13 +38,11 @@ impl BackgroundDocumentRequestHandler for SemanticTokensRangeRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
|
|
||||||
// Convert LSP range to text offsets
|
// Convert LSP range to text offsets
|
||||||
let requested_range = params
|
let requested_range =
|
||||||
.range
|
params
|
||||||
.to_text_range(&source, &line_index, snapshot.encoding());
|
.range
|
||||||
|
.to_text_range(db, file, snapshot.url(), snapshot.encoding());
|
||||||
|
|
||||||
let lsp_tokens = generate_semantic_tokens(
|
let lsp_tokens = generate_semantic_tokens(
|
||||||
db,
|
db,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ use lsp_types::{
|
||||||
Documentation, ParameterInformation, ParameterLabel, SignatureHelp, SignatureHelpParams,
|
Documentation, ParameterInformation, ParameterLabel, SignatureHelp, SignatureHelpParams,
|
||||||
SignatureInformation, Url,
|
SignatureInformation, Url,
|
||||||
};
|
};
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
use ty_ide::signature_help;
|
use ty_ide::signature_help;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
||||||
|
|
@ -43,11 +42,10 @@ impl BackgroundDocumentRequestHandler for SignatureHelpRequestHandler {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let offset = params.text_document_position_params.position.to_text_size(
|
let offset = params.text_document_position_params.position.to_text_size(
|
||||||
&source,
|
db,
|
||||||
&line_index,
|
file,
|
||||||
|
snapshot.url(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@ use crate::server::api::traits::{
|
||||||
};
|
};
|
||||||
use crate::session::SessionSnapshot;
|
use crate::session::SessionSnapshot;
|
||||||
use crate::session::client::Client;
|
use crate::session::client::Client;
|
||||||
use crate::system::file_to_url;
|
|
||||||
use ruff_db::source::{line_index, source_text};
|
|
||||||
|
|
||||||
pub(crate) struct WorkspaceSymbolRequestHandler;
|
pub(crate) struct WorkspaceSymbolRequestHandler;
|
||||||
|
|
||||||
|
|
@ -41,23 +39,19 @@ impl BackgroundRequestHandler for WorkspaceSymbolRequestHandler {
|
||||||
for workspace_symbol_info in workspace_symbol_infos {
|
for workspace_symbol_info in workspace_symbol_infos {
|
||||||
let WorkspaceSymbolInfo { symbol, file } = workspace_symbol_info;
|
let WorkspaceSymbolInfo { symbol, file } = workspace_symbol_info;
|
||||||
|
|
||||||
// Get file information for URL conversion
|
|
||||||
let source = source_text(db, file);
|
|
||||||
let line_index = line_index(db, file);
|
|
||||||
|
|
||||||
// Convert file to URL
|
|
||||||
let Some(url) = file_to_url(db, file) else {
|
|
||||||
tracing::debug!("Failed to convert file to URL at {}", file.path(db));
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get position encoding from session
|
// Get position encoding from session
|
||||||
let encoding = snapshot.position_encoding();
|
let encoding = snapshot.position_encoding();
|
||||||
|
|
||||||
let lsp_symbol =
|
let Some(symbol) = convert_to_lsp_symbol_information(db, file, symbol, encoding)
|
||||||
convert_to_lsp_symbol_information(symbol, &url, &source, &line_index, encoding);
|
else {
|
||||||
|
tracing::debug!(
|
||||||
|
"Failed to convert symbol '{}' to LSP symbol information",
|
||||||
|
file.path(db)
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
all_symbols.push(lsp_symbol);
|
all_symbols.push(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use lsp_types::SemanticToken;
|
use lsp_types::SemanticToken;
|
||||||
use ruff_db::source::{line_index, source_text};
|
use ruff_db::source::source_text;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
use ty_ide::semantic_tokens;
|
use ty_ide::semantic_tokens;
|
||||||
use ty_project::ProjectDatabase;
|
use ty_project::ProjectDatabase;
|
||||||
|
|
@ -16,7 +16,6 @@ pub(crate) fn generate_semantic_tokens(
|
||||||
multiline_token_support: bool,
|
multiline_token_support: bool,
|
||||||
) -> Vec<SemanticToken> {
|
) -> Vec<SemanticToken> {
|
||||||
let source = source_text(db, file);
|
let source = source_text(db, file);
|
||||||
let line_index = line_index(db, file);
|
|
||||||
let semantic_token_data = semantic_tokens(db, file, range);
|
let semantic_token_data = semantic_tokens(db, file, range);
|
||||||
|
|
||||||
// Convert semantic tokens to LSP format
|
// Convert semantic tokens to LSP format
|
||||||
|
|
@ -25,7 +24,10 @@ pub(crate) fn generate_semantic_tokens(
|
||||||
let mut prev_start = 0u32;
|
let mut prev_start = 0u32;
|
||||||
|
|
||||||
for token in &*semantic_token_data {
|
for token in &*semantic_token_data {
|
||||||
let lsp_range = token.range().to_lsp_range(&source, &line_index, encoding);
|
let lsp_range = token
|
||||||
|
.range()
|
||||||
|
.as_lsp_range(db, file, encoding)
|
||||||
|
.to_local_range();
|
||||||
let line = lsp_range.start.line;
|
let line = lsp_range.start.line;
|
||||||
let character = lsp_range.start.character;
|
let character = lsp_range.start.character;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
//! Utility functions common to language server request handlers
|
//! Utility functions common to language server request handlers
|
||||||
//! that return symbol information.
|
//! that return symbol information.
|
||||||
|
|
||||||
use lsp_types::{SymbolInformation, SymbolKind, Url};
|
use lsp_types::{SymbolInformation, SymbolKind};
|
||||||
use ruff_source_file::LineIndex;
|
|
||||||
use ty_ide::SymbolInfo;
|
use ty_ide::SymbolInfo;
|
||||||
|
use ty_project::Db;
|
||||||
|
|
||||||
use crate::document::{PositionEncoding, ToRangeExt};
|
use crate::document::{PositionEncoding, ToRangeExt};
|
||||||
|
|
||||||
|
|
@ -27,24 +27,25 @@ pub(crate) fn convert_symbol_kind(kind: ty_ide::SymbolKind) -> SymbolKind {
|
||||||
|
|
||||||
/// Convert a `ty_ide` `SymbolInfo` to LSP `SymbolInformation`
|
/// Convert a `ty_ide` `SymbolInfo` to LSP `SymbolInformation`
|
||||||
pub(crate) fn convert_to_lsp_symbol_information(
|
pub(crate) fn convert_to_lsp_symbol_information(
|
||||||
|
db: &dyn Db,
|
||||||
|
file: ruff_db::files::File,
|
||||||
symbol: SymbolInfo<'_>,
|
symbol: SymbolInfo<'_>,
|
||||||
uri: &Url,
|
|
||||||
source: &str,
|
|
||||||
line_index: &LineIndex,
|
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> SymbolInformation {
|
) -> Option<SymbolInformation> {
|
||||||
let symbol_kind = convert_symbol_kind(symbol.kind);
|
let symbol_kind = convert_symbol_kind(symbol.kind);
|
||||||
|
|
||||||
SymbolInformation {
|
let location = symbol
|
||||||
|
.full_range
|
||||||
|
.as_lsp_range(db, file, encoding)
|
||||||
|
.to_location()?;
|
||||||
|
|
||||||
|
Some(SymbolInformation {
|
||||||
name: symbol.name.into_owned(),
|
name: symbol.name.into_owned(),
|
||||||
kind: symbol_kind,
|
kind: symbol_kind,
|
||||||
tags: None,
|
tags: None,
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
deprecated: None,
|
deprecated: None,
|
||||||
location: lsp_types::Location {
|
location,
|
||||||
uri: uri.clone(),
|
|
||||||
range: symbol.full_range.to_lsp_range(source, line_index, encoding),
|
|
||||||
},
|
|
||||||
container_name: None,
|
container_name: None,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1028,6 +1028,11 @@ impl DocumentSnapshot {
|
||||||
&self.document
|
&self.document
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the URL of the document.
|
||||||
|
pub(crate) fn url(&self) -> &lsp_types::Url {
|
||||||
|
self.document.url()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn notebook(&self) -> Option<&NotebookDocument> {
|
pub(crate) fn notebook(&self) -> Option<&NotebookDocument> {
|
||||||
self.notebook.as_deref()
|
self.notebook.as_deref()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue