fixed the multi-line note and some utf-8 stuff

This commit is contained in:
Hermes Agent
2026-08-16 19:42:44 +00:00
parent ba530a7271
commit b099157a17
5 changed files with 206 additions and 10 deletions

View File

@@ -24,6 +24,8 @@ pub struct InputState {
pub title: String,
pub value: String,
pub multiline: bool,
/// UTF-8 byte offset kept on a character boundary.
pub cursor: usize,
}
#[derive(Debug, Clone)]
@@ -237,11 +239,13 @@ impl App {
Ok(())
}
fn open_input(&mut self, kind: InputKind, title: &str, value: String, multiline: bool) {
let cursor = value.len();
self.mode = Mode::Input(InputState {
kind,
title: title.into(),
value,
multiline,
cursor,
});
}
fn edit_selected(&mut self) {
@@ -330,13 +334,22 @@ impl App {
return self.accept_input(input);
}
match key.code {
KeyCode::Enter if input.multiline => input.value.push('\n'),
KeyCode::Enter if input.multiline => insert_at_cursor(&mut input, '\n'),
KeyCode::Enter => return self.accept_input(input),
KeyCode::Backspace => {
input.value.pop();
KeyCode::Backspace => delete_before_cursor(&mut input),
KeyCode::Delete => delete_at_cursor(&mut input),
KeyCode::Left => input.cursor = previous_boundary(&input.value, input.cursor),
KeyCode::Right => input.cursor = next_boundary(&input.value, input.cursor),
KeyCode::Home => input.cursor = line_start(&input.value, input.cursor),
KeyCode::End => input.cursor = line_end(&input.value, input.cursor),
KeyCode::Up if input.multiline => move_cursor_vertically(&mut input, -1),
KeyCode::Down if input.multiline => move_cursor_vertically(&mut input, 1),
KeyCode::Char('a') if key.modifiers.contains(KeyModifiers::CONTROL) => input.cursor = 0,
KeyCode::Char('e') if key.modifiers.contains(KeyModifiers::CONTROL) => {
input.cursor = input.value.len()
}
KeyCode::Char(c) if !key.modifiers.contains(KeyModifiers::CONTROL) => {
input.value.push(c)
insert_at_cursor(&mut input, c)
}
_ => {}
}
@@ -810,3 +823,79 @@ fn normalize_date(value: &str) -> Option<String> {
fn inside(r: Rect, x: u16, y: u16) -> bool {
x >= r.x && x < r.x + r.width && y >= r.y && y < r.y + r.height
}
fn insert_at_cursor(input: &mut InputState, c: char) {
input.value.insert(input.cursor, c);
input.cursor += c.len_utf8();
}
fn delete_before_cursor(input: &mut InputState) {
let previous = previous_boundary(&input.value, input.cursor);
if previous != input.cursor {
input.value.drain(previous..input.cursor);
input.cursor = previous;
}
}
fn delete_at_cursor(input: &mut InputState) {
let next = next_boundary(&input.value, input.cursor);
if next != input.cursor {
input.value.drain(input.cursor..next);
}
}
fn previous_boundary(value: &str, cursor: usize) -> usize {
value[..cursor]
.char_indices()
.next_back()
.map_or(0, |(index, _)| index)
}
fn next_boundary(value: &str, cursor: usize) -> usize {
value[cursor..]
.chars()
.next()
.map_or(cursor, |c| cursor + c.len_utf8())
}
fn line_start(value: &str, cursor: usize) -> usize {
value[..cursor].rfind('\n').map_or(0, |index| index + 1)
}
fn line_end(value: &str, cursor: usize) -> usize {
value[cursor..]
.find('\n')
.map_or(value.len(), |index| cursor + index)
}
fn byte_at_character(value: &str, start: usize, end: usize, column: usize) -> usize {
value[start..end]
.char_indices()
.nth(column)
.map_or(end, |(offset, _)| start + offset)
}
fn move_cursor_vertically(input: &mut InputState, delta: isize) {
let start = line_start(&input.value, input.cursor);
let end = line_end(&input.value, input.cursor);
let column = input.value[start..input.cursor].chars().count();
input.cursor = if delta < 0 {
if start == 0 {
input.cursor
} else {
let target_end = start - 1;
let target_start = input.value[..target_end]
.rfind('\n')
.map_or(0, |index| index + 1);
byte_at_character(&input.value, target_start, target_end, column)
}
} else if end == input.value.len() {
input.cursor
} else {
let target_start = end + 1;
let target_end = input.value[target_start..]
.find('\n')
.map_or(input.value.len(), |index| target_start + index);
byte_at_character(&input.value, target_start, target_end, column)
};
}