refactor: extract file-tree key handling into key_actions module (#2042)

* refactor: extract file-tree key handling into key_actions module

* refactor: simplify file_tree_key with early Esc return and let-else binding

* fix: address review comments on file-tree key_actions refactor

Restore file_tree_visible guard, remove stale KeyActionResult docs, unify format string style.
This commit is contained in:
Shen Bowen
2026-05-26 23:38:12 +08:00
committed by GitHub
parent d1b5cf6f1c
commit b6afb4c030
3 changed files with 62 additions and 41 deletions
+56
View File
@@ -0,0 +1,56 @@
//! Keyboard event action handlers extracted from `ui.rs`.
//!
//! Each function handles a focused subset of keyboard input so the
//! main event loop stays lean.
use crossterm::event::{KeyCode, KeyEvent};
use super::app::App;
// ── File-tree key handling ───────────────────────────────────────
/// Handle keyboard input when the file-tree pane is visible.
///
/// Returns `true` when the key was consumed (caller should `continue`).
pub fn handle_file_tree_key(app: &mut App, key: &KeyEvent) -> bool {
// Guard: do not intercept keys when the file-tree pane is not visible.
if !app.file_tree_visible {
return false;
}
// Esc closes the tree even when entries are still loading.
if key.code == KeyCode::Esc && app.file_tree.is_some() {
app.file_tree = None;
app.status_message = Some("File tree closed".to_string());
app.needs_redraw = true;
return true;
}
let Some(file_tree) = app.file_tree.as_mut() else {
return false;
};
match key.code {
KeyCode::Up => {
file_tree.cursor_up();
app.needs_redraw = true;
true
}
KeyCode::Down => {
file_tree.cursor_down();
app.needs_redraw = true;
true
}
KeyCode::Enter => {
if let Some(rel_path) = file_tree.activate() {
let path_str = rel_path.to_string_lossy().to_string();
app.status_message = Some(format!("Attached @{path_str}"));
app.insert_str(&format!("@{path_str} "));
} else {
app.needs_redraw = true;
}
true
}
_ => false,
}
}
+1
View File
@@ -35,6 +35,7 @@ pub mod footer_ui;
pub mod format_helpers;
pub mod frame_rate_limiter;
pub mod history;
pub mod key_actions;
pub mod key_shortcuts;
pub mod keybindings;
pub mod live_transcript;
+5 -41
View File
@@ -106,6 +106,8 @@ use crate::tui::views::subagent_view_agents;
use crate::tui::vim_mode;
use crate::tui::workspace_context;
use super::key_actions;
use super::app::{
App, AppAction, AppMode, OnboardingState, QueuedMessage, ReasoningEffort, SidebarFocus,
StatusToastLevel, SubmitDisposition, TaskPanelEntry, TuiOptions,
@@ -2772,47 +2774,9 @@ async fn run_event_loop(
continue;
}
// File-tree navigation: intercept keys when the file-tree pane is
// visible so Up/Down/Enter/Esc operate on the tree rather than
// falling through to composer or modal handlers.
if app.file_tree_visible {
match key.code {
KeyCode::Up => {
if let Some(state) = app.file_tree.as_mut() {
state.cursor_up();
}
app.needs_redraw = true;
continue;
}
KeyCode::Down => {
if let Some(state) = app.file_tree.as_mut() {
state.cursor_down();
}
app.needs_redraw = true;
continue;
}
KeyCode::Enter => {
if let Some(state) = app.file_tree.as_mut() {
if let Some(rel_path) = state.activate() {
// Insert @path into the composer.
let path_str = rel_path.to_string_lossy().to_string();
app.status_message = Some(format!("Attached @{path_str}"));
app.insert_str(&format!("@{path_str} "));
} else {
// Directory was expanded/collapsed; rebuild.
app.needs_redraw = true;
}
}
continue;
}
KeyCode::Esc => {
app.file_tree = None;
app.status_message = Some("File tree closed".to_string());
app.needs_redraw = true;
continue;
}
_ => {}
}
// File-tree navigation: delegated to key_actions module.
if key_actions::handle_file_tree_key(app, &key) {
continue;
}
if app.is_history_search_active() {