Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 23 additions & 33 deletions src/change.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,27 +172,13 @@ impl GridIndex {
///
/// If the row value of the [`GridIndex`] is same as the number of rows, this will insert a
/// line break.
pub fn normalize(&mut self, text: &mut Text) -> Result<()> {
let br_indexes = &mut text.br_indexes;
let mut row_count = br_indexes.row_count();
pub fn normalize(&mut self, text: &Text) -> Result<()> {
let br_indexes = &text.br_indexes;
let row_count = br_indexes.row_count();
if self.row == row_count.get() {
br_indexes.insert_index(self.row, br_indexes.last_row_start());
text.text.push('\n');
row_count = row_count.saturating_add(1);
return Err(Error::oob_row(row_count, self.row));
}

let row_start = br_indexes
.row_start(self.row)
.ok_or(Error::oob_row(row_count, self.row))?;
let pure_line = if !br_indexes.is_last_row(self.row) && row_count.get() > 1 {
let row_end = br_indexes
.row_start(self.row + 1)
.ok_or(Error::oob_row(row_count, self.row))?;
let base_line = &text.text[row_start..row_end];
trim_eol_from_end(base_line)
} else {
&text.text[row_start..]
};
let pure_line = resolve_pure_line(text, self.row)?;

self.col = (text.encoding[0])(pure_line, self.col)?;

Expand All @@ -201,20 +187,7 @@ impl GridIndex {

/// Transform the positions to the [`Text`]'s expected encoding, from UTF-8 positions.
pub fn denormalize(&mut self, text: &Text) -> Result<()> {
let br_indexes = &text.br_indexes;
let row_count = br_indexes.row_count();
let row_start = br_indexes
.row_start(self.row)
.ok_or(Error::oob_row(row_count, self.row))?;
let pure_line = if !br_indexes.is_last_row(self.row) && row_count.get() > 1 {
let row_end = br_indexes
.row_start(self.row + 1)
.ok_or(Error::oob_row(row_count, self.row))?;
let base_line = &text.text[row_start..row_end];
trim_eol_from_end(base_line)
} else {
&text.text[row_start..]
};
let pure_line = resolve_pure_line(text, self.row)?;

self.col = (text.encoding[1])(pure_line, self.col)?;

Expand All @@ -229,3 +202,20 @@ pub(crate) fn correct_positions(start: &mut GridIndex, end: &mut GridIndex) {
std::mem::swap(start, end);
}
}

/// Resolve the line content for the given row, trimming EOL for non-last rows.
pub(crate) fn resolve_pure_line(text: &Text, row: usize) -> Result<&str> {
let br_indexes = &text.br_indexes;
let row_count = br_indexes.row_count();
let row_start = br_indexes
.row_start(row)
.ok_or(Error::oob_row(row_count, row))?;
if !br_indexes.is_last_row(row) && row_count.get() > 1 {
let row_end = br_indexes
.row_start(row + 1)
.ok_or(Error::oob_row(row_count, row))?;
Ok(trim_eol_from_end(&text.text[row_start..row_end]))
} else {
Ok(&text.text[row_start..])
}
}
28 changes: 22 additions & 6 deletions src/core/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{
ops::Range,
};


use super::{
encodings::{EncodingFns, UTF16, UTF32, UTF8},
eol_indexes::EolIndexes,
Expand Down Expand Up @@ -888,6 +887,10 @@ mod tests {
}

mod replace {
use std::{borrow::Cow, num::NonZeroUsize};

use crate::error::Error;

use super::*;

#[test]
Expand Down Expand Up @@ -1107,14 +1110,25 @@ mod tests {
Text::new("SomeText\nSome Other Text\nSome somsoemesome\n wowoas \n\n".into());

assert_eq!(t.br_indexes, [0, 8, 24, 42, 51, 52]);
let err = t
.replace(
"Hello, World!\nBye World!",
GridIndex { row: 0, col: 0 },
GridIndex { row: 6, col: 0 },
&mut (),
)
.unwrap_err();
assert_eq!(err, Error::oob_row(NonZeroUsize::new(6).unwrap(), 6));
t.text.push('\n');
t.br_indexes
.insert_index(6, t.br_indexes.last_row_start());
t.replace(
"Hello, World!\nBye World!",
GridIndex { row: 0, col: 0 },
GridIndex { row: 6, col: 0 },
&mut (),
)
.unwrap();

assert_eq!(t.text, "Hello, World!\nBye World!");
assert_eq!(t.br_indexes, [0, 13]);
}
Expand Down Expand Up @@ -1149,14 +1163,16 @@ mod tests {
assert_eq!(t.br_indexes, [0, 17]);

// Second call - this previously panicked due to missing update_prep()
t.replace_full(Cow::Borrowed("Second replacement\nAnother line\nThird"), &mut ())
.unwrap();
t.replace_full(
Cow::Borrowed("Second replacement\nAnother line\nThird"),
&mut (),
)
.unwrap();
assert_eq!(t.text, "Second replacement\nAnother line\nThird");
assert_eq!(t.br_indexes, [0, 18, 31]);

// Third call to ensure stability
t.replace_full(Cow::Borrowed("Final"), &mut ())
.unwrap();
t.replace_full(Cow::Borrowed("Final"), &mut ()).unwrap();
assert_eq!(t.text, "Final");
assert_eq!(t.br_indexes, [0]);
}
Expand Down
14 changes: 14 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ impl Error {
current,
}
}

/// Check if the error is caused by a single missing newline
///
/// Some LSP servers and clients may assume an extra newline exists at the end.
/// In the majority of these cases the correct fix is to append an empty line to the string.
/// This function returns [`true`] if the error can be fixed/ignored by appending a newline.
#[inline]
pub fn is_missing_newline(self) -> bool {
if let Self::OutOfBoundsRow { max, current } = self {
max + 1 == current
} else {
false
}
}
}

impl std::error::Error for Error {}
Loading