Skip to content

Commit fd56df5

Browse files
committed
feat: cancel current request
Signed-off-by: blob42 <contact@blob42.xyz>
1 parent ada5142 commit fd56df5

File tree

7 files changed

+46
-17
lines changed

7 files changed

+46
-17
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This fork does the following:
1111
- **Streaming mode** for real-time popup responses
1212
- [**New table-based configuration**](#example-configuration) instead of global variables
1313
- [**New commands**](#other-available-commands) and added support to the `%` range modifier
14+
- **Ability to cancel** current request.
1415
- **UI Query and select** local or remote model
1516
- **Strips thinking tokens** from replies if the model forgets to use codeblocks
1617
- **Refactored for idiomatic Lua** and neovim plugin style

TODO.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
## High
2+
- [ ] cancel current request
23
- [ ] implement streaming for OpenAI APIs.
34
- [ ] list/select with telescope picker
45
- [ ] model definition inheritance: define model from previous one

lua/codegpt/commands.lua

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,23 @@ local models = require("codegpt.models")
77

88
local M = {}
99

10-
local text_popup_stream = function(stream, bufnr, start_row, start_col, end_row, end_col)
10+
local text_popup_stream = function(job, stream, bufnr, start_row, start_col, end_row, end_col)
1111
local popup_filetype = Config.opts.ui.text_popup_filetype
12-
Ui.popup_stream(stream, popup_filetype, bufnr, start_row, start_col, end_row, end_col)
12+
Ui.popup_stream(job, stream, popup_filetype, bufnr, start_row, start_col, end_row, end_col)
1313
end
1414

1515
M.CallbackTypes = {
1616
["text_popup_stream"] = text_popup_stream,
17-
["text_popup"] = function(lines, bufnr, start_row, start_col, end_row, end_col)
17+
["text_popup"] = function(job, lines, bufnr, start_row, start_col, end_row, end_col)
1818
local popup_filetype = Config.opts.ui.text_popup_filetype
19-
Ui.popup(lines, popup_filetype, bufnr, start_row, start_col, end_row, end_col)
19+
Ui.popup(job, lines, popup_filetype, bufnr, start_row, start_col, end_row, end_col)
2020
end,
21-
["code_popup"] = function(lines, bufnr, start_row, start_col, end_row, end_col)
21+
["code_popup"] = function(job, lines, bufnr, start_row, start_col, end_row, end_col)
2222
lines = Utils.trim_to_code_block(lines)
2323
Utils.fix_indentation(bufnr, start_row, end_row, lines)
24-
Ui.popup(lines, Utils.get_filetype(), bufnr, start_row, start_col, end_row, end_col)
24+
Ui.popup(job, lines, Utils.get_filetype(), bufnr, start_row, start_col, end_row, end_col)
2525
end,
26-
["replace_lines"] = function(lines, bufnr, start_row, start_col, end_row, end_col)
26+
["replace_lines"] = function(job, lines, bufnr, start_row, start_col, end_row, end_col)
2727
lines = Utils.strip_reasoning(lines, "<think>", "</think>")
2828
lines = Utils.trim_to_code_block(lines)
2929
lines = Utils.remove_trailing_whitespace(lines)
@@ -32,7 +32,7 @@ M.CallbackTypes = {
3232
Utils.replace_lines(lines, bufnr, start_row, start_col, end_row, end_col)
3333
else
3434
-- if the buffer is not valid, open a popup. This can happen when the user closes the previous popup window before the request is finished.
35-
Ui.popup(lines, Utils.get_filetype(), bufnr, start_row, start_col, end_row, end_col)
35+
Ui.popup(job, lines, Utils.get_filetype(), bufnr, start_row, start_col, end_row, end_col)
3636
end
3737
end,
3838
["custom"] = nil,
@@ -51,7 +51,7 @@ local function get_cmd_opts(cmd)
5151
local is_stream = false
5252

5353
local model
54-
if opts.model then
54+
if opts ~= nil and opts.model then
5555
_, model = models.get_model_by_name(opts.model)
5656
else
5757
_, model = models.get_model()
@@ -96,12 +96,12 @@ function M.run_cmd(command, command_args, text_selection, bounds)
9696
local new_callback = nil
9797

9898
if is_stream then
99-
new_callback = function(stream)
100-
cmd_opts.callback(stream, bufnr, unpack(bounds))
99+
new_callback = function(stream, job)
100+
cmd_opts.callback(job, stream, bufnr, unpack(bounds))
101101
end
102102
else
103-
new_callback = function(lines) -- called from Provider.handle_response
104-
cmd_opts.callback(lines, bufnr, unpack(bounds))
103+
new_callback = function(lines, job) -- called from Provider.handle_response
104+
cmd_opts.callback(job, lines, bufnr, unpack(bounds))
105105
end
106106
end
107107

lua/codegpt/config.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ local defaults = {
210210
quit = "q", -- key to quit the popup
211211
use_as_output = "<c-o>", -- key to use the popup content as output and replace the original lines
212212
use_as_input = "<c-i>", -- key to use the popup content as input for a new API request
213+
cancel = "<c-c>", -- cancel current request
213214
custom = {}, -- define your custom mappings here
214215
},
215216
},

lua/codegpt/errors.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local Api = require("codegpt.api")
12
local M = {}
23

34
---@param provider string
@@ -11,4 +12,13 @@ function M.err(msg)
1112
vim.notify(msg, vim.log.levels.ERROR)
1213
end
1314

15+
function M.curl_error(err)
16+
if err.exit ~= nil then
17+
vim.defer_fn(function()
18+
vim.notify("curl error: " .. err.message, vim.log.levels.ERROR)
19+
end, 0)
20+
end
21+
Api.run_finished_hook()
22+
end
23+
1424
return M

lua/codegpt/ui.lua

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ local function create_window()
7777
return ui_elem
7878
end
7979

80-
function M.popup(lines, filetype, bufnr, start_row, start_col, end_row, end_col)
80+
function M.popup(job, lines, filetype, bufnr, start_row, start_col, end_row, end_col)
8181
local ui_elem = create_window()
8282
-- mount/open the component
8383
ui_elem:mount()
@@ -93,6 +93,11 @@ function M.popup(lines, filetype, bufnr, start_row, start_col, end_row, end_col)
9393
ui_elem:map("n", config.opts.ui.actions.quit, function()
9494
ui_elem:unmount()
9595
end, { noremap = true, silent = true })
96+
--
97+
-- cancel job if actions.cancel is called
98+
ui_elem:map("n", config.opts.ui.actions.cancel, function()
99+
job:shutdown()
100+
end, { noremap = true, silent = true })
96101

97102
-- set content
98103
vim.api.nvim_set_option_value("filetype", filetype, { buf = ui_elem.bufnr })
@@ -119,7 +124,7 @@ end
119124
local streaming = false
120125
local stream_ui_elem = nil
121126

122-
function M.popup_stream(stream, filetype, bufnr, start_row, start_col, end_row, end_col)
127+
function M.popup_stream(job, stream, filetype, bufnr, start_row, start_col, end_row, end_col)
123128
if not streaming then
124129
streaming = true
125130
stream_ui_elem = create_window()
@@ -139,6 +144,11 @@ function M.popup_stream(stream, filetype, bufnr, start_row, start_col, end_row,
139144
stream_ui_elem:unmount()
140145
end, { noremap = true, silent = true })
141146

147+
-- cancel job if actions.cancel is called
148+
stream_ui_elem:map("n", config.opts.ui.actions.cancel, function()
149+
job:shutdown()
150+
end, { noremap = true, silent = true })
151+
142152
vim.api.nvim_set_option_value("filetype", filetype, { buf = stream_ui_elem.bufnr })
143153
vim.api.nvim_set_option_value("wrap", true, { win = stream_ui_elem.winid })
144154
end
@@ -156,7 +166,13 @@ function M.popup_stream(stream, filetype, bufnr, start_row, start_col, end_row,
156166
streaming = false
157167
return
158168
else
159-
local payload = vim.fn.json_decode(stream)
169+
local ok, payload = pcall(function()
170+
return vim.fn.json_decode(stream)
171+
end)
172+
if not ok then
173+
streaming = false
174+
return
175+
end
160176
local content = payload.message.content
161177
local content_lines = vim.split(content, "\n")
162178
if #content_lines == 1 then

tests/parsing_spec.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
local utils = require("codegpt.utils")
22

33
describe("parsing llm response", function()
4-
it("should extract code", function()
4+
it("should extract code from reasoning", function()
55
local input = [[
66
<think>
77
Okay, the user is asking how to get the first element of an array in Lua, and they just want the code. Let me think.

0 commit comments

Comments
 (0)