Skip to content

Commit 7017c24

Browse files
committed
feat: code_action should now be retro-compatible with vim.lsp.buf.code_action
Fixes #63
1 parent 10540d5 commit 7017c24

File tree

1 file changed

+109
-9
lines changed

1 file changed

+109
-9
lines changed

lua/tiny-code-action/init.lua

Lines changed: 109 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,24 @@ local function code_action_finder(opts, callback)
118118
local position_encoding = vim.api.nvim_get_option_value("encoding", { scope = "local" })
119119
local params
120120

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
122139
params = {
123140
textDocument = {
124141
uri = vim.uri_from_bufnr(opts.bufnr),
@@ -140,8 +157,26 @@ local function code_action_finder(opts, callback)
140157
end
141158

142159
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+
145180
params.context = context
146181

147182
local clients = vim.lsp.get_clients({ bufnr = opts.bufnr, method = "textDocument/codeAction" })
@@ -227,14 +262,28 @@ local function get_picker_module(picker_name)
227262
end
228263
end
229264

230-
--- @class Filters
231-
--- @field kind string
265+
--- @class Filters (plugin-specific filters for backward compatibility)
266+
--- @field kind string|string[]
232267
--- @field str string
233268
--- @field client string
234269
--- @field line int
270+
--- @field only string[]
235271

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)
238287

239288
--- Sort code actions based on priority with isPreferred at the top
240289
--- @param results table: The code actions to sort
@@ -262,19 +311,51 @@ local function sort_by_preferred(results)
262311
end
263312

264313
--- 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)
266323
function M.code_action(opts)
267324
local bufnr = vim.api.nvim_get_current_buf()
268325

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)
270334
if opts == nil then
271335
opts = {}
272336
end
273337

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)
274344
if opts.filters ~= nil then
275345
results = utils.filter_code_actions(results, opts.filters)
276346
end
277347

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+
278359
-- Sort actions with isPreferred to the top
279360
results = sort_by_preferred(results)
280361

@@ -283,6 +364,25 @@ function M.code_action(opts)
283364
return
284365
end
285366

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+
286386
-- Get the configured or default picker module
287387
local picker_name
288388

0 commit comments

Comments
 (0)