fix some crashes

This commit is contained in:
alice pellerin
2026-03-22 16:05:01 -05:00
parent 86e13d5b01
commit 6f7c55f1d1
2 changed files with 32 additions and 31 deletions
+30 -28
View File
@@ -165,23 +165,23 @@ impl Buffer {
BufferAction::Save => self.save(), BufferAction::Save => self.save(),
BufferAction::CopySelectionOnNextLine => self.copy_selection_on_next_line(), BufferAction::CopySelectionOnNextLine => self.copy_selection_on_next_line(window_size),
BufferAction::RotateSelectionsBackward => self.rotate_selections_backward(), BufferAction::RotateSelectionsBackward => self.rotate_selections_backward(window_size),
BufferAction::RotateSelectionsForward => self.rotate_selections_forward(), BufferAction::RotateSelectionsForward => self.rotate_selections_forward(window_size),
BufferAction::KeepPrimarySelection => self.keep_primary_selection(), BufferAction::KeepPrimarySelection => self.keep_primary_selection(),
BufferAction::RemovePrimarySelection => self.remove_primary_selection(), BufferAction::RemovePrimarySelection => self.remove_primary_selection(),
BufferAction::SplitSelectionsInto1s => self.split_selections_into_size(1), BufferAction::SplitSelectionsInto1s => self.split_selections_into_size(1, window_size),
BufferAction::SplitSelectionsInto2s => self.split_selections_into_size(2), BufferAction::SplitSelectionsInto2s => self.split_selections_into_size(2, window_size),
BufferAction::SplitSelectionsInto3s => self.split_selections_into_size(3), BufferAction::SplitSelectionsInto3s => self.split_selections_into_size(3, window_size),
BufferAction::SplitSelectionsInto4s => self.split_selections_into_size(4), BufferAction::SplitSelectionsInto4s => self.split_selections_into_size(4, window_size),
BufferAction::SplitSelectionsInto5s => self.split_selections_into_size(5), BufferAction::SplitSelectionsInto5s => self.split_selections_into_size(5, window_size),
BufferAction::SplitSelectionsInto6s => self.split_selections_into_size(6), BufferAction::SplitSelectionsInto6s => self.split_selections_into_size(6, window_size),
BufferAction::SplitSelectionsInto7s => self.split_selections_into_size(7), BufferAction::SplitSelectionsInto7s => self.split_selections_into_size(7, window_size),
BufferAction::SplitSelectionsInto8s => self.split_selections_into_size(8), BufferAction::SplitSelectionsInto8s => self.split_selections_into_size(8, window_size),
BufferAction::SplitSelectionsInto9s => self.split_selections_into_size(9), BufferAction::SplitSelectionsInto9s => self.split_selections_into_size(9, window_size),
BufferAction::JumpToSelectedOffset => self.jump_to_selected_offset(window_size), BufferAction::JumpToSelectedOffset => self.jump_to_selected_offset(window_size),
BufferAction::JumpToSelectedOffsetRelativeToMark => self.jump_to_selected_offset_relative_to_mark(window_size), BufferAction::JumpToSelectedOffsetRelativeToMark => self.jump_to_selected_offset_relative_to_mark(window_size),
@@ -328,7 +328,7 @@ impl Buffer {
self.scroll_position = min( self.scroll_position = min(
self.scroll_position + window_size.visible_byte_count(), self.scroll_position + window_size.visible_byte_count(),
self.contents.len() - BYTES_OF_PADDING - self.contents.len() % BYTES_PER_LINE self.max_contents_index() - BYTES_OF_PADDING - self.max_contents_index() % BYTES_PER_LINE
); );
if window_size.hex_rows() > LINES_OF_PADDING * 2 { if window_size.hex_rows() > LINES_OF_PADDING * 2 {
@@ -445,7 +445,7 @@ impl Buffer {
); );
} }
fn copy_selection_on_next_line(&mut self) { fn copy_selection_on_next_line(&mut self, window_size: WindowSize) {
let new_cursors: Vec<Cursor> = iter::once(&self.primary_cursor) let new_cursors: Vec<Cursor> = iter::once(&self.primary_cursor)
.chain(&self.cursors) .chain(&self.cursors)
.filter_map(|cursor| { .filter_map(|cursor| {
@@ -470,10 +470,10 @@ impl Buffer {
self.combine_cursors_if_overlapping(); self.combine_cursors_if_overlapping();
self.rotate_selections_forward(); self.rotate_selections_forward(window_size);
} }
fn rotate_selections_backward(&mut self) { fn rotate_selections_backward(&mut self, window_size: WindowSize) {
if self.cursors.is_empty() { return; } if self.cursors.is_empty() { return; }
let next_cursor_index = self.cursors let next_cursor_index = self.cursors
@@ -489,9 +489,11 @@ impl Buffer {
} else { } else {
swap(&mut self.primary_cursor, &mut self.cursors[next_cursor_index - 1]); swap(&mut self.primary_cursor, &mut self.cursors[next_cursor_index - 1]);
} }
self.clamp_screen_to_primary_cursor(window_size);
} }
fn rotate_selections_forward(&mut self) { fn rotate_selections_forward(&mut self, window_size: WindowSize) {
if self.cursors.is_empty() { return; } if self.cursors.is_empty() { return; }
let next_cursor_index = self.cursors let next_cursor_index = self.cursors
@@ -505,6 +507,8 @@ impl Buffer {
} else { } else {
swap(&mut self.primary_cursor, &mut self.cursors[next_cursor_index]); swap(&mut self.primary_cursor, &mut self.cursors[next_cursor_index]);
} }
self.clamp_screen_to_primary_cursor(window_size);
} }
fn keep_primary_selection(&mut self) { fn keep_primary_selection(&mut self) {
@@ -525,7 +529,7 @@ impl Buffer {
} }
} }
fn split_selections_into_size(&mut self, size: usize) { fn split_selections_into_size(&mut self, size: usize, window_size: WindowSize) {
if !iter::once(&self.primary_cursor) if !iter::once(&self.primary_cursor)
.chain(&self.cursors) .chain(&self.cursors)
.all(|cursor| cursor.len().is_multiple_of(size)) .all(|cursor| cursor.len().is_multiple_of(size))
@@ -547,6 +551,8 @@ impl Buffer {
self.primary_cursor = new_cursors.next().unwrap(); self.primary_cursor = new_cursors.next().unwrap();
self.cursors = new_cursors.collect(); self.cursors = new_cursors.collect();
self.clamp_screen_to_primary_cursor(window_size);
} }
fn jump_to_selected_offset(&mut self, window_size: WindowSize) { fn jump_to_selected_offset(&mut self, window_size: WindowSize) {
@@ -769,12 +775,8 @@ impl Buffer {
.map(|int| Span::from(format!("{int}")).white()); .map(|int| Span::from(format!("{int}")).white());
let utf8 = str::from_utf8(selection).ok() let utf8 = str::from_utf8(selection).ok()
.and_then(|utf8| { .map(|utf8| utf8.trim_suffix('\0'))
utf8 .filter(|utf8| !utf8.contains(is_illegal_control_character))
.contains(character_is_allowed_in_strings)
.then_some(utf8)
})
.map(|utf8| utf8.replace('\0', "\\0"))
.map(|utf8| Span::from(format!("\"{utf8}\"")).red()); .map(|utf8| Span::from(format!("\"{utf8}\"")).red());
#[allow(clippy::cast_precision_loss)] #[allow(clippy::cast_precision_loss)]
@@ -927,10 +929,10 @@ fn mark_after(offset: usize, sorted_marks: &[usize], max: usize) -> usize {
} }
} }
const fn character_is_allowed_in_strings(character: char) -> bool { const fn is_illegal_control_character(character: char) -> bool {
match character { match character {
'\0' | '\t' | '\n' | '\r' => true, '\t' | '\n' | '\r' => false,
_ if character.is_ascii_control() => false, _ if character.is_ascii_control() => true,
_ => true, _ => false,
} }
} }
+2 -3
View File
@@ -3,6 +3,7 @@
#![feature(get_disjoint_mut_helpers)] #![feature(get_disjoint_mut_helpers)]
#![feature(exact_bitshifts)] #![feature(exact_bitshifts)]
#![feature(hash_set_entry)] #![feature(hash_set_entry)]
#![feature(trim_prefix_suffix)]
use app::App; use app::App;
use crossterm::{QueueableCommand, event::{DisableMouseCapture, EnableMouseCapture}}; use crossterm::{QueueableCommand, event::{DisableMouseCapture, EnableMouseCapture}};
@@ -26,13 +27,11 @@ const LINES_OF_PADDING: usize = 5;
const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE; const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE;
// TODO: // TODO:
// - 4 with large selection crashes
// - also ( and )
// - also C-F in excavate_defs
// - search // - search
// - ascii and bytes (`/` and `A-/`?) // - ascii and bytes (`/` and `A-/`?)
// - diffing // - diffing
// - s/A-k/A-K // - s/A-k/A-K
// - sm select marks
// - C-a/C-x // - C-a/C-x
// - modifications // - modifications
// - insert/append // - insert/append