From 63c6d007ae52038211d5c3742d57f75073bf51ad Mon Sep 17 00:00:00 2001 From: altair823 Date: Sat, 2 May 2026 13:31:19 +0000 Subject: [PATCH] =?UTF-8?q?review(p9-1):=20=ED=9A=8C=EC=B0=A8=201=20?= =?UTF-8?q?=EC=A7=80=EC=A0=81=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - p9-2/3/4 미머지 시점에 / ? Enter 키로 focus 가 Search/Ask/Inspect 로 옮겨가면 헤더만 바뀌고 본문은 Library 그대로 + 키 매핑도 Library 라 사용자에게 거짓말. footer hint 가 \"Search pane not yet implemented (lands with p9-2) — q to return\" 로 전환된다. 새 stub 핸들러 `handle_key_unimplemented_pane` 가 q / Esc 만 받아 Library 로 복귀, 나머지 키는 no-op (이전 구현은 handle_key_library 로 위임해서 focus 와 다른 pane state 가 mutate 되던 절뚝거림 차단). - `format_doc_row` 의 `{title: --- crates/kebab-tui/src/library.rs | 4 ++++ crates/kebab-tui/src/run.rs | 37 ++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/crates/kebab-tui/src/library.rs b/crates/kebab-tui/src/library.rs index f14fe84..ea74534 100644 --- a/crates/kebab-tui/src/library.rs +++ b/crates/kebab-tui/src/library.rs @@ -194,6 +194,10 @@ pub(crate) fn format_doc_row(d: &DocSummary, title_w: usize) -> String { .format(&time::format_description::well_known::Rfc3339) .unwrap_or_else(|_| "?".to_string()); let updated_short = updated.split('T').next().unwrap_or("?"); + // `` is std::fmt's named-arg width form (`title_w` is the + // named arg below; `$` says "use it as the padding width"). See + // https://doc.rust-lang.org/std/fmt/#width §"Width via named + // parameters". format!( "{title: Result<()> { let outcome = match app.focus { Pane::Library => handle_key_library(app, key), // p9-2/3/4 plug their handlers here as their - // crates land. Until then, any non-Library - // pane behaves like Library (we never switch - // to them at present). + // crates land. Until then, the non-Library + // panes accept only `q` / `Esc` to return — + // anything else is a no-op. The footer hint + // tells the user the pane is unimplemented. Pane::Search | Pane::Ask | Pane::Inspect | Pane::Jobs => { - handle_key_library(app, key) + handle_key_unimplemented_pane(app, key) } }; match outcome { @@ -67,6 +68,26 @@ pub(crate) fn run_loop(app: &mut App) -> Result<()> { Ok(()) } +/// Stub key handler for panes whose authoring task has not landed +/// yet. `q` / `Esc` returns to Library; everything else is a no-op. +/// Does NOT delegate to `handle_key_library` because that would let +/// `j` / `k` / `f` mutate Library state while focus says otherwise — +/// confusing UX. +fn handle_key_unimplemented_pane( + app: &mut App, + key: crossterm::event::KeyEvent, +) -> KeyOutcome { + use crossterm::event::KeyCode; + if app.error_overlay.is_some() { + app.error_overlay = None; + return KeyOutcome::Continue; + } + match key.code { + KeyCode::Char('q') | KeyCode::Esc => KeyOutcome::SwitchPane(Pane::Library), + _ => KeyOutcome::Continue, + } +} + fn render_root(f: &mut Frame, app: &App) { let outer = Layout::default() .direction(Direction::Vertical) @@ -110,6 +131,9 @@ fn render_header(f: &mut Frame, area: Rect, app: &App) { } fn render_footer(f: &mut Frame, area: Rect, app: &App) { + // p9-2/3/4 가 머지되기 전에는 SwitchPane(Search/Ask/Inspect) 가 + // focus 만 바꾸고 본문은 Library 가 그려지는 절뚝거림이 사용자에게 + // 보임. footer 에서 \"미구현\" 을 명시해 거짓말 안 함. let hints = match app.focus { Pane::Library => { if app.library.inner.filter_edit.is_some() { @@ -118,7 +142,10 @@ fn render_footer(f: &mut Frame, area: Rect, app: &App) { "j/k=move gg=top G=bottom f=filter /=search ?=ask Enter=inspect q=quit" } } - _ => "q=quit", + Pane::Search => "Search pane not yet implemented (lands with p9-2) — q to return", + Pane::Ask => "Ask pane not yet implemented (lands with p9-3) — q to return", + Pane::Inspect => "Inspect pane not yet implemented (lands with p9-4) — q to return", + Pane::Jobs => "Jobs pane not yet implemented — q to return", }; let line = Line::from(Span::styled( hints,