d93d3d534fe8
let Esc always step back and leave the view from the list, dropping a kept filter first, and stop unknown escape sequences counting as Esc (3.0.69)
- time
- 2026-09-26 13:35 UTC · 2 weeks ago
- machine
- Junes-MacBook-Pro.local
- agent
- claude-opus-5-5
- session
- history view
- parent
- 4806e6424ec3
↓ koh-d93d3d53.tar.gzatlas at this save
files changed6 files
VERSION+1 −1src/view/term.v+3 −1src/view/term_test.v+9 −0src/view/view.v+9 −1src/view/view_test.v+26 −0v.mod+1 −1src/view/term.v+3 −1
@@ -167,9 +167,11 @@167167 kind: .page_down168168 }169169 }170+ // Shift-tab, function keys, focus reports: not Esc, which would171+ // leave the view.170172 else {171173 Key{172- kind: .escape174+ kind: .unknown173175 }174176 }175177 }src/view/term_test.v+9 −0
@@ -27,3 +27,12 @@2727 assert decode('search'.bytes()).text == 'search'2828 assert decode('✦'.bytes()).text == '✦'2929 }30+31+// Now that Esc leaves the view, only a lone Esc may count as one: shift-tab,32+// function keys and focus reports must not close it.33+fn test_unknown_escape_sequences_are_not_esc() {34+ assert decode([u8(0x1b), u8(`[`), u8(`Z`)]).kind == .unknown35+ assert decode([u8(0x1b), u8(`O`), u8(`P`)]).kind == .unknown36+ assert decode([u8(0x1b), u8(`[`), u8(`I`)]).kind == .unknown37+ assert decode([u8(0x1b), u8(`x`)]).kind == .unknown38+}src/view/view.v+9 −1
@@ -168,6 +168,14 @@168168 session.mode = .detail169169 }170170 }171+ // Esc goes back one step: a kept search filter first, then the view.172+ .escape {173+ if session.screen.query == '' {174+ return true175+ }176+ session.screen.query = ''177+ session.screen.selected = 0178+ }171179 .rune {172180 match key.text {173181 'q' {@@ -531,7 +539,7 @@531539 '${action_word(session.pending.kind)} [${session.pending.save_id}]? y yes · n/esc cancel'532540 }533541 .list {534- '↑↓ nav · / search · tab mode · c copy · enter detail · q'542+ '↑↓ nav · / search · tab mode · c copy · enter detail · q/esc'535543 }536544 }537545 left := ' view: ${tab_name(session.screen.tab)} · ${hint}'src/view/view_test.v+26 −0
@@ -317,3 +317,29 @@317317 // The last block ends at the bottom of the body, right above the status bar.318318 assert lines.len - 2 - separators.last() <= 1319319 }320+321+// Esc always goes back one step, and from the list it leaves the view: first322+// it drops a kept search filter, then it exits, just as q does.323+fn test_esc_goes_back_or_exits_from_the_list() {324+ mut session := list_session([save('aaa', 'first', false)])325+ session.screen.query = 'fir'326+ assert !handle_key(mut session, unsafe { nil }, Key{ kind: .escape }, never_act)327+ assert session.screen.query == ''328+ assert handle_key(mut session, unsafe { nil }, Key{ kind: .escape }, never_act)329+}330+331+fn test_esc_steps_back_from_every_other_mode() {332+ mut session := list_session([save('aaa', 'first', false)])333+ handle_key(mut session, unsafe { nil }, Key{ kind: .enter }, never_act)334+ handle_key(mut session, unsafe { nil }, Key{ kind: .rune, text: 'f' }, never_act)335+ assert session.mode == .reason336+ handle_key(mut session, unsafe { nil }, Key{ kind: .escape }, never_act)337+ assert session.mode == .detail338+ handle_key(mut session, unsafe { nil }, Key{ kind: .rune, text: 'l' }, never_act)339+ assert session.mode == .confirm340+ handle_key(mut session, unsafe { nil }, Key{ kind: .escape }, never_act)341+ assert session.mode == .list342+ handle_key(mut session, unsafe { nil }, Key{ kind: .enter }, never_act)343+ handle_key(mut session, unsafe { nil }, Key{ kind: .escape }, never_act)344+ assert session.mode == .list345+}v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 name: 'koh3'3- version: '3.0.68'3+ version: '3.0.69'44 description: 'One SQLite file per repo, one line of history.'55 license: 'MIT'66 }