krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Commit 7ac0ac2c42

7ac0ac2c42ca19da5d3df70dfbf428ab08d1d95b

parent: 0b9419ea7c

Verified · cmc

cmc <hello@cleberg.net> · 2026-10-08 03:40 UTC

Report undefined leader sequences instead of replaying them

In Doom state, an unbound sequence after SPC, C-c or C-x shows
'... is undefined' and does nothing, rather than going to the Vim
engine key by key.

Layout: unified · split

Sources/OrgEditorAppKit/Modal.swift +6
@@ -36,6 +36,12 @@ extension OrgEditor {
3636 return feedVim(keys)
3737 case .undefined(let keys):
3838 onKeysPending?(nil, [])
39 // The leader and Emacs prefixes (C-c, C-x) mean nothing to evil: the sequence is
40 // undefined, as in Doom. Other prefixes (g, z, [, ]) are evil's too.
41 if let first = keys.first, first == KeyChord("SPC") || !first.modifiers.isDisjoint(with: [.control, .meta]) {
42 onMessage?("\(KeySequence.format(keys)) is undefined")
43 return true
44 }
3945 return feedVim(keys)
4046 case .unbound:
4147 return feedVim([chord])
Tests/OrgEditorAppKitTests/ModalTests.swift +19
@@ -72,6 +72,25 @@ struct ModalTests {
7272 #expect(h.editor.vim.mode == .normal)
7373 }
7474
75 @Test func undefinedLeaderSequencesDoNothing() {
76 let h = doom("* Task\nbody text\n")
77 var messages: [String] = []
78 h.editor.onMessage = { messages.append($0) }
79 h.caret(at: 0)
80 type(h, "SPC m z")
81 #expect(messages.last == "SPC m z is undefined")
82 #expect(h.textView.selectedRange().location == 0)
83 // No mark z was set: a jump to it fails and the caret stays.
84 type(h, "j ' z")
85 #expect(h.textView.selectedRange().location == 7)
86 type(h, "C-c z")
87 #expect(messages.last == "C-c z is undefined")
88 #expect(h.editor.document.text == "* Task\nbody text\n")
89 // Evil's own prefixes still reach it.
90 type(h, "g g")
91 #expect(h.textView.selectedRange().location == 0)
92 }
93
7594 @Test func keyHintsFollowContext() {
7695 let h = doom("* a\n#+begin_src sh\necho\n#+end_src\n")
7796 var hints: [(key: String, title: String)] = []