Repository navigation
In an "are you sure?" dialog, Enter can delete or discard if the wrong button has focus #483
Description
Opportunity
Every "are you sure?" in TuiCode starts with Cancel focused, but Enter presses whichever button has focus. A Tab or a mouse click moves focus onto Don't save, Overwrite, Reload, Delete or Revert, and the next Enter loses work. No choice has its own key, so the only way to pick one is Tab-Tab-Enter, which is exactly how the wrong one gets picked. And all the buttons are the same [ bracketed ] text, so the dangerous choice looks like the safe one.
It happens in the confirms you see most in a working day:
| Dialog | When | Destructive choice |
|---|---|---|
| Unsaved changes | closing a dirty tab | Don't save |
| Unsaved changes | quitting or opening another folder with dirty tabs | Don't save |
| File changed on disk | saving over a file that changed under you | Overwrite, Reload |
| Reload from disk | reloading a dirty tab | Reload |
| Delete | deleting from the explorer | Delete |
| Revert all changes | in a diff | Revert |
| Shortcut in use | rebinding a key in Settings | Replace |
Evidence:
MentalDesk.Tui0.2.2+ (Bump MentalDesk.Tui from 0.2.0 to 0.2.2 #482) carries the style guide's Dialog buttons rule (tui-style-guide#26, #30): Esc cancels. Left/Right or Tab move between buttons and Space presses one. Each action has its own key, shown on its button, that works without Alt. Enter is optional and never a Danger action. Buttons are filled Primary / Danger / Secondary blocks (#21, #23). Swatch's Theme › Close… and Delete… already work this way.- The guide is revising that rule in tui-style-guide#53:
Ctrl+Enterconfirms every dialog (the main action, Danger included),Enternever does, other actions keep their own key, andConfirmDialogenforces it. - TuiCode's
ConfirmViewbinds only Esc and leaves Enter to the focused button.KeybindingConflictDialogis a second, separate copy. - AGENTS.md: "Where the library has a type, use it rather than a TuiCode copy; a change it needs goes to the style guide first, as its own PR."
Options considered
- Leave it. Cancel-first focus already stops a stray Enter straight after the dialog opens. But it's no protection once focus has moved, picking a choice still means Tab-Enter, and TuiCode keeps disagreeing with the guide it's meant to follow. No.
- Patch
ConfirmViewin TuiCode. Add letter keys, make Enter do nothing, and draw filled buttons withAppButton. It's quick, but it's the TuiCode copy AGENTS.md rules out, and it would drift from Swatch. No. - Make the destructive actions undoable and drop the confirms. Delete to the Trash (Deleting a file in the explorer can't be taken back, even when git can't restore it #128), Revert is already undoable with Ctrl+Z, and so on. That's the better answer for delete, and Deleting a file in the explorer can't be taken back, even when git can't restore it #128 is pitched for it. But there's no undo for "Don't save" or "Overwrite", so the dialogs that matter most stay as they are. It doesn't solve this.
- Host the library's
ConfirmDialogin TuiCode for every confirm. One implementation of the rule, shared with Swatch. The catch is thatConfirmDialogruns only under the library'sAppShell, which TuiCode doesn't use; TuiCode has its own key-scope stack. So the library needs a small change first: a way for an app withoutAppShellto run aConfirmDialogand route keys to it. Chosen.
Proposal
Every confirm in the table becomes the library's ConfirmDialog, following the guide's revised rule (tui-style-guide#53):
Ctrl+Enterpresses the main action, shown on its button, key first. It's the same key that saves Settings and posts a review comment today.- Every other choice has its own key, shown on its button, that works without Alt. Esc cancels. Space presses the focused button; Left/Right and Tab move between them.
- Enter does nothing, whichever button has focus.
- Buttons are filled blocks: a safe main action is Primary, anything that throws work away is Danger (red), and Cancel is Secondary. Cancel still starts focused.
- TuiCode's four bundled themes gain the guide's
ButtonPrimary/ButtonDanger/ButtonSecondaryschemes.
| Dialog | Choices (key, kind) |
|---|---|
| Unsaved changes (close tab) | Ctrl+Enter Save (Primary) · D Don't save (Danger) · Esc Cancel |
| Unsaved changes (quit / open folder) | Ctrl+Enter Save all (Primary) · D Don't save (Danger) · Esc Cancel |
| File changed on disk | Ctrl+Enter Compare (Primary) · O Overwrite (Danger) · R Reload (Danger) · Esc Cancel |
| Reload from disk | Ctrl+Enter Reload (Danger) · Esc Cancel |
| Delete | Ctrl+Enter Delete (Danger) · Esc Cancel |
| Revert all changes | Ctrl+Enter Revert (Danger) · Esc Cancel |
| Shortcut in use | Ctrl+Enter Bind / Replace (Primary) · Esc Cancel |
Mockup
▓ … ▓ is a filled button (Primary accent, Danger red, Secondary muted); ▶ marks focus.
┌ Unsaved changes ──────────────────────────────────────────────────┐
│ Save changes to 'Program.cs' before closing? │
│ Your changes will be lost if you don't save them. │
│ │
│ ▓ Ctrl+Enter Save ▓ ▓ D Don't save ▓ ▶▓ Esc Cancel ▓ │ Button (Primary), Button (Danger), Button (Secondary)
└───────────────────────────────────────────────────────────────────┘
Ctrl+Enter saves and closes · D closes without saving · Esc cancels · Enter: nothing
┌ Delete ───────────────────────────────────────────────────┐
│ Permanently delete 'old-notes.md'? │
│ This action is irreversible! │
│ │
│ ▓ Ctrl+Enter Delete ▓ ▶▓ Esc Cancel ▓ │ Button (Danger), Button (Secondary)
└───────────────────────────────────────────────────────────┘
Scope
In: the seven dialogs above, including Settings' "Shortcut in use", switched to ConfirmDialog. The three button schemes added to every bundled theme. Updating AGENTS.md's description of the confirm.
Out:
- Buttons outside confirms (Document Info, the review comment box, Open Folder, the terminal-integration picker, Settings' "Conflict" OK box): I can't tell at a glance which button is the main action, which is destructive, or which has focus #484.
- Delete to the Trash: Deleting a file in the explorer can't be taken back, even when git can't restore it #128. Whichever lands second updates the Delete dialog's wording and kind.
- Making these keys rebindable. They're dialog navigation, like the find bar's keys.
- TuiCode's own Windows
Ctrl+LineFeedrewrite stays, since TuiCode doesn't run under the library'sAppShell.
Delivery
One TuiCode PR. It waits on two library changes being released: tui-style-guide#53 (ConfirmDialog confirms on Ctrl+Enter and refuses Enter) and tui-style-guide#44 (an app without AppShell can run a ConfirmDialog).
Decided
All the Lead's, accepted by the stakeholder when they approved the pitch.
- TuiCode follows Switch release publish to Native AOT #53 as pitched there. If Switch release publish to Native AOT #53 changes before it ships, this follows it.
- Danger main actions confirm on
Ctrl+Entertoo (Delete, Revert, Reload). A chord can't be pressed by accident, which is Switch release publish to Native AOT #53's reasoning; focus still never starts on Danger. - Compare is the main action when a file changed on disk: it loses nothing, and both other choices do.
- Cancel still starts focused, as today and as in Swatch.
Dfor Don't save, as in Swatch's Close.- Reload counts as Danger even when the tab has no unsaved edits. One kind per button is simpler to learn.
- Replace in "Shortcut in use" is Primary, not Danger. It overwrites one binding you can rebind straight away.
- I can't tell at a glance which button is the main action, which is destructive, or which has focus #484 stays a separate pitch. Whichever lands first adds the theme schemes.
Original idea
When TuiCode asks "are you sure?" (delete a file, discard unsaved changes, overwrite a file changed on disk, revert all changes in a diff), the only safe habit is to read which button has focus before pressing Enter. Cancel starts focused, but Tab or the mouse moves focus onto Delete, Don't save, Overwrite or Revert, and then Enter does the destructive thing. None of the choices has its own key, so the quick way out is always Tab-Tab-Enter, which is exactly the motion that goes wrong. The buttons are also all the same bracketed text, so a destructive choice doesn't look any different from a harmless one.
Notes from discovery: TuiCode bundles its own
themes.json, so the three button schemes need adding to every bundled theme.ConfirmDialogis anAppDialogwith its own commands and keys, whileConfirmViewplugs into TuiCode's input-scope stack.
Activity
a-team-app commentedon Oct 9, 2026
Pitched now: it out-ranks #375, which went back to Exploring.
One change since drafting: Delivery now also names #482 (the
MentalDesk.Tui0.2.2 bump), still open, as a prerequisite alongside the library change. The question under Needs your answer (who files the library change) still stands.jamescrosswell commentedon Oct 9, 2026
Yes go ahead.
a-team-app commentedon Oct 9, 2026
Done: filed as mentaldesk/tui-style-guide#44. It asks for a way for an app without
AppShellto run aConfirmDialogand send keys to it, for example a publicScopeor aRunthat takes TuiCode's own app and scope stack.In the pitch, that question has moved to Assumed and Delivery links #44. Nothing is waiting on you now. Once approved, the TuiCode task will wait on the release that carries #44 and on #482.
jamescrosswell commentedon Oct 10, 2026
We're actually revising the guidance in the style guide repo:
mentaldesk/tui-style-guide#53
a-team-app commentedon Oct 10, 2026
Updated to follow tui-style-guide#53:
Ctrl+Enterpresses each confirm's main action (Danger included: Delete, Revert, Reload), other choices keep a letter (DDon't save,O/Ron the changed-on-disk prompt),Esccancels, Enter does nothing. Mockups and table redrawn.It now waits on #53's release as well as #44. Compare is the main action on "File changed on disk", since it's the only choice that loses nothing.
a-team-app commentedon Oct 12, 2026
One task: #524, the seven confirms on
ConfirmDialog.It's labelled
blocked: it can't start until tui-style-guide#44 (run aConfirmDialogwithoutAppShell) ships in a MentalDesk.Tui release. #44 is still open and isn't on the tui team's board, so nothing is moving it. To unblock: put #44 on the tui board, then removeblockedfrom #524 once it's released. (#53, Ctrl+Enter, is done; #484's button schemes already landed in #506.)All of Assumed is now under Decided, as approved.
a-team-app commentedon Oct 20, 2026
Tried
origin/main(52e6eac, with #582) in a scratch folder. I edited a file and pressed Ctrl+W. "Unsaved changes" came up with a filledCtrl+Enter Save(Primary), a redDon't save(Danger) andEsc Cancel(Secondary), with Cancel focused. I moved focus to Don't save and pressed Enter, and nothing happened.Dclosed the tab without saving, and the file on disk was unchanged. #524 was the only task, so I'm closing this pitch as done.