Skip to content

Commit 9ef2967

Browse files
committed
fix: 'q' and '?' keys now work correctly during FilterInput mode
- Extract key handling from main.rs into App::handle_key() method - FilterInput mode routes all chars to input buffer before global handlers - Previously 'q' quit the app and '?' toggled help even while typing tags - Import AppMode in ui.rs to replace 8 full crate path references - main.rs reduced from 151 to 97 lines
1 parent 57e87d9 commit 9ef2967

3 files changed

Lines changed: 72 additions & 70 deletions

File tree

src/main.rs

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -70,61 +70,7 @@ async fn main() -> Result<()> {
7070

7171
if let Some(event) = event_handler.next().await {
7272
match event {
73-
Event::Key(key) => {
74-
match key.code {
75-
crossterm::event::KeyCode::Char('?') => {
76-
if app.mode != tui::app::AppMode::Help {
77-
app.mode = tui::app::AppMode::Help;
78-
} else {
79-
app.mode = tui::app::AppMode::CommandSelection; // Or back to previous?
80-
}
81-
}
82-
crossterm::event::KeyCode::Char('q') => app.should_quit = true,
83-
crossterm::event::KeyCode::Up | crossterm::event::KeyCode::Char('k') => {
84-
match app.mode {
85-
tui::app::AppMode::CommandSelection => app.previous_command(),
86-
tui::app::AppMode::ResultsView => app.previous_result(),
87-
_ => {}
88-
}
89-
}
90-
crossterm::event::KeyCode::Down | crossterm::event::KeyCode::Char('j') => {
91-
match app.mode {
92-
tui::app::AppMode::CommandSelection => app.next_command(),
93-
tui::app::AppMode::ResultsView => app.next_result(),
94-
_ => {}
95-
}
96-
}
97-
crossterm::event::KeyCode::Enter => match app.mode {
98-
tui::app::AppMode::CommandSelection => app.select_command(),
99-
tui::app::AppMode::FilterInput => app.execute_search().await,
100-
_ => {}
101-
},
102-
crossterm::event::KeyCode::Esc => match app.mode {
103-
tui::app::AppMode::CommandSelection => app.should_quit = true,
104-
tui::app::AppMode::FilterInput => {
105-
app.error_message = None;
106-
app.mode = tui::app::AppMode::CommandSelection;
107-
}
108-
tui::app::AppMode::ResultsView => {
109-
app.error_message = None;
110-
app.mode = tui::app::AppMode::CommandSelection;
111-
}
112-
_ => app.mode = tui::app::AppMode::CommandSelection,
113-
},
114-
// FilterInput text entry
115-
crossterm::event::KeyCode::Char(c)
116-
if app.mode == tui::app::AppMode::FilterInput =>
117-
{
118-
app.input_buffer.push(c);
119-
}
120-
crossterm::event::KeyCode::Backspace
121-
if app.mode == tui::app::AppMode::FilterInput =>
122-
{
123-
app.input_buffer.pop();
124-
}
125-
_ => {}
126-
}
127-
}
73+
Event::Key(key) => app.handle_key(key).await,
12874
Event::Tick => app.tick(),
12975
}
13076
}

src/tui/app.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::conductor::Conductor;
22
use crate::models::manager::RunnerManager;
33
use crate::models::runner::Runner;
4+
use crossterm::event::{KeyCode, KeyEvent};
45
use ratatui::widgets::TableState;
56

67
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
@@ -258,6 +259,67 @@ impl App {
258259
self.advance_spinner();
259260
}
260261
}
262+
263+
pub async fn handle_key(&mut self, key: KeyEvent) {
264+
// FilterInput mode: route all chars/backspace to input buffer first
265+
if self.mode == AppMode::FilterInput {
266+
match key.code {
267+
KeyCode::Enter => self.execute_search().await,
268+
KeyCode::Esc => {
269+
self.error_message = None;
270+
self.mode = AppMode::CommandSelection;
271+
}
272+
KeyCode::Backspace => {
273+
self.input_buffer.pop();
274+
}
275+
KeyCode::Char(c) => {
276+
self.input_buffer.push(c);
277+
}
278+
_ => {}
279+
}
280+
return;
281+
}
282+
283+
// Help mode: any key closes help
284+
if self.mode == AppMode::Help {
285+
self.mode = AppMode::CommandSelection;
286+
return;
287+
}
288+
289+
// CommandSelection and ResultsView modes
290+
match key.code {
291+
KeyCode::Char('?') => {
292+
self.mode = AppMode::Help;
293+
}
294+
KeyCode::Char('q') => {
295+
self.should_quit = true;
296+
}
297+
KeyCode::Up | KeyCode::Char('k') => match self.mode {
298+
AppMode::CommandSelection => self.previous_command(),
299+
AppMode::ResultsView => self.previous_result(),
300+
_ => {}
301+
},
302+
KeyCode::Down | KeyCode::Char('j') => match self.mode {
303+
AppMode::CommandSelection => self.next_command(),
304+
AppMode::ResultsView => self.next_result(),
305+
_ => {}
306+
},
307+
KeyCode::Enter => {
308+
if self.mode == AppMode::CommandSelection {
309+
self.select_command();
310+
}
311+
}
312+
KeyCode::Esc => match self.mode {
313+
AppMode::CommandSelection => self.should_quit = true,
314+
AppMode::ResultsView => {
315+
self.error_message = None;
316+
self.mode = AppMode::CommandSelection;
317+
}
318+
_ => self.mode = AppMode::CommandSelection,
319+
},
320+
_ => {}
321+
}
322+
}
261323
}
262324

263325
#[cfg(test)]

src/tui/ui.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::tui::app::{App, ResultsViewType};
1+
use crate::tui::app::{App, AppMode, ResultsViewType};
22
use ratatui::{
33
layout::{Constraint, Direction, Layout, Rect},
44
style::{Color, Modifier, Style},
@@ -40,27 +40,21 @@ pub fn render(app: &mut App, frame: &mut Frame) {
4040

4141
// Content based on mode
4242
match app.mode {
43-
crate::tui::app::AppMode::CommandSelection => {
44-
render_command_selection(app, frame, chunks[1])
45-
}
46-
crate::tui::app::AppMode::FilterInput => render_filter_input(app, frame, chunks[1]),
47-
crate::tui::app::AppMode::ResultsView => render_results(app, frame, chunks[1]),
48-
crate::tui::app::AppMode::Help => render_help_view(app, frame, chunks[1]),
43+
AppMode::CommandSelection => render_command_selection(app, frame, chunks[1]),
44+
AppMode::FilterInput => render_filter_input(app, frame, chunks[1]),
45+
AppMode::ResultsView => render_results(app, frame, chunks[1]),
46+
AppMode::Help => render_help_view(app, frame, chunks[1]),
4947
};
5048

5149
// Status bar with context-sensitive help
5250
let status_text = if app.error_message.is_some() {
5351
"Press Esc to dismiss error and go back"
5452
} else {
5553
match app.mode {
56-
crate::tui::app::AppMode::CommandSelection => {
57-
"↑/↓: Navigate | Enter: Select | ?: Help | q: Quit"
58-
}
59-
crate::tui::app::AppMode::FilterInput => {
60-
"Enter: Search | Esc: Back | Type to filter by tags"
61-
}
62-
crate::tui::app::AppMode::ResultsView => "↑/↓: Scroll | Esc: Back | q: Quit",
63-
crate::tui::app::AppMode::Help => "Press any key to close help",
54+
AppMode::CommandSelection => "↑/↓: Navigate | Enter: Select | ?: Help | q: Quit",
55+
AppMode::FilterInput => "Enter: Search | Esc: Back | Type to filter by tags",
56+
AppMode::ResultsView => "↑/↓: Scroll | Esc: Back | q: Quit",
57+
AppMode::Help => "Press any key to close help",
6458
}
6559
};
6660
let status = Paragraph::new(status_text).block(Block::default().borders(Borders::ALL));

0 commit comments

Comments
 (0)