feat: add alt/option+esc binding to current esc key behavior

Max Justus Spransy created

This mimics the behavior of Claude Code and allows folks who use
Crush from within a terminal emulator that captures the escape key
(like Nvim's built in terminal emulator) to use it.

Change summary

internal/tui/components/chat/editor/editor.go      |  2 +-
internal/tui/components/chat/editor/keys.go        |  2 +-
internal/tui/components/chat/messages/messages.go  |  2 +-
internal/tui/components/chat/splash/keys.go        |  2 +-
internal/tui/components/completions/keys.go        |  2 +-
internal/tui/components/dialogs/commands/keys.go   |  2 +-
internal/tui/components/dialogs/compact/keys.go    |  2 +-
internal/tui/components/dialogs/filepicker/keys.go |  2 +-
internal/tui/components/dialogs/keys.go            |  2 +-
internal/tui/components/dialogs/models/keys.go     |  2 +-
internal/tui/components/dialogs/quit/keys.go       |  2 +-
internal/tui/components/dialogs/sessions/keys.go   |  2 +-
internal/tui/page/chat/chat.go                     | 14 +++++++-------
internal/tui/page/chat/keys.go                     |  2 +-
14 files changed, 20 insertions(+), 20 deletions(-)

Detailed changes

internal/tui/components/chat/editor/editor.go 🔗

@@ -75,7 +75,7 @@ var DeleteKeyMaps = DeleteAttachmentKeyMaps{
 		key.WithHelp("ctrl+r+{i}", "delete attachment at index i"),
 	),
 	Escape: key.NewBinding(
-		key.WithKeys("esc"),
+		key.WithKeys("esc", "alt+esc"),
 		key.WithHelp("esc", "cancel delete mode"),
 	),
 	DeleteAllAttachments: key.NewBinding(

internal/tui/components/chat/editor/keys.go 🔗

@@ -61,7 +61,7 @@ var AttachmentsKeyMaps = DeleteAttachmentKeyMaps{
 		key.WithHelp("ctrl+r+{i}", "delete attachment at index i"),
 	),
 	Escape: key.NewBinding(
-		key.WithKeys("esc"),
+		key.WithKeys("esc", "alt+esc"),
 		key.WithHelp("esc", "cancel delete mode"),
 	),
 	DeleteAllAttachments: key.NewBinding(

internal/tui/components/chat/messages/messages.go 🔗

@@ -29,7 +29,7 @@ import (
 var CopyKey = key.NewBinding(key.WithKeys("c", "y", "C", "Y"), key.WithHelp("c/y", "copy"))
 
 // ClearSelectionKey is the key binding for clearing the current selection in the chat interface.
-var ClearSelectionKey = key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "clear selection"))
+var ClearSelectionKey = key.NewBinding(key.WithKeys("esc", "alt+esc"), key.WithHelp("esc", "clear selection"))
 
 // MessageCmp defines the interface for message components in the chat interface.
 // It combines standard UI model interfaces with message-specific functionality.

internal/tui/components/chat/splash/keys.go 🔗

@@ -46,7 +46,7 @@ func DefaultKeyMap() KeyMap {
 			key.WithHelp("←/→", "switch"),
 		),
 		Back: key.NewBinding(
-			key.WithKeys("esc"),
+			key.WithKeys("esc", "alt+esc"),
 			key.WithHelp("esc", "back"),
 		),
 	}

internal/tui/components/completions/keys.go 🔗

@@ -28,7 +28,7 @@ func DefaultKeyMap() KeyMap {
 			key.WithHelp("enter", "select"),
 		),
 		Cancel: key.NewBinding(
-			key.WithKeys("esc"),
+			key.WithKeys("esc", "alt+esc"),
 			key.WithHelp("esc", "cancel"),
 		),
 		DownInsert: key.NewBinding(

internal/tui/components/dialogs/commands/keys.go 🔗

@@ -31,7 +31,7 @@ func DefaultCommandsDialogKeyMap() CommandsDialogKeyMap {
 			key.WithHelp("tab", "switch selection"),
 		),
 		Close: key.NewBinding(
-			key.WithKeys("esc"),
+			key.WithKeys("esc", "alt+esc"),
 			key.WithHelp("esc", "cancel"),
 		),
 	}

internal/tui/components/dialogs/keys.go 🔗

@@ -12,7 +12,7 @@ type KeyMap struct {
 func DefaultKeyMap() KeyMap {
 	return KeyMap{
 		Close: key.NewBinding(
-			key.WithKeys("esc"),
+			key.WithKeys("esc", "alt+esc"),
 		),
 	}
 }

internal/tui/components/dialogs/models/keys.go 🔗

@@ -34,7 +34,7 @@ func DefaultKeyMap() KeyMap {
 			key.WithHelp("tab", "toggle type"),
 		),
 		Close: key.NewBinding(
-			key.WithKeys("esc"),
+			key.WithKeys("esc", "alt+esc"),
 			key.WithHelp("esc", "cancel"),
 		),
 	}

internal/tui/components/dialogs/quit/keys.go 🔗

@@ -37,7 +37,7 @@ func DefaultKeymap() KeyMap {
 			key.WithHelp("tab", "switch options"),
 		),
 		Close: key.NewBinding(
-			key.WithKeys("esc"),
+			key.WithKeys("esc", "alt+esc"),
 			key.WithHelp("esc", "cancel"),
 		),
 	}

internal/tui/components/dialogs/sessions/keys.go 🔗

@@ -26,7 +26,7 @@ func DefaultKeyMap() KeyMap {
 			key.WithHelp("↑", "previous item"),
 		),
 		Close: key.NewBinding(
-			key.WithKeys("esc"),
+			key.WithKeys("esc", "alt+esc"),
 			key.WithHelp("esc", "cancel"),
 		),
 	}

internal/tui/page/chat/chat.go 🔗

@@ -766,7 +766,7 @@ func (p *chatPage) Bindings() []key.Binding {
 		cancelBinding := p.keyMap.Cancel
 		if p.isCanceling {
 			cancelBinding = key.NewBinding(
-				key.WithKeys("esc"),
+				key.WithKeys("esc", "alt+esc"),
 				key.WithHelp("esc", "press again to cancel"),
 			)
 		}
@@ -835,7 +835,7 @@ func (p *chatPage) Help() help.KeyMap {
 			shortList = append(shortList,
 				// Go back
 				key.NewBinding(
-					key.WithKeys("esc"),
+					key.WithKeys("esc", "alt+esc"),
 					key.WithHelp("esc", "back"),
 				),
 			)
@@ -870,7 +870,7 @@ func (p *chatPage) Help() help.KeyMap {
 					key.WithHelp("tab/enter", "complete"),
 				),
 				key.NewBinding(
-					key.WithKeys("esc"),
+					key.WithKeys("esc", "alt+esc"),
 					key.WithHelp("esc", "cancel"),
 				),
 				key.NewBinding(
@@ -885,18 +885,18 @@ func (p *chatPage) Help() help.KeyMap {
 		}
 		if p.app.CoderAgent != nil && p.app.CoderAgent.IsBusy() {
 			cancelBinding := key.NewBinding(
-				key.WithKeys("esc"),
+				key.WithKeys("esc", "alt+esc"),
 				key.WithHelp("esc", "cancel"),
 			)
 			if p.isCanceling {
 				cancelBinding = key.NewBinding(
-					key.WithKeys("esc"),
+					key.WithKeys("esc", "alt+esc"),
 					key.WithHelp("esc", "press again to cancel"),
 				)
 			}
 			if p.app.CoderAgent != nil && p.app.CoderAgent.QueuedPrompts(p.session.ID) > 0 {
 				cancelBinding = key.NewBinding(
-					key.WithKeys("esc"),
+					key.WithKeys("esc", "alt+esc"),
 					key.WithHelp("esc", "clear queue"),
 				)
 			}
@@ -1042,7 +1042,7 @@ func (p *chatPage) Help() help.KeyMap {
 						key.WithHelp("ctrl+r+r", "delete all attachments"),
 					),
 					key.NewBinding(
-						key.WithKeys("esc"),
+						key.WithKeys("esc", "alt+esc"),
 						key.WithHelp("esc", "cancel delete mode"),
 					),
 				})

internal/tui/page/chat/keys.go 🔗

@@ -23,7 +23,7 @@ func DefaultKeyMap() KeyMap {
 			key.WithHelp("ctrl+f", "add attachment"),
 		),
 		Cancel: key.NewBinding(
-			key.WithKeys("esc"),
+			key.WithKeys("esc", "alt+esc"),
 			key.WithHelp("esc", "cancel"),
 		),
 		Tab: key.NewBinding(