Skip to content

Commit 4d2c537

Browse files
committed
feat: handle CompletionDonePre as well
1 parent 3f41a87 commit 4d2c537

5 files changed

Lines changed: 376 additions & 13 deletions

File tree

lua/opencode/lsp/opencode_ls.lua

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---In-process LSP server for opencode completion
22
---Provides completion for files, subagents, commands, and context items
33
---Works with any LSP-compatible completion plugin (blink.cmp, nvim-cmp, etc.)
4+
local M = { _completion_done_handled = false }
45

5-
local M = {}
66
---@type table<vim.lsp.protocol.Method, fun(params: table, callback:fun(err: lsp.ResponseError?, result: any))>
77
local handlers = {}
88
local ms = vim.lsp.protocol.Methods
@@ -33,6 +33,11 @@ end
3333

3434
handlers[ms.workspace_executeCommand] = function(params, callback)
3535
if params.command == 'opencode.completion_done' then
36+
if M._completion_done_handled then
37+
callback(nil, nil)
38+
M._completion_done_handled = false
39+
return
40+
end
3641
local item = params.arguments and params.arguments[1]
3742
if item then
3843
require('opencode.ui.completion').on_completion_done(item)
@@ -87,10 +92,13 @@ end
8792
---@param item CompletionItem
8893
---@param index integer
8994
---@return OpencodeLspItem
90-
local function to_lsp_item(item, index)
95+
local function to_lsp_item(item, index, params)
9196
local source = require('opencode.ui.completion').get_source_by_name(item.source_name)
9297
local kind = (source and source.custom_kind) or vim.lsp.protocol.CompletionItemKind.Function ---@type lsp.CompletionItemKind
9398
local priority = source and source.priority or 999
99+
local line = params.position.line
100+
local col = params.position.character
101+
94102
---@type OpencodeLspItem
95103
local lsp_item = {
96104
label = (M.supports_kind_icons() and '' or item.kind_icon .. ' ') .. item.label,
@@ -102,10 +110,16 @@ local function to_lsp_item(item, index)
102110
kind = 'plaintext',
103111
value = item.documentation,
104112
} or nil,
105-
insertText = item.insert_text or item.label,
106-
insertTextFormat = vim.lsp.protocol.InsertTextFormat.PlainText,
113+
insertText = item.label,
107114
filterText = item.label,
108115
sortText = string.format('%02d_%02d_%02d_%s', priority, item.priority or 999, index, item.label),
116+
textEdit = {
117+
range = {
118+
start = { line = line, character = col },
119+
['end'] = { line = line, character = col + (item.insert_text and #item.insert_text or 0) },
120+
},
121+
newText = item.insert_text,
122+
},
109123
command = {
110124
title = 'opencode.completion_done',
111125
command = 'opencode.completion_done',
@@ -159,7 +173,7 @@ handlers[ms.textDocument_completion] = function(params, callback)
159173
is_incomplete = true
160174
end
161175

162-
table.insert(all_items, to_lsp_item(item, i))
176+
table.insert(all_items, to_lsp_item(item, i, params))
163177
end
164178
end
165179

@@ -207,6 +221,27 @@ end
207221
---@return integer? client_id
208222
function M.start(bufnr)
209223
local config = M.create_config()
224+
local augroup = vim.api.nvim_create_augroup('OpencodeLspCompletion', { clear = true })
225+
226+
-- Handle completion done to trigger the action, some completion plugins do not trigger the command callback, so we use this as a fallback
227+
vim.api.nvim_create_autocmd('CompleteDonePre', {
228+
group = augroup,
229+
buffer = bufnr,
230+
callback = function()
231+
M._completion_done_handled = true
232+
local completed_item = vim.v.completed_item
233+
if completed_item and completed_item.user_data then
234+
local data = vim.tbl_get(completed_item, 'user_data', 'nvim', 'lsp', 'completion_item', 'data')
235+
or vim.tbl_get(completed_item, 'user_data', 'lsp', 'item', 'data')
236+
237+
local item = data and data._opencode_item
238+
239+
if item then
240+
require('opencode.ui.completion').on_completion_done(item)
241+
end
242+
end
243+
end,
244+
})
210245
return vim.lsp.start(config, { bufnr = bufnr, silent = false })
211246
end
212247

lua/opencode/ui/completion/commands.lua

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ local command_source = {
5454
kind_icon = icons.get('command'),
5555
detail = command.description,
5656
documentation = command.documentation .. (command.args and '\n\n* This command takes arguments.' or ''),
57-
insert_text = command.name:sub(2), -- remove the trigger char from the inserted text
57+
insert_text = command.name:sub(2) .. (command.args and ' ' or ''),
5858
source_name = 'commands',
5959
data = {
6060
name = command.name,
@@ -76,13 +76,11 @@ local command_source = {
7676
if item.kind == 'commands' then
7777
if item.data.fn then
7878
if item.data.args then
79-
require('opencode.ui.input_window').set_content(item.insert_text .. ' ')
80-
vim.api.nvim_win_set_cursor(0, { 1, #item.insert_text + 1 })
8179
return
8280
end
8381
vim.defer_fn(function()
8482
item.data.fn()
85-
end, 10) -- slight delay to allow completion menu to close, this prevent a weird bug with mini.pick where it displays an empty window with `BlinkDonotRepeatHack` text inserted
83+
end, 10) -- slight delay to allow completion menu to close,
8684
require('opencode.ui.input_window').set_content('')
8785
else
8886
vim.notify('Command not found: ' .. item.label, vim.log.levels.ERROR)

lua/opencode/ui/completion/context.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ local function create_context_item(name, type, available, documentation, icon, a
2929
kind_hl = not icon and available and 'OpencodeContextSwitchOn' or nil,
3030
detail = name,
3131
documentation = documentation or (available and name or 'Enable ' .. name .. ' for this message'),
32-
insert_text = name,
32+
insert_text = '',
3333
source_name = 'context',
3434
priority = priority or (available and 100 or 200),
3535
data = { type = type, name = name, available = available, additional_data = additional_data },

lua/opencode/ui/input_window.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ function M.handle_submit()
125125
return false
126126
end
127127
---@cast windows { input_buf: integer }
128+
local completion = require('opencode.ui.completion')
129+
if completion.is_completion_visible() then
130+
return false
131+
end
128132

129133
local input_content = table.concat(vim.api.nvim_buf_get_lines(windows.input_buf, 0, -1, false), '\n')
130134
vim.api.nvim_buf_set_lines(windows.input_buf, 0, -1, false, {})

0 commit comments

Comments
 (0)