feat(shortcuts): keys for the two column verbs, and a better rule for why - #653
Merged
Conversation
… why Palette-only was the honest answer to the `Mod+Alt+C` collision and the wrong answer for the user. Reaching Insert Column meant `Mod+P`, typing the command's name, then Enter — three steps, and you have to remember what it is called, while both hands are in the middle of building a table. Insert Column Mod+Shift+C Delete Column Mod+Shift+Backspace THE RULE THAT DECIDES WHICH VERB GETS A KEY HAS CHANGED, and this is the part worth reading. `TABLE_VERBS_WITHOUT_A_CHORD` used to say destructive table verbs get no keys because a mis-fire costs too much. Delete Column destroys more than Delete Row does and is getting a key here, so that rule was not the one being applied. It is deleted rather than left sitting beside its replacement. What actually decides it is how hard the edit is BY HAND: Insert Row Mod+Enter / Mod+Shift+Enter, Tab at the last cell frequent Insert Column Mod+Shift+C mid-frequency, fiddly by hand Delete Column Mod+Shift+Backspace no manual fallback at all Delete Row palette only trivial by hand Deleting a row is putting the caret on the line, selecting it, deleting. Deleting a column is editing the pipes on every row without slipping once. The first needs no chord; the second has no other practical route. So the test for a new row in that table is now "can the user already do this without us", not "is it dangerous". The old hazard is gone in fact too: `Mod+Shift+K` is unbound on this branch and the `Mod+K` namespace no longer exists, so the near-neighbour that started this is not there. WHY BACKSPACE AND NOT A LETTER. `Mod+Shift+D` is free, but D is the physical neighbour of C — one slip would turn "insert a column" into "delete a column". A destructive verb does not go next to its constructive counterpart; that is the same defect as the old `Mod+K Shift+R` sitting one slip from Monaco's delete-line. Backspace is across the keyboard and already means "remove", so it needs no mnemonic. VERIFIED, NOT ASSUMED. Monaco's real keybinding registry dumped per platform under jsdom says `Shift+Meta+C` / `Ctrl+Shift+C` and `Shift+Meta+Backspace` / `Ctrl+Shift+Backspace` are unclaimed on all three, as complete chords and as chord prefixes. The only Monaco chords ending in C anywhere are `Alt+Meta+C` / `Alt+C` (toggleFindCaseSensitive) and `Mod+K Mod+C` (addCommentLine, behind a prefix this branch already ended); the nearest neighbour of the Backspace chord is `Mod+Backspace` (`deleteAllLeft`), an ordinary undoable edit. Also checked and free: the app's registry, every `addAction` and bare `addCommand` in `Editor.svelte`, the document handler in `MarkdownViewer.svelte` (which handles no Backspace or Delete at all), and the Rust menu, still claiming only `CmdOrCtrl+,` and `CmdOrCtrl+Q`. Nothing is taken from anyone, so no DELIBERATE_OVERRIDES row is needed. `Mod+Alt+C` IS NOW RECORDED where the next chord hunt happens, above DELIBERATE_OVERRIDES: it is `toggleFindCaseSensitive`, registered with `registerEditorCommand` rather than `registerEditorAction`, and only the latter contributes a `MenuId.CommandPalette` entry — so it has no palette fallback and can never be allow-listed, whatever the argument. Its `kbExpr` is a bare `EditorContextKeys.focus`, so it is live whenever the editor has focus, not only while the find widget is open. The same disqualification applies to `toggleFindWholeWord`, `toggleFindRegex` and `toggleFindInSelection`, registered identically, so the next person does not work through them one at a time. Tests: 903 pass, vitest 357, check 0 errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 12, 2026
PathGao
added a commit
that referenced
this pull request
Aug 12, 2026
…660) * docs: bring the release runbook and the syntax reference up to 2.7.4 Four claims in the docs describe behaviour that PRs since 2.7.3 changed, and two features shipped without reaching the file that documents what Markpad can do. RELEASING.md - snapcraft.yaml no longer builds the app; it unpacks the release's own .deb (#579), so the `npm ci` note and the `rust-deps` troubleshooting row both described a file that no longer exists in that shape (#577). - The .deb/.rpm coverage note still said *Check for Updates…* offers an update and then fails to install it. #573 asks `self_update_supported` first, so it says where updates come from instead. - Adds the AppImage checks (#584, #658) as their own troubleshooting row, and notes that release builds are serialized (#612). README, README.zh-CN - The same pre-#573 claim, in both languages. The Chinese one also told .deb/.rpm users to update "through their distribution channels", which is the sentence #566 removed from the English one — there is no apt or dnf repository. snapcraft.yaml - The comment pointed at .github/workflows/test_snap.yml, deleted in #601. samples/markdown-syntax{,.zh-CN}.md - Lists: Enter continues the marker, Tab changes level, Enter on an empty item leaves the list (#636), and the three list chords (#652). - Tables: cell, row and column keys, why deleting a row has no chord (#645, #653). - Links: Ctrl/Cmd+K (#652). npm test 904 pass, vitest 365 pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(syntax): drop two design arguments that belong in the PRs, not here The syntax reference carries no issue numbers, no history and no defence of a decision anywhere in its 500 lines; where it does give a reason -- the three deliberate incompatibilities -- the reason tells the reader what to write instead. Two sentences I added argued for the design at the reader: that four other editors use Mod+K, and why deleting a row has no chord while deleting a column does. Neither changes anything the reader would type. What is left of the second is the part that was actually useful: to delete a row, delete its line. * docs(readme): drop the only issue number a reader ever sees #570 was the last issue number in either README, and it was one I added a few days ago. It is a closed bug report, and after #573 the sentence it was attached to describes ordinary behaviour -- so a reader asking "how does my .deb update" now clicks through to a fault that no longer exists. The half-sentence in front of it went for the same reason: "rather than offering one it cannot install" describes what the app used to do. What is left is what the reader needs -- .deb and .rpm are one-time installs, there is no apt or dnf repository, and Check for Updates says so. Both READMEs keep the Report a Bug link, which is the only issue link either of them had before. * docs(releasing): cut the post-mortems back out of the runbook This file is what you read on the day you cut a release. Over three days in August I turned it into a runbook with post-mortems threaded through it: which run pushed Chocolatey 2.7.2 at 15:37, that the snap served 2.6.11 for three months and six versions, which two of the three v2.7.2 attempts the AppImage strip failed in, how the 2.7.2/2.7.3 lock skew was found. All true, none of it changes what you do next, and it sits between you and step 5 while a build is running. Test applied to each one: can it change an action taken on release day. Gone: the "Why package managers publish after the release" section entirely -- its one operational sentence (workflow_dispatch works against a published tag, the only way to exercise snapcraft.yaml) moves into step 7, where you would need it. The failure histories in three troubleshooting rows, keeping the symptom and the fix. The placeholder-pubkey era. Two design defences. Kept: reasons that stop you doing the wrong thing -- why not to create anything at alecdotdev/Markpad, why the Cargo.lock bump is the one that gets forgotten. A prohibition without its reason gets deleted as superstition by whoever comes next. 1957 -> 1563 words. The version before I started was 883. --------- Co-authored-by: PathGao <gaoyanbo@gaoyanbodeMacBook-Air.local> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#652 left both column verbs palette-only. Reaching one is
Cmd+P, then typing the command's name, then Enter — three steps, and you have to remember what it is called.Mod+Shift+CMod+Shift+BackspaceThe rule changed, so the old one is deleted rather than parked
TABLE_VERBS_WITHOUT_A_CHORDsaid, in effect, destructive table verbs get no keys, because a mis-fire costs too much. That cannot have been the rule being applied — Delete Column destroys strictly more than Delete Row, and it is the one getting a key.The distinction that actually holds is whether the user can already do it without us:
So Delete Column earns a key because there is no fallback; Delete Row does not, because a key buys nothing over what its user can already do.
TABLE_VERBS_WITHOUT_A_CHORDis down to that one row, and theWHY THE DESTRUCTIVE PAIR HAS NO CHORDblock inEditor.sveltewas rewritten to match — including that its original hazard is gone in fact, sinceMod+Shift+Kis unbound and theMod+Knamespace no longer exists.An "the asymmetry is itself a protection" paragraph added in an earlier round was removed, not amended: it argued the rule that has now been replaced, and leaving it would have been two rules standing side by side.
Why Backspace, when
Mod+Shift+Dis also freePhysical non-adjacency.
Dsits next toC; one slip would turn "insert a column" into "delete a column". A destructive verb should not neighbour its constructive counterpart — the same shape as the original complaint thatMod+K Shift+Rsat one slip from Monaco's delete-line. Backspace is across the keyboard and already means "remove" everywhere.That
Mod+Shift+Dis free is stated at the binding, so the next reader sees it was rejected deliberately rather than overlooked. Also noted there: the new chord's nearest neighbour isMod+Backspace(deleteAllLeft), one modifier away — an ordinary undoable edit rather than a structural one, so it does not disqualify the chord, but "one slip from" is the exact hazard class this rework is about and it belongs on the record.Two of my premises were wrong
I claimed
Mod+Shift+Deletewas taken byclipboard.jsandMod+Shift+YbyeditorExtensions.js. Both are free on all three platforms.clipboard.jsbindsShift+Deletewith no Mod — and per its own header binds nothing at all in a browser, sinceisNativeis false in a WebView.Ctrl+Yis redo on Windows and Linux, but without Shift.So Backspace was not forced by elimination. It stands on the adjacency argument above, which is the reason that was actually being applied.
Mod+Alt+Cstays recordedAbove
DELIBERATE_OVERRIDES, where the next chord hunt starts.toggleFindCaseSensitiveis aregisterEditorCommand, not aregisterEditorAction, so it has no command palette entry — taking its chord would leave it reachable only by clicking theAabutton, breaking the contract every override row rests on.Extended past that one command:
toggleFindWholeWord,toggleFindRegexandtoggleFindInSelectionare registered identically and are disqualified for the same reason, so nobody has to work through them one at a time.On coverage
No new
test()was added, and none was needed: the registry↔editor contract test is parameterised overSHORTCUTS, so adding a row is adding per-platform coverage. That is what produced the red.Same pair for
table-delete-column.npm test903 ·vitest357 ·check0 errors.🤖 Generated with Claude Code