-
Notifications
You must be signed in to change notification settings - Fork 2.4k
feat: allow ctrl+d to exit the app (v0) #3594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -367,7 +367,6 @@ func LoadFromConfig(config *opencode.Config, customCommands []opencode.Command) | |
| Description: "last message", | ||
| Keybindings: parseBindings("ctrl+alt+g"), | ||
| }, | ||
|
|
||
| { | ||
| Name: MessagesCopyCommand, | ||
| Description: "copy message", | ||
|
|
@@ -388,7 +387,8 @@ func LoadFromConfig(config *opencode.Config, customCommands []opencode.Command) | |
| { | ||
| Name: AppExitCommand, | ||
| Description: "exit the app", | ||
| Keybindings: parseBindings("ctrl+c", "<leader>q"), | ||
| // NOTE: ctrl+c requires a double press to exit while ctrl+d requires a single press | ||
| Keybindings: parseBindings("ctrl+c", "ctrl+d", "<leader>q"), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Trigger: []string{"exit", "quit", "q"}, | ||
| }, | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -305,9 +305,14 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { | |
| } | ||
| } | ||
|
|
||
| // 8. Handle exit key debounce for app exit when using non-leader command | ||
| // 8. Handle immediate exit command both for empty and non-empty editor | ||
| exitCommand := a.app.Commands[commands.AppExitCommand] | ||
| if exitCommand.Matches(msg, a.app.IsLeaderSequence) { | ||
| if exitCommand.Matches(msg, a.app.IsLeaderSequence) && keyString == "ctrl+d" && a.editor.Length() == 0 { | ||
| return a, util.CmdHandler(commands.ExecuteCommandMsg(exitCommand)) | ||
| } | ||
|
|
||
| // 9. Handle exit key debounce for app exit when using non-leader command | ||
| if exitCommand.Matches(msg, a.app.IsLeaderSequence) && keyString != "ctrl+d" { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided a separate block was cleanest. |
||
| switch a.exitKeyState { | ||
| case ExitKeyIdle: | ||
| // First exit key press - start debounce timer | ||
|
|
@@ -324,22 +329,26 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { | |
| } | ||
| } | ||
|
|
||
| // 9. Check again for commands that don't require leader (excluding interrupt when busy and exit when in debounce) | ||
| // 10. Check again for commands that don't require leader (excluding interrupt when busy and exit when in debounce) | ||
| matches := a.app.Commands.Matches(msg, a.app.IsLeaderSequence) | ||
| if len(matches) > 0 { | ||
| if len(matches) > 0 && keyString != "ctrl+d" { | ||
| // Skip interrupt key if we're in debounce mode and app is busy | ||
| if interruptCommand.Matches(msg, a.app.IsLeaderSequence) && a.app.IsBusy() && a.interruptKeyState != InterruptKeyIdle { | ||
| return a, nil | ||
| } | ||
| // Skip ctrl+d immediate exit key if the editor has content. Allow editor update commands to handle it as forward delete. | ||
| if exitCommand.Matches(msg, a.app.IsLeaderSequence) && keyString == "ctrl+d" && a.editor.Length() > 0 { | ||
| return a, nil | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This allows the later fall through on next cycle into step 12 further below. |
||
| } | ||
| return a, util.CmdHandler(commands.ExecuteCommandsMsg(matches)) | ||
| } | ||
|
|
||
| // Fallback: suspend if ctrl+z is pressed and no user keybind matched | ||
| // 11. Fallback: suspend if ctrl+z is pressed and no user keybind matched | ||
| if keyString == "ctrl+z" { | ||
| return a, tea.Suspend | ||
| } | ||
|
|
||
| // 10. Fallback to editor. This is for other characters like backspace, tab, etc. | ||
| // 12. Fallback to editor. This is for other characters like backspace, tab, etc. | ||
| updatedEditor, cmd := a.editor.Update(msg) | ||
| a.editor = updatedEditor.(chat.EditorComponent) | ||
| return a, cmd | ||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated all locations the exit commands are enumerated