Replace row/column based Location with byte-offsets. (#3931)

This commit is contained in:
Micha Reiser 2023-04-26 20:11:02 +02:00 committed by GitHub
parent ee91598835
commit cab65b25da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
418 changed files with 6203 additions and 7040 deletions

View file

@ -1,11 +1,10 @@
use anyhow::Result;
use log::error;
use rustpython_parser::ast::Location;
use ruff_text_size::{TextRange, TextSize};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use ruff_python_ast::types::Range;
use crate::Fix;
#[derive(Debug, PartialEq, Eq)]
@ -24,18 +23,16 @@ pub struct DiagnosticKind {
#[derive(Debug, PartialEq, Eq)]
pub struct Diagnostic {
pub kind: DiagnosticKind,
pub location: Location,
pub end_location: Location,
pub range: TextRange,
pub fix: Fix,
pub parent: Option<Location>,
pub parent: Option<TextSize>,
}
impl Diagnostic {
pub fn new<T: Into<DiagnosticKind>>(kind: T, range: Range) -> Self {
pub fn new<T: Into<DiagnosticKind>>(kind: T, range: TextRange) -> Self {
Self {
kind: kind.into(),
location: range.location,
end_location: range.end_location,
range,
fix: Fix::empty(),
parent: None,
}
@ -65,9 +62,21 @@ impl Diagnostic {
}
}
pub const fn range(&self) -> TextRange {
self.range
}
pub const fn start(&self) -> TextSize {
self.range.start()
}
pub const fn end(&self) -> TextSize {
self.range.end()
}
/// Set the location of the diagnostic's parent node.
#[inline]
pub fn set_parent(&mut self, parent: Location) {
pub fn set_parent(&mut self, parent: TextSize) {
self.parent = Some(parent);
}
}

View file

@ -1,49 +1,58 @@
use rustpython_parser::ast::Location;
use ruff_text_size::{TextRange, TextSize};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
/// A text edit to be applied to a source file. Inserts, deletes, or replaces
/// content at a given location.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Edit {
/// The start location of the edit.
location: Location,
/// The end location of the edit.
end_location: Location,
range: TextRange,
/// The replacement content to insert between the start and end locations.
content: Option<Box<str>>,
}
impl Edit {
/// Creates an edit that deletes the content in the `start` to `end` range.
pub const fn deletion(start: Location, end: Location) -> Self {
#[inline]
pub const fn deletion(start: TextSize, end: TextSize) -> Self {
Self::range_deletion(TextRange::new(start, end))
}
/// Creates an edit that deletes the content in `range`.
pub const fn range_deletion(range: TextRange) -> Self {
Self {
content: None,
location: start,
end_location: end,
range,
}
}
/// Creates an edit that replaces the content in the `start` to `end` range with `content`.
pub fn replacement(content: String, start: Location, end: Location) -> Self {
#[inline]
pub fn replacement(content: String, start: TextSize, end: TextSize) -> Self {
Self::range_replacement(content, TextRange::new(start, end))
}
/// Creates an edit that replaces the content in `range` with `content`.
pub fn range_replacement(content: String, range: TextRange) -> Self {
debug_assert!(!content.is_empty(), "Prefer `Fix::deletion`");
Self {
content: Some(Box::from(content)),
location: start,
end_location: end,
range,
}
}
/// Creates an edit that inserts `content` at the [`Location`] `at`.
pub fn insertion(content: String, at: Location) -> Self {
/// Creates an edit that inserts `content` at the [`TextSize`] `at`.
pub fn insertion(content: String, at: TextSize) -> Self {
debug_assert!(!content.is_empty(), "Insert content is empty");
Self {
content: Some(Box::from(content)),
location: at,
end_location: at,
range: TextRange::new(at, at),
}
}
@ -53,19 +62,23 @@ impl Edit {
}
/// Returns the start location of the edit in the source document.
pub const fn location(&self) -> Location {
self.location
pub const fn start(&self) -> TextSize {
self.range.start()
}
pub const fn range(&self) -> TextRange {
self.range
}
/// Returns the edit's end location in the source document.
pub const fn end_location(&self) -> Location {
self.end_location
pub const fn end(&self) -> TextSize {
self.range.end()
}
fn kind(&self) -> EditOperationKind {
if self.content.is_none() {
EditOperationKind::Deletion
} else if self.location == self.end_location {
} else if self.range.is_empty() {
EditOperationKind::Insertion
} else {
EditOperationKind::Replacement
@ -91,6 +104,21 @@ impl Edit {
}
}
impl Ord for Edit {
fn cmp(&self, other: &Self) -> Ordering {
self.start()
.cmp(&other.start())
.then_with(|| self.end().cmp(&other.end()))
.then_with(|| self.content.cmp(&other.content))
}
}
impl PartialOrd for Edit {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum EditOperationKind {
/// Edit that inserts new content into the source document.

View file

@ -1,4 +1,4 @@
use rustpython_parser::ast::Location;
use ruff_text_size::TextSize;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
@ -27,9 +27,9 @@ impl Fix {
self.edits.is_empty()
}
/// Return the [`Location`] of the first [`Edit`] in the [`Fix`].
pub fn min_location(&self) -> Option<Location> {
self.edits.iter().map(Edit::location).min()
/// Return the [`TextSize`] of the first [`Edit`] in the [`Fix`].
pub fn min_start(&self) -> Option<TextSize> {
self.edits.iter().map(Edit::start).min()
}
/// Return a slice of the [`Edit`] elements in the [`Fix`].