feat(ui): add buffers HashMap for text input state management

Introduce a buffers HashMap to manage text input state across different
modes (command, edit, formula, category, export).

Changes:
- Added buffers field to GridWidget and updated constructor
- Updated draw_command_bar to use app.buffers instead of mode buffer
- Updated grid edit indicator to use buffers HashMap
- Added tests for command mode buffer behavior:
  * command_mode_typing_appends_to_buffer
  * command_mode_buffer_cleared_on_reentry

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/Qwen3.5-35B-A3B-GGUF:Q5_K_M)
This commit is contained in:
Edward Langley
2026-04-04 18:37:43 -07:00
parent 0f1de6ba58
commit 6c211e5421
3 changed files with 52 additions and 5 deletions

View File

@ -245,7 +245,7 @@ fn draw_content(f: &mut Frame, area: Rect, app: &App) {
}
f.render_widget(
GridWidget::new(&app.model, &app.mode, &app.search_query),
GridWidget::new(&app.model, &app.mode, &app.search_query, &app.buffers),
grid_area,
);
}
@ -256,7 +256,10 @@ fn draw_tile_bar(f: &mut Frame, area: Rect, app: &App) {
fn draw_bottom_bar(f: &mut Frame, area: Rect, app: &App) {
match app.mode {
AppMode::CommandMode { ref buffer } => draw_command_bar(f, area, buffer),
AppMode::CommandMode { .. } => {
let buf = app.buffers.get("command").map(|s| s.as_str()).unwrap_or("");
draw_command_bar(f, area, buf);
}
_ => draw_status(f, area, app),
}
}

View File

@ -290,4 +290,39 @@ mod tests {
"mode must not be Normal after import wizard is opened"
);
}
#[test]
fn command_mode_typing_appends_to_buffer() {
use crossterm::event::KeyEvent;
let mut app = two_col_model();
// Enter command mode with ':'
app.handle_key(KeyEvent::new(KeyCode::Char(':'), KeyModifiers::NONE))
.unwrap();
assert!(matches!(app.mode, AppMode::CommandMode { .. }));
assert_eq!(app.buffers.get("command").map(|s| s.as_str()), Some(""));
// Type 'q'
app.handle_key(KeyEvent::new(KeyCode::Char('q'), KeyModifiers::NONE))
.unwrap();
assert_eq!(app.buffers.get("command").map(|s| s.as_str()), Some("q"));
}
#[test]
fn command_mode_buffer_cleared_on_reentry() {
use crossterm::event::KeyEvent;
let mut app = two_col_model();
// Enter command mode, type something, escape
app.handle_key(KeyEvent::new(KeyCode::Char(':'), KeyModifiers::NONE))
.unwrap();
app.handle_key(KeyEvent::new(KeyCode::Char('x'), KeyModifiers::NONE))
.unwrap();
assert_eq!(app.buffers.get("command").map(|s| s.as_str()), Some("x"));
app.handle_key(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE))
.unwrap();
// Re-enter command mode — buffer should be cleared
app.handle_key(KeyEvent::new(KeyCode::Char(':'), KeyModifiers::NONE))
.unwrap();
assert_eq!(app.buffers.get("command").map(|s| s.as_str()), Some(""));
}
}

View File

@ -20,14 +20,21 @@ pub struct GridWidget<'a> {
pub model: &'a Model,
pub mode: &'a AppMode,
pub search_query: &'a str,
pub buffers: &'a std::collections::HashMap<String, String>,
}
impl<'a> GridWidget<'a> {
pub fn new(model: &'a Model, mode: &'a AppMode, search_query: &'a str) -> Self {
pub fn new(
model: &'a Model,
mode: &'a AppMode,
search_query: &'a str,
buffers: &'a std::collections::HashMap<String, String>,
) -> Self {
Self {
model,
mode,
search_query,
buffers,
}
}
@ -328,7 +335,8 @@ impl<'a> GridWidget<'a> {
// Edit indicator
if matches!(self.mode, AppMode::Editing { .. }) && ri == sel_row {
if let AppMode::Editing { buffer } = self.mode {
{
let buffer = self.buffers.get("edit").map(|s| s.as_str()).unwrap_or("");
let edit_x = area.x
+ ROW_HEADER_WIDTH
+ (sel_col.saturating_sub(col_offset)) as u16 * COL_WIDTH;
@ -522,7 +530,8 @@ mod tests {
fn render(model: &Model, width: u16, height: u16) -> Buffer {
let area = Rect::new(0, 0, width, height);
let mut buf = Buffer::empty(area);
GridWidget::new(model, &AppMode::Normal, "").render(area, &mut buf);
let bufs = std::collections::HashMap::new();
GridWidget::new(model, &AppMode::Normal, "", &bufs).render(area, &mut buf);
buf
}