diff --git a/crates/lore-tui/src/view/command_palette.rs b/crates/lore-tui/src/view/command_palette.rs index 4f73769..ee8b93a 100644 --- a/crates/lore-tui/src/view/command_palette.rs +++ b/crates/lore-tui/src/view/command_palette.rs @@ -9,6 +9,7 @@ use ftui::render::drawing::{BorderChars, Draw}; use ftui::render::frame::Frame; use crate::state::command_palette::CommandPaletteState; +use crate::text_width::cursor_cell_offset; use super::{ACCENT, BG_SURFACE, BORDER, TEXT, TEXT_MUTED}; @@ -16,14 +17,6 @@ fn text_cell_width(text: &str) -> u16 { text.chars().count().min(u16::MAX as usize) as u16 } -fn cursor_cell_offset(query: &str, cursor: usize) -> u16 { - let mut idx = cursor.min(query.len()); - while idx > 0 && !query.is_char_boundary(idx) { - idx -= 1; - } - text_cell_width(&query[..idx]) -} - // --------------------------------------------------------------------------- // render_command_palette // --------------------------------------------------------------------------- diff --git a/crates/lore-tui/src/view/file_history.rs b/crates/lore-tui/src/view/file_history.rs index 92de8f8..525489a 100644 --- a/crates/lore-tui/src/view/file_history.rs +++ b/crates/lore-tui/src/view/file_history.rs @@ -21,8 +21,9 @@ use ftui::render::cell::{Cell, PackedRgba}; use ftui::render::drawing::Draw; use ftui::render::frame::Frame; -use crate::state::file_history::{FileHistoryResult, FileHistoryState}; use super::common::truncate_str; +use crate::state::file_history::{FileHistoryResult, FileHistoryState}; +use crate::text_width::cursor_cell_offset; // --------------------------------------------------------------------------- // Colors (Flexoki palette) @@ -137,8 +138,7 @@ fn render_path_input(frame: &mut Frame<'_>, state: &FileHistoryState, x: u16, y: // Cursor indicator. if state.path_focused { - let cursor_col = state.path_input[..state.path_cursor].chars().count() as u16; - let cursor_x = after_label + cursor_col; + let cursor_x = after_label + cursor_cell_offset(&state.path_input, state.path_cursor); if cursor_x < max_x { let cursor_cell = Cell { fg: PackedRgba::rgb(0x10, 0x0F, 0x0F), // dark bg diff --git a/crates/lore-tui/src/view/search.rs b/crates/lore-tui/src/view/search.rs index 848c222..851d562 100644 --- a/crates/lore-tui/src/view/search.rs +++ b/crates/lore-tui/src/view/search.rs @@ -18,24 +18,11 @@ use ftui::core::geometry::Rect; use ftui::render::cell::Cell; use ftui::render::drawing::Draw; - -/// Count display-width columns for a string (char count, not byte count). -fn text_cell_width(text: &str) -> u16 { - text.chars().count().min(u16::MAX as usize) as u16 -} - -/// Convert a byte-offset cursor position to a display-column offset. -fn cursor_cell_offset(query: &str, cursor: usize) -> u16 { - let mut idx = cursor.min(query.len()); - while idx > 0 && !query.is_char_boundary(idx) { - idx -= 1; - } - text_cell_width(&query[..idx]) -} use ftui::render::frame::Frame; use crate::message::EntityKind; use crate::state::search::SearchState; +use crate::text_width::cursor_cell_offset; use super::{ACCENT, BG_SURFACE, BORDER, TEXT, TEXT_MUTED}; diff --git a/crates/lore-tui/src/view/trace.rs b/crates/lore-tui/src/view/trace.rs index 95cfea4..fe26dd4 100644 --- a/crates/lore-tui/src/view/trace.rs +++ b/crates/lore-tui/src/view/trace.rs @@ -135,8 +135,7 @@ fn render_path_input(frame: &mut Frame<'_>, state: &TraceState, x: u16, y: u16, // Cursor. if state.path_focused { - let cursor_col = state.path_input[..state.path_cursor].chars().count() as u16; - let cursor_x = after_label + cursor_col; + let cursor_x = after_label + cursor_cell_offset(&state.path_input, state.path_cursor); if cursor_x < max_x { let cursor_cell = Cell { fg: PackedRgba::rgb(0x10, 0x0F, 0x0F),