Skip to content

In an "are you sure?" dialog, Enter can delete or discard if the wrong button has focus #483

Closed
1 of 1 issue completed

Description

@a-team-app

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.Tui 0.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+Enter confirms every dialog (the main action, Danger included), Enter never does, other actions keep their own key, and ConfirmDialog enforces it.
  • TuiCode's ConfirmView binds only Esc and leaves Enter to the focused button. KeybindingConflictDialog is 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

  1. 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.
  2. Patch ConfirmView in TuiCode. Add letter keys, make Enter do nothing, and draw filled buttons with AppButton. It's quick, but it's the TuiCode copy AGENTS.md rules out, and it would drift from Swatch. No.
  3. 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.
  4. Host the library's ConfirmDialog in TuiCode for every confirm. One implementation of the rule, shared with Swatch. The catch is that ConfirmDialog runs only under the library's AppShell, 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 without AppShell to run a ConfirmDialog and 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+Enter presses 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 / ButtonSecondary schemes.
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:

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.

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. ConfirmDialog is an AppDialog with its own commands and keys, while ConfirmView plugs into TuiCode's input-scope stack.

Activity

  1. added
    a-team:ideaFound by the a-team Lead; give it a Priority to have it pitched
    pitchAn a-team pitch: Lead shapes it, reviewer approves it
    on Oct 8, 2026
  2. a-team-app commented on Oct 9, 2026

    @a-team-app
    ContributorAuthor

    Pitched now: it out-ranks #375, which went back to Exploring.

    One change since drafting: Delivery now also names #482 (the MentalDesk.Tui 0.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.

  3. jamescrosswell commented on Oct 9, 2026

    @jamescrosswell
    Contributor
    • TuiCode needs ConfirmDialog to run and take keys without AppShell. I'm only cleared to write to TuiCode. Shall I file it on mentaldesk/tui-style-guide (that needs your OK)

    Yes go ahead.

  4. a-team-app commented on Oct 9, 2026

    @a-team-app
    ContributorAuthor

    Done: filed as mentaldesk/tui-style-guide#44. It asks for a way for an app without AppShell to run a ConfirmDialog and send keys to it, for example a public Scope or a Run that 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.

  5. jamescrosswell commented on Oct 10, 2026

    @jamescrosswell
    Contributor

    We're actually revising the guidance in the style guide repo:
    mentaldesk/tui-style-guide#53

  6. a-team-app commented on Oct 10, 2026

    @a-team-app
    ContributorAuthor

    Updated to follow tui-style-guide#53: Ctrl+Enter presses each confirm's main action (Danger included: Delete, Revert, Reload), other choices keep a letter (D Don't save, O/R on the changed-on-disk prompt), Esc cancels, 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.

  7. a-team-app commented on Oct 12, 2026

    @a-team-app
    ContributorAuthor

    One task: #524, the seven confirms on ConfirmDialog.

    It's labelled blocked: it can't start until tui-style-guide#44 (run a ConfirmDialog without AppShell) 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 remove blocked from #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.

  8. a-team-app commented on Oct 20, 2026

    @a-team-app
    ContributorAuthor

    Tried origin/main (52e6eac, with #582) in a scratch folder. I edited a file and pressed Ctrl+W. "Unsaved changes" came up with a filled Ctrl+Enter Save (Primary), a red Don't save (Danger) and Esc Cancel (Secondary), with Cancel focused. I moved focus to Don't save and pressed Enter, and nothing happened. D closed the tab without saving, and the file on disk was unchanged. #524 was the only task, so I'm closing this pitch as done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    a-team:ideaFound by the a-team Lead; give it a Priority to have it pitchedpitchAn a-team pitch: Lead shapes it, reviewer approves ittheme: Daily-driver gapsThe vision theme the a-team Lead says this pitch serves

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions