mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	feat(lsp): handle disabled code actions (#34453)
This commit also makes it so that disabled code actions are not displayed unless the trigger kind is "Invoked".
This commit is contained in:
		| @@ -174,6 +174,7 @@ LSP | ||||
| • Incremental selection is now supported via `textDocument/selectionRange`. | ||||
|   `an` selects outwards and `in` selects inwards. | ||||
| • Support for multiline semantic tokens. | ||||
| • Support for the `disabled` field on code actions. | ||||
|  | ||||
| LUA | ||||
|  | ||||
|   | ||||
| @@ -1141,7 +1141,8 @@ local function on_code_action_results(results, opts) | ||||
|   ---@param a lsp.Command|lsp.CodeAction | ||||
|   local function action_filter(a) | ||||
|     -- filter by specified action kind | ||||
|     if opts and opts.context and opts.context.only then | ||||
|     if opts and opts.context then | ||||
|       if opts.context.only then | ||||
|         if not a.kind then | ||||
|           return false | ||||
|         end | ||||
| @@ -1158,6 +1159,11 @@ local function on_code_action_results(results, opts) | ||||
|           return false | ||||
|         end | ||||
|       end | ||||
|       -- Only show disabled code actions when the trigger kind is "Invoked". | ||||
|       if a.disabled and opts.context.triggerKind ~= lsp.protocol.CodeActionTriggerKind.Invoked then | ||||
|         return false | ||||
|       end | ||||
|     end | ||||
|     -- filter by user function | ||||
|     if opts and opts.filter and not opts.filter(a) then | ||||
|       return false | ||||
| @@ -1223,6 +1229,11 @@ local function on_code_action_results(results, opts) | ||||
|       return | ||||
|     end | ||||
|  | ||||
|     if action.disabled then | ||||
|       vim.notify(action.disabled.reason, vim.log.levels.ERROR) | ||||
|       return | ||||
|     end | ||||
|  | ||||
|     if not (action.edit and action.command) and client:supports_method(ms.codeAction_resolve) then | ||||
|       client:request(ms.codeAction_resolve, action, function(err, resolved_action) | ||||
|         if err then | ||||
| @@ -1253,6 +1264,10 @@ local function on_code_action_results(results, opts) | ||||
|     local clients = lsp.get_clients({ bufnr = item.ctx.bufnr }) | ||||
|     local title = item.action.title:gsub('\r\n', '\\r\\n'):gsub('\n', '\\n') | ||||
|  | ||||
|     if item.action.disabled then | ||||
|       title = title .. ' (disabled)' | ||||
|     end | ||||
|  | ||||
|     if #clients == 1 then | ||||
|       return title | ||||
|     end | ||||
|   | ||||
| @@ -430,6 +430,7 @@ function protocol.make_client_capabilities() | ||||
|         resolveSupport = { | ||||
|           properties = { 'edit', 'command' }, | ||||
|         }, | ||||
|         disabledSupport = true, | ||||
|       }, | ||||
|       codeLens = { | ||||
|         dynamicRegistration = false, | ||||
|   | ||||
| @@ -4718,6 +4718,70 @@ describe('LSP', function() | ||||
|       eq('workspace/executeCommand', result[5].method) | ||||
|       eq('command:1', result[5].params.command) | ||||
|     end) | ||||
|  | ||||
|     it('supports disabled actions', function() | ||||
|       exec_lua(create_server_definition) | ||||
|       local result = exec_lua(function() | ||||
|         local server = _G._create_server({ | ||||
|           capabilities = { | ||||
|             executeCommandProvider = { | ||||
|               commands = { 'command:1' }, | ||||
|             }, | ||||
|             codeActionProvider = { | ||||
|               resolveProvider = true, | ||||
|             }, | ||||
|           }, | ||||
|           handlers = { | ||||
|             ['textDocument/codeAction'] = function(_, _, callback) | ||||
|               callback(nil, { | ||||
|                 { | ||||
|                   title = 'Code Action 1', | ||||
|                   disabled = { | ||||
|                     reason = 'This action is disabled', | ||||
|                   }, | ||||
|                 }, | ||||
|               }) | ||||
|             end, | ||||
|             ['codeAction/resolve'] = function(_, _, callback) | ||||
|               callback(nil, { | ||||
|                 title = 'Code Action 1', | ||||
|                 command = { | ||||
|                   title = 'Command 1', | ||||
|                   command = 'command:1', | ||||
|                 }, | ||||
|               }) | ||||
|             end, | ||||
|           }, | ||||
|         }) | ||||
|  | ||||
|         local client_id = assert(vim.lsp.start({ | ||||
|           name = 'dummy', | ||||
|           cmd = server.cmd, | ||||
|         })) | ||||
|  | ||||
|         --- @diagnostic disable-next-line:duplicate-set-field | ||||
|         vim.notify = function(message, code) | ||||
|           server.messages[#server.messages + 1] = { | ||||
|             params = { | ||||
|               message = message, | ||||
|               code = code, | ||||
|             }, | ||||
|           } | ||||
|         end | ||||
|  | ||||
|         vim.lsp.buf.code_action({ apply = true }) | ||||
|         vim.lsp.stop_client(client_id) | ||||
|         return server.messages | ||||
|       end) | ||||
|       eq( | ||||
|         exec_lua(function() | ||||
|           return { message = 'This action is disabled', code = vim.log.levels.ERROR } | ||||
|         end), | ||||
|         result[4].params | ||||
|       ) | ||||
|       -- No command is resolved/applied after selecting a disabled code action | ||||
|       eq('shutdown', result[5].method) | ||||
|     end) | ||||
|   end) | ||||
|  | ||||
|   describe('vim.lsp.commands', function() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Riley Bruins
					Riley Bruins