@@ -118,7 +118,24 @@ local function code_action_finder(opts, callback)
118
118
local position_encoding = vim .api .nvim_get_option_value (" encoding" , { scope = " local" })
119
119
local params
120
120
121
- if vim .fn .mode () == " n" then
121
+ -- Handle custom range if provided
122
+ if opts .range then
123
+ params = {
124
+ textDocument = {
125
+ uri = vim .uri_from_bufnr (opts .bufnr ),
126
+ },
127
+ range = {
128
+ start = {
129
+ line = opts .range .start [1 ] - 1 , -- Convert to 0-based
130
+ character = opts .range .start [2 ],
131
+ },
132
+ [" end" ] = {
133
+ line = opts .range [" end" ][1 ] - 1 , -- Convert to 0-based
134
+ character = opts .range [" end" ][2 ],
135
+ },
136
+ },
137
+ }
138
+ elseif vim .fn .mode () == " n" then
122
139
params = {
123
140
textDocument = {
124
141
uri = vim .uri_from_bufnr (opts .bufnr ),
@@ -140,8 +157,26 @@ local function code_action_finder(opts, callback)
140
157
end
141
158
142
159
local context = {}
143
- context .triggerKind = vim .lsp .protocol .CodeActionTriggerKind .Invoked
144
- context .diagnostics = get_line_diagnostics (opts .bufnr )
160
+
161
+ -- Set trigger kind (default to Invoked if not provided)
162
+ if opts .context and opts .context .triggerKind then
163
+ context .triggerKind = opts .context .triggerKind
164
+ else
165
+ context .triggerKind = vim .lsp .protocol .CodeActionTriggerKind .Invoked
166
+ end
167
+
168
+ -- Use provided diagnostics or get line diagnostics
169
+ if opts .context and opts .context .diagnostics then
170
+ context .diagnostics = opts .context .diagnostics
171
+ else
172
+ context .diagnostics = get_line_diagnostics (opts .bufnr )
173
+ end
174
+
175
+ -- Add 'only' filter to context if provided
176
+ if opts .context and opts .context .only then
177
+ context .only = opts .context .only
178
+ end
179
+
145
180
params .context = context
146
181
147
182
local clients = vim .lsp .get_clients ({ bufnr = opts .bufnr , method = " textDocument/codeAction" })
@@ -227,14 +262,28 @@ local function get_picker_module(picker_name)
227
262
end
228
263
end
229
264
230
- --- @class Filters
231
- --- @field kind string
265
+ --- @class Filters ( plugin-specific filters for backward compatibility )
266
+ --- @field kind string | string[]
232
267
--- @field str string
233
268
--- @field client string
234
269
--- @field line int
270
+ --- @field only string[]
235
271
236
- --- @class CodeActionOpts
237
- --- @field filters Filters
272
+ --- @class Context (LSP CodeActionContext )
273
+ --- @field only string[] Array of CodeActionKind strings to filter by
274
+ --- @field diagnostics table[] Array of diagnostics to include in context
275
+ --- @field triggerKind integer The reason why code actions were requested
276
+
277
+ --- @class Range
278
+ --- @field start integer[] Start position {row , col } (1-based )
279
+ --- @field end integer[] End position {row , col } (1-based )
280
+
281
+ --- @class CodeActionOpts (compatible with vim.lsp.buf.code_action )
282
+ --- @field context Context LSP context options
283
+ --- @field filter fun ( action : table ): boolean Function predicate to filter actions
284
+ --- @field apply boolean When true and only one action remains , apply it automatically
285
+ --- @field range Range Range for which code actions should be requested
286
+ --- @field filters Filters Plugin-specific filters (for backward compatibility )
238
287
239
288
--- Sort code actions based on priority with isPreferred at the top
240
289
--- @param results table : The code actions to sort
@@ -262,19 +311,51 @@ local function sort_by_preferred(results)
262
311
end
263
312
264
313
--- Get the code actions for the current buffer
265
- --- @param opts table : The options for the code actions.
314
+ --- @param opts table : The options for the code actions (compatible with vim.lsp.buf.code_action ).
315
+ --- - context: Table with LSP context options
316
+ --- - only: Array of CodeActionKind strings to filter by (e.g., {"source"})
317
+ --- - diagnostics: Array of diagnostics to include in context
318
+ --- - triggerKind: The reason why code actions were requested
319
+ --- - filter: Function predicate taking a CodeAction and returning boolean
320
+ --- - apply: Boolean - when true and only one action remains, apply it automatically
321
+ --- - range: {start: integer[], end: integer[]} - Range for code actions
322
+ --- - filters: Table of filters to apply (plugin-specific, for backward compatibility)
266
323
function M .code_action (opts )
267
324
local bufnr = vim .api .nvim_get_current_buf ()
268
325
269
- code_action_finder ({ bufnr = bufnr }, function (results )
326
+ -- Build finder options
327
+ local finder_opts = {
328
+ bufnr = bufnr ,
329
+ context = opts and opts .context ,
330
+ range = opts and opts .range ,
331
+ }
332
+
333
+ code_action_finder (finder_opts , function (results )
270
334
if opts == nil then
271
335
opts = {}
272
336
end
273
337
338
+ -- Apply context-based filtering first (if provided)
339
+ if opts .context and opts .context .only then
340
+ results = utils .filter_code_actions (results , { only = opts .context .only })
341
+ end
342
+
343
+ -- Apply additional filters if provided (plugin-specific)
274
344
if opts .filters ~= nil then
275
345
results = utils .filter_code_actions (results , opts .filters )
276
346
end
277
347
348
+ -- Apply filter function if provided (vim.lsp.buf.code_action compatible)
349
+ if opts .filter and type (opts .filter ) == " function" then
350
+ local filtered_results = {}
351
+ for _ , result in ipairs (results ) do
352
+ if opts .filter (result .action ) then
353
+ table.insert (filtered_results , result )
354
+ end
355
+ end
356
+ results = filtered_results
357
+ end
358
+
278
359
-- Sort actions with isPreferred to the top
279
360
results = sort_by_preferred (results )
280
361
@@ -283,6 +364,25 @@ function M.code_action(opts)
283
364
return
284
365
end
285
366
367
+ -- If apply=true and only one action remains, apply it automatically
368
+ if opts .apply and # results == 1 then
369
+ local action = results [1 ]
370
+ if action .action .edit then
371
+ vim .lsp .util .apply_workspace_edit (action .action .edit , action .client .offset_encoding )
372
+ end
373
+ if action .action .command then
374
+ if action .client .commands and action .client .commands [action .action .command .command ] then
375
+ action .client .commands [action .action .command .command ](
376
+ action .action .command ,
377
+ { bufnr = bufnr }
378
+ )
379
+ else
380
+ action .client :exec_cmd (action .action .command , { bufnr = bufnr })
381
+ end
382
+ end
383
+ return
384
+ end
385
+
286
386
-- Get the configured or default picker module
287
387
local picker_name
288
388
0 commit comments