mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-10 07:04:17 +00:00
fix(examples): changed user_input example to work with multi-byte unicode chars (#1069)
This is the proposed solution for issue #1068. It solves the bug in the user_input example with multi-byte UTF-8 characters as input. Fixes: #1068 --------- Co-authored-by: Josh McKinney <joshka@users.noreply.github.com>
This commit is contained in:
parent
20fc0ddfca
commit
4392759501
1 changed files with 25 additions and 13 deletions
|
@ -49,7 +49,7 @@ struct App {
|
|||
/// Current value of the input box
|
||||
input: String,
|
||||
/// Position of cursor in the editor area.
|
||||
cursor_position: usize,
|
||||
character_index: usize,
|
||||
/// Current input mode
|
||||
input_mode: InputMode,
|
||||
/// History of recorded messages
|
||||
|
@ -62,34 +62,46 @@ impl App {
|
|||
input: String::new(),
|
||||
input_mode: InputMode::Normal,
|
||||
messages: Vec::new(),
|
||||
cursor_position: 0,
|
||||
character_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn move_cursor_left(&mut self) {
|
||||
let cursor_moved_left = self.cursor_position.saturating_sub(1);
|
||||
self.cursor_position = self.clamp_cursor(cursor_moved_left);
|
||||
let cursor_moved_left = self.character_index.saturating_sub(1);
|
||||
self.character_index = self.clamp_cursor(cursor_moved_left);
|
||||
}
|
||||
|
||||
fn move_cursor_right(&mut self) {
|
||||
let cursor_moved_right = self.cursor_position.saturating_add(1);
|
||||
self.cursor_position = self.clamp_cursor(cursor_moved_right);
|
||||
let cursor_moved_right = self.character_index.saturating_add(1);
|
||||
self.character_index = self.clamp_cursor(cursor_moved_right);
|
||||
}
|
||||
|
||||
fn enter_char(&mut self, new_char: char) {
|
||||
self.input.insert(self.cursor_position, new_char);
|
||||
|
||||
let index = self.byte_index();
|
||||
self.input.insert(index, new_char);
|
||||
self.move_cursor_right();
|
||||
}
|
||||
|
||||
/// Returns the byte index based on the character position.
|
||||
///
|
||||
/// Since each character in a string can be contain multiple bytes, it's necessary to calculate
|
||||
/// the byte index based on the index of the character.
|
||||
fn byte_index(&mut self) -> usize {
|
||||
self.input
|
||||
.char_indices()
|
||||
.map(|(i, _)| i)
|
||||
.nth(self.character_index)
|
||||
.unwrap_or(self.input.len())
|
||||
}
|
||||
|
||||
fn delete_char(&mut self) {
|
||||
let is_not_cursor_leftmost = self.cursor_position != 0;
|
||||
let is_not_cursor_leftmost = self.character_index != 0;
|
||||
if is_not_cursor_leftmost {
|
||||
// Method "remove" is not used on the saved text for deleting the selected char.
|
||||
// Reason: Using remove on String works on bytes instead of the chars.
|
||||
// Using remove would require special care because of char boundaries.
|
||||
|
||||
let current_index = self.cursor_position;
|
||||
let current_index = self.character_index;
|
||||
let from_left_to_current_index = current_index - 1;
|
||||
|
||||
// Getting all characters before the selected character.
|
||||
|
@ -105,11 +117,11 @@ impl App {
|
|||
}
|
||||
|
||||
fn clamp_cursor(&self, new_cursor_pos: usize) -> usize {
|
||||
new_cursor_pos.clamp(0, self.input.len())
|
||||
new_cursor_pos.clamp(0, self.input.chars().count())
|
||||
}
|
||||
|
||||
fn reset_cursor(&mut self) {
|
||||
self.cursor_position = 0;
|
||||
self.character_index = 0;
|
||||
}
|
||||
|
||||
fn submit_message(&mut self) {
|
||||
|
@ -240,7 +252,7 @@ fn ui(f: &mut Frame, app: &App) {
|
|||
f.set_cursor(
|
||||
// Draw the cursor at the current position in the input field.
|
||||
// This position is can be controlled via the left and right arrow key
|
||||
input_area.x + app.cursor_position as u16 + 1,
|
||||
input_area.x + app.character_index as u16 + 1,
|
||||
// Move one line down, from the border to the input line
|
||||
input_area.y + 1,
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue