input: Fix some Rope method call will crash. (#1213)

This commit is contained in:
Jason Lee 2025-09-05 19:09:46 +08:00 committed by GitHub
parent cfc2449820
commit f35398d797
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 7 deletions

View file

@ -1,23 +1,40 @@
pub(crate) trait RopeExt {
/// Get the index of (line, column) (0-based) from the byte offset (0-based).
/// If the offset is out of bounds, return the last line and column.
///
/// If the `offset` is out of bounds, it returns (0, 0).
fn line_column(&self, byte_offset: usize) -> (usize, usize);
/// Get the byte offset (0-based) from the line, column (0-based).
///
/// Return the last line, if line is out of bounds.
/// Return the end column of line, if the column is out of bounds.
fn line_column_to_byte(&self, line_ix: usize, column_ix: usize) -> usize;
}
impl RopeExt for ropey::Rope {
fn line_column(&self, offset: usize) -> (usize, usize) {
let line_ix = self.byte_to_line(offset);
let line_offset = offset.saturating_sub(self.line_to_byte(line_ix));
let Ok(line_ix) = self.try_byte_to_line(offset) else {
return (0, 0);
};
let line = self.line(line_ix);
let column_ix = line.byte_to_char(line_offset);
let line_start_byte = self.line_to_byte(line_ix);
let line_offset = offset.saturating_sub(line_start_byte);
let column_ix = line
.try_byte_to_char(line_offset)
.unwrap_or(line.len_chars());
(line_ix, column_ix)
}
fn line_column_to_byte(&self, line_ix: usize, column_ix: usize) -> usize {
let line_ix = self.len_lines().saturating_sub(1).min(line_ix);
let line = self.line(line_ix);
self.line_to_byte(line_ix) + line.char_to_byte(column_ix)
self.line_to_byte(line_ix)
+ line
.try_char_to_byte(column_ix)
.unwrap_or(line.len_bytes().saturating_sub(1))
}
}

View file

@ -565,10 +565,18 @@ impl InputState {
let offset = self.cursor().offset;
let was_preferred_column = self.preferred_column;
let line_ix = self.text.byte_to_line(offset);
let Ok(line_ix) = self.text.try_byte_to_line(offset) else {
return;
};
let new_line_ix = line_ix.saturating_add_signed(move_lines);
let line = self.text.line(new_line_ix);
let line_start_offset = self.text.line_to_byte(new_line_ix);
let Some(line) = self.text.get_line(new_line_ix) else {
return;
};
let Ok(line_start_offset) = self.text.try_line_to_byte(new_line_ix) else {
return;
};
let new_column = self
.preferred_column
.unwrap_or_default()