@@ -7,43 +7,22 @@ local M = {}
77local handlers = {}
88local ms = vim .lsp .protocol .Methods
99
10- --- Parse trigger characters from all registered completion sources
11- --- @return string[]
12- local function get_trigger_characters ()
13- local chars = {}
14- local config = require (' opencode.config' )
15-
16- -- Get trigger characters from keymaps
17- local triggers = {
18- config .get_key_for_function (' input_window' , ' mention' ), -- @ for subagents
19- config .get_key_for_function (' input_window' , ' slash_commands' ), -- / for commands
20- config .get_key_for_function (' input_window' , ' context_items' ), -- # for context
21- }
22-
23- for _ , trigger in ipairs (triggers ) do
24- if trigger and not vim .tbl_contains (chars , trigger ) then
25- table.insert (chars , trigger )
26- end
27- end
28-
29- return chars
30- end
31-
3210--- Initialize handler - negotiates capabilities with the client
3311--- @param params lsp.InitializeParams
3412--- @param callback fun ( err ?: lsp.ResponseError , result : lsp.InitializeResult )
3513handlers [ms .initialize ] = function (params , callback )
36- local trigger_chars = get_trigger_characters ()
14+ local completion = require (' opencode.ui.completion' )
15+ local triggers = completion .get_trigger_characters ()
3716
3817 callback (nil , {
3918 capabilities = {
4019 completionProvider = {
4120 resolveProvider = true ,
42- triggerCharacters = trigger_chars ,
21+ triggerCharacters = triggers ,
4322 },
4423 },
4524 serverInfo = {
46- name = ' opencode_ls ' ,
25+ name = ' opencode_completion_ls ' ,
4726 version = ' 1.0.0' ,
4827 },
4928 })
5534--- @return string trigger_char
5635--- @return string full_line
5736local function get_completion_context (params )
37+ local completion = require (' opencode.ui.completion' )
5838 local bufnr = vim .api .nvim_get_current_buf ()
5939 local line_num = params .position .line + 1 -- LSP is 0-indexed
6040 local col = params .position .character
@@ -64,14 +44,7 @@ local function get_completion_context(params)
6444 local line_to_cursor = line :sub (1 , col )
6545
6646 -- Find the trigger character
67- local trigger_char = ' '
68- local config = require (' opencode.config' )
69- local triggers = {
70- config .get_key_for_function (' input_window' , ' mention' ),
71- config .get_key_for_function (' input_window' , ' slash_commands' ),
72- config .get_key_for_function (' input_window' , ' context_items' ),
73- }
74-
47+ local triggers = completion .get_trigger_characters ()
7548 for _ , t in ipairs (triggers ) do
7649 if t and line_to_cursor :match (vim .pesc (t ) .. ' [^%s]*$' ) then
7750 trigger_char = t
@@ -88,24 +61,23 @@ local function get_completion_context(params)
8861 return word , trigger_char , line
8962end
9063
64+ local function supports_kind_icons ()
65+ -- only blink.cmp supports kind icons currently, so we check for its presence
66+ local has_blink_cmp = pcall (require , ' blink.cmp' )
67+ return has_blink_cmp
68+ end
69+
9170--- Convert opencode CompletionItem to LSP CompletionItem
9271--- @param item CompletionItem
9372--- @param index integer
9473--- @return lsp.CompletionItem
9574local function to_lsp_item (item , index )
96- -- Map opencode kinds to LSP kinds
97- local kind_map = {
98- file = vim .lsp .protocol .CompletionItemKind .File ,
99- subagent = vim .lsp .protocol .CompletionItemKind .Class ,
100- command = vim .lsp .protocol .CompletionItemKind .Function ,
101- context = vim .lsp .protocol .CompletionItemKind .Variable ,
102- }
10375 local source = require (' opencode.ui.completion' ).get_source_by_name (item .source_name )
10476
10577 local lsp_item = {
106- label = item .kind_icon .. item .label ,
107- kind = 0 ,
108- kind_icon = ' ' ,
78+ label = ( supports_kind_icons () and ' ' or ( item .kind_icon .. ' ' )) .. item .label ,
79+ kind = vim . lsp . protocol . CompletionItemKind . Text ,
80+ kind_icon = supports_kind_icons () and item . kind_icon or nil , -- Only include kind_icon if supported
10981 kind_hl = item .kind_hl ,
11082 detail = item .detail ,
11183 documentation = item .documentation and {
@@ -139,39 +111,41 @@ handlers[ms.textDocument_completion] = function(params, callback)
139111 line = line ,
140112 }
141113
142- -- Get all registered sources
143114 local completion = require (' opencode.ui.completion' )
144115 local sources = completion .get_sources ()
145116
146- -- Collect promises from all sources
147117 local Promise = require (' opencode.promise' )
148118 local promises = {}
149119
150120 for _ , source in ipairs (sources ) do
151- if source .complete then
152- table.insert (promises , source .complete (completion_context ))
153- end
121+ table.insert (promises , source .complete (completion_context ))
154122 end
155123
156- -- Wait for all sources to complete in parallel
157124 Promise .all (promises )
158125 :and_then (function (results )
159126 local all_items = {}
160127
161- -- Flatten results from all sources
128+ local is_incomplete = false
162129 for i , items in ipairs (results ) do
163- if type (items ) == ' table' then
164- for _ , item in ipairs (items ) do
165- table.insert (all_items , to_lsp_item (item , i ))
130+ for _ , item in ipairs (items or {}) do
131+ local source = completion .get_source_by_name (item .source_name )
132+ if source and source .is_incomplete then
133+ is_incomplete = true
166134 end
135+
136+ table.insert (all_items , to_lsp_item (item , i ))
167137 end
168138 end
169139
170- callback (nil , all_items )
140+ callback (nil , {
141+ isIncomplete = is_incomplete ,
142+ items = all_items ,
143+ })
171144 completion .store_completion_items (all_items )
172145 end )
173146 :catch (function (err )
174- vim .notify (' Opencode LSP completion error: ' .. tostring (err ), vim .log .levels .ERROR )
147+ local log = require (' opencode.log' )
148+ log .error (' Error in completion handler: ' .. tostring (err ))
175149 callback (nil , {})
176150 end )
177151end
@@ -182,17 +156,14 @@ end
182156handlers [ms .completionItem_resolve ] = function (params , callback )
183157 local item = vim .deepcopy (params )
184158
185- -- Additional resolution can be done here if needed
186- -- For now, documentation is already attached in textDocument_completion
187-
188159 callback (nil , item )
189160end
190161
191162--- Create the LSP server configuration
192163--- @return vim.lsp.ClientConfig
193164function M .create_config ()
194165 return {
195- name = ' opencode_ls ' ,
166+ name = ' opencode_completion_ls ' ,
196167 cmd = function (dispatchers , config )
197168 return {
198169 request = function (method , params , callback )
@@ -219,19 +190,4 @@ function M.start(bufnr)
219190 return vim .lsp .start (config , { bufnr = bufnr , silent = false })
220191end
221192
222- --- Hook into completion item selection to trigger on_complete callbacks
223- --- This is called when a completion item is confirmed/selected
224- --- @param item lsp.CompletionItem
225- function M .on_completion_done (item )
226- if not item or not item .data or not item .data ._opencode_item then
227- return
228- end
229-
230- local completion = require (' opencode.ui.completion' )
231- local original_item = item .data ._opencode_item
232-
233- -- Call the source's on_complete callback
234- completion .on_complete (original_item )
235- end
236-
237193return M
0 commit comments