Skip to content

Commit 3544c55

Browse files
cpcloudcursoragent
andcommitted
feat(ui): change ctrl+c to cancel operations, ctrl+q to quit
Changed keybinding behavior to match common terminal UX: **ctrl+c**: Cancel ongoing LLM operations without quitting - Cancels model pulls - Cancels streaming responses - Cancels query generation - Does nothing if no operation is active (no longer quits) **ctrl+q**: New hard quit keybinding - Quits the application immediately - Also callable from top-level (model.go) to cancel any LLM ops before exit - Shown as "q / ctrl+q" in help screen since 'q' already quits from nav mode This matches terminal conventions where ctrl+c interrupts the current task but doesn't exit the program. Updated: - Top-level handler in model.go: ctrl+q quits, ctrl+c cancels ops - Chat completer: ctrl+q quits instead of ctrl+c - Chat main handler: ctrl+c only cancels, removed quit fallback - Form help: ctrl+q instead of ctrl+c - Help screen: "Cancel operation" instead of "Cancel stream" - Nav mode help: "q / ctrl+q" instead of just "q" Closes #170 Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 8ae5da6 commit 3544c55

File tree

3 files changed

+13
-9
lines changed

3 files changed

+13
-9
lines changed

internal/app/chat.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,7 @@ func (m *Model) handleChatKey(key tea.KeyMsg) (tea.Model, tea.Cmd) {
10761076
}
10771077
m.deactivateCompleter()
10781078
return m, nil
1079-
case "ctrl+c":
1079+
case "ctrl+q":
10801080
return m, tea.Interrupt
10811081
}
10821082
}
@@ -1094,7 +1094,7 @@ func (m *Model) handleChatKey(key tea.KeyMsg) (tea.Model, tea.Cmd) {
10941094
m.toggleSQL()
10951095
return m, nil
10961096
case "ctrl+c":
1097-
// Cancel stream or pull, otherwise quit.
1097+
// Cancel stream or pull if active.
10981098
if m.chat.Streaming && m.chat.CancelFn != nil {
10991099
m.chat.CancelFn()
11001100
m.chat.Streaming = false
@@ -1112,9 +1112,8 @@ func (m *Model) handleChatKey(key tea.KeyMsg) (tea.Model, tea.Cmd) {
11121112
m.refreshChatViewport()
11131113
return m, nil
11141114
}
1115-
// No active operations -- clean up and quit.
1116-
m.cancelChatOperations()
1117-
return m, tea.Interrupt
1115+
// No active operations -- ctrl+c does nothing in chat.
1116+
return m, nil
11181117
case "up", "ctrl+p":
11191118
if m.chat.Input.Focused() && !m.chat.Streaming {
11201119
m.historyBack()

internal/app/model.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,15 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
143143
m.resizeTables()
144144
m.updateAllViewports()
145145
case tea.KeyMsg:
146-
if typed.String() == "ctrl+c" {
146+
if typed.String() == "ctrl+q" {
147147
m.cancelChatOperations()
148148
return m, tea.Interrupt
149149
}
150+
if typed.String() == "ctrl+c" {
151+
// Cancel any ongoing LLM operations but don't quit.
152+
m.cancelChatOperations()
153+
return m, nil
154+
}
150155
case chatChunkMsg:
151156
// Chunks arriving after chat is closed are harmlessly dropped.
152157
if m.chat != nil {

internal/app/view.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ func (m *Model) statusView() string {
251251
dirtyIndicator,
252252
m.helpItem("ctrl+s", "save"),
253253
m.helpItem("esc", "cancel"),
254-
m.helpItem("ctrl+c", "quit"),
254+
m.helpItem("ctrl+q", "quit"),
255255
)
256256
return m.withStatusMessage(help)
257257
}
@@ -776,7 +776,7 @@ func (m *Model) helpContent() string {
776776
{"@", "Ask LLM"},
777777
{"i", "Edit mode"},
778778
{"?", "Help"},
779-
{"q", "Quit"},
779+
{"q / ctrl+q", "Quit"},
780780
},
781781
},
782782
{
@@ -805,7 +805,7 @@ func (m *Model) helpContent() string {
805805
{"enter", "Send message"},
806806
{"ctrl+s", "Toggle SQL display"},
807807
{"\u2191/\u2193", "Prompt history"},
808-
{"ctrl+c", "Cancel stream"},
808+
{"ctrl+c", "Cancel operation"},
809809
{"esc", "Hide chat"},
810810
},
811811
},

0 commit comments

Comments
 (0)