feat(kebab-tui): p9-fb-12 partial — Mode enum + global i/Esc + auto switch + status label #84

Merged
altair823 merged 2 commits from feat/p9-fb-12-mode into main 2026-05-03 07:29:06 +00:00
Owner

요약

도그푸딩 item 10 — vim-style NORMAL/INSERT mode 도입. 절반 ship: 사용자 가시 signal (mode label + auto flip + i/Esc global) 만, dispatch 의 input-empty heuristic 제거는 follow-up PR.

변경

  • Mode { Normal, Insert } + auto_for(pane) + label() + Default = Normal
  • App.mode: Mode field
  • run loop mode_intercept — Insert+Esc → Normal (어디서나), Normal+i → Insert (Library/Inspect/Jobs 만; Search/Ask 는 자동 Insert 라 i 가 typed char)
  • pane 전환Mode::auto_for(p) 자동 flip
  • status bar: header 우측 colored mode label (Insert=Success green, Normal=Heading cyan+bold)

Deferred → follow-up PR (HOTFIXES entry)

spec 의 "is_typing_mod (search) + input-empty heuristic (ask) 제거" 는 별 PR. 회귀 surface 좁게 유지. spec status in_progress 유지 (NOT completed).

테스트

  • 3 신규 unit (auto_for 5 pane, label 핀, default Normal)
  • 기존 98 TUI 테스트 모두 통과 (heuristic 유지라 회귀 0)
  • cargo test --workspace --no-fail-fast -j 1 exit 0
  • cargo clippy --workspace --all-targets -- -D warnings clean

문서

  • README kebab tui 행: vim mode + auto NORMAL/INSERT
  • HANDOFF entry (partial-ship 명시)
  • HOTFIXES entry (deferral 사유)
  • spec status planned → in_progress
## 요약 도그푸딩 item 10 — vim-style NORMAL/INSERT mode 도입. 절반 ship: 사용자 가시 signal (mode label + auto flip + i/Esc global) 만, dispatch 의 input-empty heuristic 제거는 follow-up PR. ## 변경 - **`Mode { Normal, Insert }`** + `auto_for(pane)` + `label()` + `Default = Normal` - **`App.mode: Mode`** field - **run loop `mode_intercept`** — Insert+Esc → Normal (어디서나), Normal+i → Insert (Library/Inspect/Jobs 만; Search/Ask 는 자동 Insert 라 i 가 typed char) - **pane 전환** 시 `Mode::auto_for(p)` 자동 flip - **status bar**: header 우측 colored mode label (Insert=Success green, Normal=Heading cyan+bold) ## Deferred → follow-up PR (HOTFIXES entry) spec 의 \"is_typing_mod (search) + input-empty heuristic (ask) 제거\" 는 별 PR. 회귀 surface 좁게 유지. spec status `in_progress` 유지 (NOT `completed`). ## 테스트 - 3 신규 unit (auto_for 5 pane, label 핀, default Normal) - 기존 98 TUI 테스트 모두 통과 (heuristic 유지라 회귀 0) - `cargo test --workspace --no-fail-fast -j 1` exit 0 - `cargo clippy --workspace --all-targets -- -D warnings` clean ## 문서 - README `kebab tui` 행: vim mode + auto NORMAL/INSERT - HANDOFF entry (partial-ship 명시) - HOTFIXES entry (deferral 사유) - spec status planned → in_progress
altair823 added 1 commit 2026-05-03 07:24:46 +00:00
도그푸딩 item 10 — vim 비익숙 사용자도 \"지금 키가 입력 vs 명령\" 명확히
구분 가능. 절반 ship: 사용자 가시 signal (mode label + auto flip + i/Esc
global) 만 land, 키 dispatch 의 input-empty heuristic 제거는 follow-up.

## 핵심 변경

- **`kebab_tui::Mode { Normal, Insert }`** enum + `Default = Normal`.
  - `Mode::label()` → `"-- NORMAL --"` / `"-- INSERT --"` (status bar
    문자열, 테스트로 핀).
  - `Mode::auto_for(pane)` → Library/Inspect/Jobs = Normal,
    Search/Ask = Insert. pane 전환 시 자동 적용.
- **`App.mode: Mode`** field. `App::new` 가 starting pane 의 auto
  mode 로 init.
- **run loop `mode_intercept(app, key)`** — pane dispatch 전에 호출:
  - Insert + `Esc` → Normal (어디서나, modifier 없음)
  - Normal + `i` (Library/Inspect/Jobs 만) → Insert
  - Search/Ask 의 `i` 는 fall-through (이미 Insert 라 typed char)
  - 그 외 fall-through
- **pane 전환 시** `app.mode = Mode::auto_for(p)` 자동 flip — 사용자가
  Tab 으로 Search 가면 자동으로 Insert.
- **status bar (header)** 에 mode label colored — Insert = Role::
  Success (green), Normal = Role::Heading (cyan + bold). a11y: 색은
  reinforcement, 글자가 authoritative signal.

## Deferred (HOTFIXES entry 추가)

spec p9-fb-12 의 \"기존 P9-3 ask 의 e/j/k input-empty heuristic 제거 —
mode 로 명확히\" 는 별 PR 로. 현재 dispatch 는 여전히:
- search.rs 의 `is_typing_mod` (SHIFT 만 typing 으로, CTRL/ALT 는 chord)
- ask.rs 의 input.is_empty() 가 e/j/k 를 navigation 으로 분기

테스트가 heuristic 에 의존해 있어, 회귀 surface 좁게 유지하려고 splitting.
spec status `in_progress` 유지 (not `completed`) — follow-up PR 가
heuristic 제거 + 완전 mode-authoritative 후 `completed` flip.

## 테스트

- 신규 3 unit (`Mode::auto_for` 모든 pane, label literals 핀,
  default = Normal)
- 기존 98 TUI 테스트 모두 통과 (heuristic 그대로라 회귀 0)
- workspace 전체 `cargo test --workspace --no-fail-fast -j 1` exit 0
- `cargo clippy --workspace --all-targets -- -D warnings` clean

## 문서

- README `kebab tui` 행: vim-style mode + auto NORMAL/INSERT + i/Esc
  안내
- HANDOFF entry (partial-ship 명시)
- HOTFIXES entry (heuristic 제거 deferral 사유)
- spec status planned → in_progress (NOT completed)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude-reviewer-01 requested changes 2026-05-03 07:26:06 +00:00
Dismissed
claude-reviewer-01 left a comment
Member

회차 1 — partial-ship 전략 합리적 (사용자 가시 signal 만 ship, heuristic 제거는 follow-up). HOTFIXES + spec status in_progress 유지로 deferred 부분 명시 깔끔. mode_intercept 의 modifier-aware filter (Ctrl+Esc 무시 등) 도 견고.

actionable nit 2 건 — (a) mode_intercept 동작 회귀 테스트 부재 (Mode enum 만 테스트, intercept 자체는 pin 안 됨), (b) auto_for 가 사용자 manual flip 을 pane 전환 시 덮어쓰는 동작에 doc 부재 — 의도된 트레이드오프임을 명시.

회차 1 — partial-ship 전략 합리적 (사용자 가시 signal 만 ship, heuristic 제거는 follow-up). HOTFIXES + spec status in_progress 유지로 deferred 부분 명시 깔끔. mode_intercept 의 modifier-aware filter (Ctrl+Esc 무시 등) 도 견고. actionable nit 2 건 — (a) mode_intercept 동작 회귀 테스트 부재 (Mode enum 만 테스트, intercept 자체는 pin 안 됨), (b) auto_for 가 사용자 manual flip 을 pane 전환 시 덮어쓰는 동작에 doc 부재 — 의도된 트레이드오프임을 명시.

신규 unit 테스트 3 건은 Mode enum 자체의 invariant 만 cover (auto_for / label / default). mode_intercept 의 실제 동작 (Insert+Esc → Normal, Normal+i → Insert in Library only, Search/Ask 에서 i fall-through, Ctrl+Esc 무시 등) 회귀 테스트가 없습니다.

현재 dispatch 가 run loop 안에 있어 직접 테스트 어렵지만, mode_interceptpub(crate) 로 노출하고 tests/mode.rs 에서 KeyEvent 직접 만들어 검증 가능. 5개 정도 (Esc-from-Insert, i-on-Library, i-on-Search-falls-through, Ctrl+Esc 무시, Esc-from-Normal noop) 면 spec 의 가시 contract pin.

선택: pub(crate) fn mode_intercept + tests/mode.rs 신규.

신규 unit 테스트 3 건은 `Mode` enum 자체의 invariant 만 cover (auto_for / label / default). `mode_intercept` 의 실제 동작 (Insert+Esc → Normal, Normal+i → Insert in Library only, Search/Ask 에서 i fall-through, Ctrl+Esc 무시 등) 회귀 테스트가 없습니다. 현재 dispatch 가 run loop 안에 있어 직접 테스트 어렵지만, `mode_intercept` 를 `pub(crate)` 로 노출하고 `tests/mode.rs` 에서 KeyEvent 직접 만들어 검증 가능. 5개 정도 (Esc-from-Insert, i-on-Library, i-on-Search-falls-through, Ctrl+Esc 무시, Esc-from-Normal noop) 면 spec 의 가시 contract pin. 선택: `pub(crate) fn mode_intercept` + `tests/mode.rs` 신규.
@@ -145,1 +156,4 @@
app.focus = p;
// p9-fb-12: auto-flip mode on switch.
// Library/Inspect/Jobs → Normal,
// Search/Ask → Insert. User can still

의도된 동작이지만 사용자 surprise 가능: pane 전환 시 Mode::auto_for(p) 가 사용자가 방금 Esc 로 manual flip 한 mode 를 덮어씁니다. 시나리오:

  1. Search 에서 Esc → Normal (user 의도: navigation)
  2. Tab → Library → Normal (자동, 의도와 일치)
  3. Tab → Ask → Insert (자동) ← user 의도와 어긋남

사용자 입장에서 "Esc 누르면 그 모드 sticky" 가 기대일 수 있습니다. v1 으로 자동 flip 이 합리적이지만 (Search/Ask 의 주 use case 가 typing), doc 으로 명시해두면 후속 사용자 피드백 시 의도된 트레이드오프임을 보여줄 수 있습니다.

제안: Mode::auto_for doc 또는 run loop pane-switch 분기 주석에:

// Auto-flip overrides any prior user-flipped mode on pane switch.
// Sticky mode (remember last user flip per pane) is a future task
// — current heuristic optimizes for the common case (Search/Ask =
// typing, others = navigation).
**의도된 동작이지만 사용자 surprise 가능**: pane 전환 시 `Mode::auto_for(p)` 가 사용자가 방금 `Esc` 로 manual flip 한 mode 를 덮어씁니다. 시나리오: 1. Search 에서 `Esc` → Normal (user 의도: navigation) 2. Tab → Library → Normal (자동, 의도와 일치) 3. Tab → Ask → Insert (자동) **← user 의도와 어긋남** 사용자 입장에서 "Esc 누르면 그 모드 sticky" 가 기대일 수 있습니다. v1 으로 자동 flip 이 합리적이지만 (Search/Ask 의 주 use case 가 typing), doc 으로 명시해두면 후속 사용자 피드백 시 의도된 트레이드오프임을 보여줄 수 있습니다. 제안: `Mode::auto_for` doc 또는 run loop pane-switch 분기 주석에: ``` // Auto-flip overrides any prior user-flipped mode on pane switch. // Sticky mode (remember last user flip per pane) is a future task // — current heuristic optimizes for the common case (Search/Ask = // typing, others = navigation). ```
altair823 added 1 commit 2026-05-03 07:28:45 +00:00
- `mode_intercept` 를 `pub` 로 노출 + `pub use run::mode_intercept`
  로 lib.rs export. 신규 `tests/mode.rs` 6 integration unit:
  - Esc-from-Insert flips to Normal on every pane (consumed)
  - Esc-from-Normal falls through (pane handler 가 처리 — Library
    의 quit signal 등 보존)
  - i-from-Normal on Library/Inspect/Jobs flips to Insert (consumed)
  - i-on-Search/Ask falls through (이미 Insert, i 가 typed char)
  - Ctrl/Alt modifier 는 intercept 안 함 (chord 가능)
  - Shift+Esc 는 toggle 됨 (modifier filter 가 SHIFT allow), Shift+I
    (capital) 는 fall-through (lowercase i 만 toggle 키)
- `Mode::auto_for` doc 에 \"auto-flip overrides user manual mode on
  pane switch\" 명시 — 의도된 트레이드오프 (typing 이 Search/Ask 의
  dominant case). sticky-per-pane 은 future task.

워크스페이스 clippy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude-reviewer-01 approved these changes 2026-05-03 07:29:02 +00:00
claude-reviewer-01 left a comment
Member

회차 2 — nit 2 건 깔끔히 반영.

  • mode_intercept pub + 6 신규 integration unit (Esc-from-Insert all panes / Esc-from-Normal fall-through / i-on-Library 등 / i-on-Search fall-through / Ctrl-Alt 무시 / Shift+Esc allowed Shift+I capital fall-through)
  • Mode::auto_for doc 에 'auto-flip overrides user manual on pane switch' 의도 명시 + sticky-per-pane 은 future task

추가 지적 없음. 머지 OK.

회차 2 — nit 2 건 깔끔히 반영. - mode_intercept pub + 6 신규 integration unit (Esc-from-Insert all panes / Esc-from-Normal fall-through / i-on-Library 등 / i-on-Search fall-through / Ctrl-Alt 무시 / Shift+Esc allowed Shift+I capital fall-through) - Mode::auto_for doc 에 'auto-flip overrides user manual on pane switch' 의도 명시 + sticky-per-pane 은 future task 추가 지적 없음. 머지 OK.
altair823 merged commit 39f20988d7 into main 2026-05-03 07:29:06 +00:00
altair823 deleted branch feat/p9-fb-12-mode 2026-05-03 07:29:07 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: altair823-org/kebab#84