mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	feat(lsp): support completion itemDefaults
This commit is contained in:
		 Maria José Solano
					Maria José Solano
				
			
				
					committed by
					
						 Christian Clason
						Christian Clason
					
				
			
			
				
	
			
			
			 Christian Clason
						Christian Clason
					
				
			
						parent
						
							3d96e3f9f2
						
					
				
				
					commit
					63f9c2da9a
				
			| @@ -125,6 +125,15 @@ The following changes may require adaptations in user config or plugins. | |||||||
| • Returning any truthy value from a callback passed to |nvim_create_autocmd()| | • Returning any truthy value from a callback passed to |nvim_create_autocmd()| | ||||||
|   (rather than just `true`) will delete the autocommand. |   (rather than just `true`) will delete the autocommand. | ||||||
|  |  | ||||||
|  | • |vim.lsp.util.extract_completion_items()| will no longer return reliable | ||||||
|  |   results, since it does not apply `itemDefaults` when its input is a | ||||||
|  |   `CompletionList`. | ||||||
|  |   Moreover, since support for LSP `completionList.itemDefaults` was added, | ||||||
|  |   some third party plugins might be negatively impacted in case the language | ||||||
|  |   servers support the feature but the plugin does not. | ||||||
|  |   If necessary, the respective capability can be | ||||||
|  |   removed when calling |vim.lsp.protocol.make_client_capabilities()|. | ||||||
|  |  | ||||||
| ============================================================================== | ============================================================================== | ||||||
| BREAKING CHANGES IN HEAD                                    *news-breaking-dev* | BREAKING CHANGES IN HEAD                                    *news-breaking-dev* | ||||||
|  |  | ||||||
| @@ -213,6 +222,11 @@ The following new APIs and features were added. | |||||||
|     the original LSP `Location` or `LocationLink`. |     the original LSP `Location` or `LocationLink`. | ||||||
|   • Added support for connecting to servers using named pipes (Windows) or |   • Added support for connecting to servers using named pipes (Windows) or | ||||||
|     unix domain sockets (Unix) via |vim.lsp.rpc.domain_socket_connect()|. |     unix domain sockets (Unix) via |vim.lsp.rpc.domain_socket_connect()|. | ||||||
|  |   • Added support for `completionList.itemDefaults`, reducing overhead when | ||||||
|  |     computing completion items where properties often share the same value | ||||||
|  |     (e.g. `commitCharacters`). Note that this might affect plugins and | ||||||
|  |     language servers that don't support the feature, and in such cases the | ||||||
|  |     respective capability can be unset. | ||||||
|  |  | ||||||
| • Treesitter | • Treesitter | ||||||
|   • Bundled parsers and queries (highlight, folds) for Markdown, Python, and |   • Bundled parsers and queries (highlight, folds) for Markdown, Python, and | ||||||
|   | |||||||
| @@ -6,6 +6,14 @@ local ms = protocol.Methods | |||||||
|  |  | ||||||
| --- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] | --- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] | ||||||
|  |  | ||||||
|  | -- TODO(mariasolos): Remove this declaration once we figure out a better way to handle | ||||||
|  | -- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331). | ||||||
|  | --- @class lsp.ItemDefaults | ||||||
|  | --- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil | ||||||
|  | --- @field insertTextFormat lsp.InsertTextFormat? | ||||||
|  | --- @field insertTextMode lsp.InsertTextMode? | ||||||
|  | --- @field data any | ||||||
|  |  | ||||||
| ---@param input string unparsed snippet | ---@param input string unparsed snippet | ||||||
| ---@return string parsed snippet | ---@return string parsed snippet | ||||||
| local function parse_snippet(input) | local function parse_snippet(input) | ||||||
| @@ -39,14 +47,44 @@ local function get_completion_word(item) | |||||||
|   return item.label |   return item.label | ||||||
| end | end | ||||||
|  |  | ||||||
|  | --- Applies the given defaults to the completion item, modifying it in place. | ||||||
|  | --- | ||||||
|  | --- @param item lsp.CompletionItem | ||||||
|  | --- @param defaults lsp.ItemDefaults? | ||||||
|  | local function apply_defaults(item, defaults) | ||||||
|  |   if not defaults then | ||||||
|  |     return | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat | ||||||
|  |   item.insertTextMode = item.insertTextMode or defaults.insertTextMode | ||||||
|  |   item.data = item.data or defaults.data | ||||||
|  |   if defaults.editRange then | ||||||
|  |     local textEdit = item.textEdit or {} | ||||||
|  |     item.textEdit = textEdit | ||||||
|  |     textEdit.newText = textEdit.newText or item.textEditText or item.insertText | ||||||
|  |     if defaults.editRange.start then | ||||||
|  |       textEdit.range = textEdit.range or defaults.editRange | ||||||
|  |     elseif defaults.editRange.insert then | ||||||
|  |       textEdit.insert = defaults.editRange.insert | ||||||
|  |       textEdit.replace = defaults.editRange.replace | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  |  | ||||||
| ---@param result vim.lsp.CompletionResult | ---@param result vim.lsp.CompletionResult | ||||||
| ---@return lsp.CompletionItem[] | ---@return lsp.CompletionItem[] | ||||||
| local function get_items(result) | local function get_items(result) | ||||||
|   if result.items then |   if result.items then | ||||||
|     return result.items |     for _, item in ipairs(result.items) do | ||||||
|  |       ---@diagnostic disable-next-line: param-type-mismatch | ||||||
|  |       apply_defaults(item, result.itemDefaults) | ||||||
|     end |     end | ||||||
|  |     return result.items | ||||||
|  |   else | ||||||
|     return result |     return result | ||||||
|   end |   end | ||||||
|  | end | ||||||
|  |  | ||||||
| --- Turns the result of a `textDocument/completion` request into vim-compatible | --- Turns the result of a `textDocument/completion` request into vim-compatible | ||||||
| --- |complete-items|. | --- |complete-items|. | ||||||
|   | |||||||
| @@ -764,6 +764,14 @@ function protocol.make_client_capabilities() | |||||||
|             return res |             return res | ||||||
|           end)(), |           end)(), | ||||||
|         }, |         }, | ||||||
|  |         completionList = { | ||||||
|  |           itemDefaults = { | ||||||
|  |             'editRange', | ||||||
|  |             'insertTextFormat', | ||||||
|  |             'insertTextMode', | ||||||
|  |             'data', | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|  |  | ||||||
|         -- TODO(tjdevries): Implement this |         -- TODO(tjdevries): Implement this | ||||||
|         contextSupport = false, |         contextSupport = false, | ||||||
|   | |||||||
| @@ -551,6 +551,10 @@ end | |||||||
| --- Can be used to extract the completion items from a | --- Can be used to extract the completion items from a | ||||||
| --- `textDocument/completion` request, which may return one of | --- `textDocument/completion` request, which may return one of | ||||||
| --- `CompletionItem[]`, `CompletionList` or null. | --- `CompletionItem[]`, `CompletionList` or null. | ||||||
|  | --- | ||||||
|  | --- Note that this method doesn't apply `itemDefaults` to `CompletionList`s, and hence the returned | ||||||
|  | --- results might be incorrect. | ||||||
|  | --- | ||||||
| ---@deprecated | ---@deprecated | ||||||
| ---@param result table The result of a `textDocument/completion` request | ---@param result table The result of a `textDocument/completion` request | ||||||
| ---@return lsp.CompletionItem[] List of completion items | ---@return lsp.CompletionItem[] List of completion items | ||||||
|   | |||||||
| @@ -248,4 +248,32 @@ describe('vim.lsp._completion', function() | |||||||
|     item.user_data = nil |     item.user_data = nil | ||||||
|     eq(expected, item) |     eq(expected, item) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|  |   it('uses defaults from itemDefaults', function() | ||||||
|  |     --- @type lsp.CompletionList | ||||||
|  |     local completion_list = { | ||||||
|  |       isIncomplete = false, | ||||||
|  |       itemDefaults = { | ||||||
|  |         editRange = { | ||||||
|  |           start = { line = 1, character = 1 }, | ||||||
|  |           ['end'] = { line = 1, character = 4 }, | ||||||
|  |         }, | ||||||
|  |         insertTextFormat = 2, | ||||||
|  |         data = 'foobar', | ||||||
|  |       }, | ||||||
|  |       items = { | ||||||
|  |         { | ||||||
|  |           label = 'hello', | ||||||
|  |           data = 'item-property-has-priority', | ||||||
|  |           textEditText = 'hello', | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     } | ||||||
|  |     local result = complete('|', completion_list) | ||||||
|  |     eq(1, #result.items) | ||||||
|  |     local item = result.items[1].user_data.nvim.lsp.completion_item --- @type lsp.CompletionItem | ||||||
|  |     eq(2, item.insertTextFormat) | ||||||
|  |     eq('item-property-has-priority', item.data) | ||||||
|  |     eq({ line = 1, character = 1 }, item.textEdit.range.start) | ||||||
|  |   end) | ||||||
| end) | end) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user