mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	feat(lsp): support textDocument/documentColor
				
					
				
			test(lsp): add tests form `vim.lsp.document_color`
This commit is contained in:
		 Maria José Solano
					Maria José Solano
				
			
				
					committed by
					
						 Christian Clason
						Christian Clason
					
				
			
			
				
	
			
			
			 Christian Clason
						Christian Clason
					
				
			
						parent
						
							ca47cc39f8
						
					
				
				
					commit
					9ff1239634
				
			| @@ -2155,6 +2155,52 @@ stop({bufnr}, {client_id})                    *vim.lsp.semantic_tokens.stop()* | ||||
|       • {client_id}  (`integer`) The ID of the |vim.lsp.Client| | ||||
|  | ||||
|  | ||||
| ============================================================================== | ||||
| Lua module: vim.lsp.document_color                        *lsp-document_color* | ||||
|  | ||||
| enable({enable}, {bufnr}, {opts})            *vim.lsp.document_color.enable()* | ||||
|     Enables document highlighting from the given language client in the given | ||||
|     buffer. | ||||
|  | ||||
|     You can enable document highlighting from a supporting client as follows: >lua | ||||
|         vim.api.nvim_create_autocmd('LspAttach', { | ||||
|           callback = function(args) | ||||
|             local client = vim.lsp.get_client_by_id(args.data.client_id) | ||||
|  | ||||
|             if client:supports_method('textDocument/documentColor') | ||||
|               vim.lsp.document_color.enable(true, args.buf) | ||||
|             end | ||||
|           end | ||||
|         }) | ||||
| < | ||||
|  | ||||
|     To "toggle", pass the inverse of `is_enabled()`: >lua | ||||
|         vim.lsp.document_color.enable(not vim.lsp.document_color.is_enabled()) | ||||
| < | ||||
|  | ||||
|     Parameters: ~ | ||||
|       • {enable}  (`boolean?`) True to enable, false to disable. (default: | ||||
|                   `true`) | ||||
|       • {bufnr}   (`integer?`) Buffer handle, or 0 for current. (default: 0) | ||||
|       • {opts}    (`table?`) A table with the following fields: | ||||
|                   • {style}? | ||||
|                     (`'background'|'foreground'|'virtual'|string|fun(bufnr: integer, range: Range4, hex_code: string)`) | ||||
|                     Highlight style. It can be one of the pre-defined styles, | ||||
|                     a string to be used as virtual text, or a function that | ||||
|                     receives the buffer handle, the range (start line, start | ||||
|                     col, end line, end col) and the resolved hex color. | ||||
|                     (default: `'background'`) | ||||
|  | ||||
| is_enabled({bufnr})                      *vim.lsp.document_color.is_enabled()* | ||||
|     Query whether document colors are enabled in the given buffer. | ||||
|  | ||||
|     Parameters: ~ | ||||
|       • {bufnr}  (`integer?`) Buffer handle, or 0 for current. (default: 0) | ||||
|  | ||||
|     Return: ~ | ||||
|         (`boolean`) | ||||
|  | ||||
|  | ||||
| ============================================================================== | ||||
| Lua module: vim.lsp.util                                            *lsp-util* | ||||
|  | ||||
|   | ||||
| @@ -131,6 +131,8 @@ HIGHLIGHTS | ||||
| LSP | ||||
|  | ||||
| • |vim.lsp.ClientConfig| gained `workspace_required`. | ||||
| • Support for `textDocument/documentColor`: |lsp-document_color| | ||||
|   https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentColor | ||||
|  | ||||
| LUA | ||||
|  | ||||
|   | ||||
| @@ -12,6 +12,7 @@ local lsp = vim._defer_require('vim.lsp', { | ||||
|   codelens = ..., --- @module 'vim.lsp.codelens' | ||||
|   completion = ..., --- @module 'vim.lsp.completion' | ||||
|   diagnostic = ..., --- @module 'vim.lsp.diagnostic' | ||||
|   document_color = ..., --- @module 'vim.lsp.document_color' | ||||
|   handlers = ..., --- @module 'vim.lsp.handlers' | ||||
|   inlay_hint = ..., --- @module 'vim.lsp.inlay_hint' | ||||
|   log = ..., --- @module 'vim.lsp.log' | ||||
|   | ||||
							
								
								
									
										350
									
								
								runtime/lua/vim/lsp/document_color.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								runtime/lua/vim/lsp/document_color.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,350 @@ | ||||
| local api = vim.api | ||||
| local lsp = vim.lsp | ||||
| local util = lsp.util | ||||
| local ms = lsp.protocol.Methods | ||||
|  | ||||
| local document_color_ns = api.nvim_create_namespace('nvim.lsp.document_color') | ||||
| local document_color_augroup = api.nvim_create_augroup('nvim.lsp.document_color', {}) | ||||
|  | ||||
| local M = {} | ||||
|  | ||||
| --- @class (private) vim.lsp.document_color.HighlightInfo | ||||
| --- @field hex_code string Resolved HEX color | ||||
| --- @field range Range4 Range of the highlight | ||||
| --- @field hl_group? string Highlight group name. Won't be present if the style is a custom function. | ||||
|  | ||||
| --- @class (private) vim.lsp.document_color.BufState | ||||
| --- @field enabled boolean Whether document_color is enabled for the current buffer | ||||
| --- @field buf_version? integer Buffer version for which the color ranges correspond to | ||||
| --- @field applied_version table<integer, integer?> (client_id -> buffer version) Last buffer version for which we applied color ranges | ||||
| --- @field hl_info table<integer, vim.lsp.document_color.HighlightInfo[]?> (client_id -> color highlights) Processed highlight information | ||||
|  | ||||
| --- @type table<integer, vim.lsp.document_color.BufState?> | ||||
| local bufstates = {} | ||||
|  | ||||
| --- @inlinedoc | ||||
| --- @class vim.lsp.document_color.enable.Opts | ||||
| --- | ||||
| --- Highlight style. It can be one of the pre-defined styles, a string to be used as virtual text, or a | ||||
| --- function that receives the buffer handle, the range (start line, start col, end line, end col) and | ||||
| --- the resolved hex color. (default: `'background'`) | ||||
| --- @field style? 'background'|'foreground'|'virtual'|string|fun(bufnr: integer, range: Range4, hex_code: string) | ||||
|  | ||||
| -- Default options. | ||||
| --- @type vim.lsp.document_color.enable.Opts | ||||
| local document_color_opts = { style = 'background' } | ||||
|  | ||||
| --- @param color string | ||||
| local function get_contrast_color(color) | ||||
|   local r_s, g_s, b_s = color:match('^#(%x%x)(%x%x)(%x%x)$') | ||||
|   local r, g, b = tonumber(r_s, 16), tonumber(g_s, 16), tonumber(b_s, 16) | ||||
|  | ||||
|   -- Source: https://www.w3.org/TR/WCAG21/#dfn-relative-luminance | ||||
|   -- Using power 2.2 is a close approximation to full piecewise transform | ||||
|   local R, G, B = (r / 255) ^ 2.2, (g / 255) ^ 2.2, (b / 255) ^ 2.2 | ||||
|   local is_bright = (0.2126 * R + 0.7152 * G + 0.0722 * B) > 0.5 | ||||
|   return is_bright and '#000000' or '#ffffff' | ||||
| end | ||||
|  | ||||
| --- Returns the hex string representing the given LSP color. | ||||
| --- @param color lsp.Color | ||||
| --- @return string | ||||
| local function get_hex_code(color) | ||||
|   -- The RGB values in lsp.Color are in the [0-1] range, but we want them to be in the [0-255] range instead. | ||||
|   --- @param n number | ||||
|   color = vim.tbl_map(function(n) | ||||
|     return math.floor((n * 255) + 0.5) | ||||
|   end, color) | ||||
|  | ||||
|   return ('#%02x%02x%02x'):format(color.red, color.green, color.blue):lower() | ||||
| end | ||||
|  | ||||
| --- Cache of the highlight groups that we've already created. | ||||
| --- @type table<string, true> | ||||
| local color_cache = {} | ||||
|  | ||||
| --- Gets or creates the highlight group for the given LSP color information. | ||||
| --- | ||||
| --- @param hex_code string | ||||
| --- @param style string | ||||
| --- @return string | ||||
| local function get_hl_group(hex_code, style) | ||||
|   if style ~= 'background' then | ||||
|     style = 'foreground' | ||||
|   end | ||||
|  | ||||
|   local hl_name = ('LspDocumentColor_%s_%s'):format(hex_code:sub(2), style) | ||||
|  | ||||
|   if not color_cache[hl_name] then | ||||
|     if style == 'background' then | ||||
|       api.nvim_set_hl(0, hl_name, { bg = hex_code, fg = get_contrast_color(hex_code) }) | ||||
|     else | ||||
|       api.nvim_set_hl(0, hl_name, { fg = hex_code }) | ||||
|     end | ||||
|  | ||||
|     color_cache[hl_name] = true | ||||
|   end | ||||
|  | ||||
|   return hl_name | ||||
| end | ||||
|  | ||||
| --- @param bufnr integer | ||||
| --- @param enabled boolean | ||||
| local function reset_bufstate(bufnr, enabled) | ||||
|   bufstates[bufnr] = { enabled = enabled, applied_version = {}, hl_info = {} } | ||||
| end | ||||
|  | ||||
| --- |lsp-handler| for the `textDocument/documentColor` method. | ||||
| --- | ||||
| --- @param err? lsp.ResponseError | ||||
| --- @param result? lsp.ColorInformation[] | ||||
| --- @param ctx lsp.HandlerContext | ||||
| local function on_document_color(err, result, ctx) | ||||
|   if err then | ||||
|     lsp.log.error('document_color', err) | ||||
|     return | ||||
|   end | ||||
|  | ||||
|   local bufnr = assert(ctx.bufnr) | ||||
|   local bufstate = assert(bufstates[bufnr]) | ||||
|   local client_id = ctx.client_id | ||||
|  | ||||
|   if | ||||
|     util.buf_versions[bufnr] ~= ctx.version | ||||
|     or not result | ||||
|     or not api.nvim_buf_is_loaded(bufnr) | ||||
|     or not bufstate.enabled | ||||
|   then | ||||
|     return | ||||
|   end | ||||
|  | ||||
|   local hl_infos = {} --- @type vim.lsp.document_color.HighlightInfo[] | ||||
|   local style = document_color_opts.style | ||||
|   for _, res in ipairs(result) do | ||||
|     local range = { | ||||
|       res.range.start.line, | ||||
|       res.range.start.character, | ||||
|       res.range['end'].line, | ||||
|       res.range['end'].character, | ||||
|     } | ||||
|     local hex_code = get_hex_code(res.color) | ||||
|     local hl_info = { range = range, hex_code = hex_code } | ||||
|  | ||||
|     if type(style) == 'string' then | ||||
|       hl_info.hl_group = get_hl_group(hex_code, style) | ||||
|     end | ||||
|  | ||||
|     table.insert(hl_infos, hl_info) | ||||
|   end | ||||
|   bufstate.hl_info[client_id] = hl_infos | ||||
|  | ||||
|   bufstate.buf_version = ctx.version | ||||
|   api.nvim__redraw({ buf = bufnr, valid = true, flush = false }) | ||||
| end | ||||
|  | ||||
| --- @param bufnr integer | ||||
| local function buf_clear(bufnr) | ||||
|   local bufstate = assert(bufstates[bufnr]) | ||||
|   local client_ids = vim.tbl_keys(bufstate.hl_info) --- @type integer[] | ||||
|  | ||||
|   for _, id in ipairs(client_ids) do | ||||
|     bufstate.hl_info[id] = {} | ||||
|   end | ||||
|  | ||||
|   api.nvim_buf_clear_namespace(bufnr, document_color_ns, 0, -1) | ||||
|   api.nvim__redraw({ buf = bufnr, valid = true, flush = false }) | ||||
| end | ||||
|  | ||||
| --- @param bufnr integer | ||||
| --- @param client_id? integer | ||||
| local function buf_refresh(bufnr, client_id) | ||||
|   util._refresh(ms.textDocument_documentColor, { | ||||
|     bufnr = bufnr, | ||||
|     handler = on_document_color, | ||||
|     client_id = client_id, | ||||
|   }) | ||||
| end | ||||
|  | ||||
| --- @param bufnr integer | ||||
| local function buf_disable(bufnr) | ||||
|   buf_clear(bufnr) | ||||
|   reset_bufstate(bufnr, false) | ||||
| end | ||||
|  | ||||
| --- @param bufnr integer | ||||
| local function buf_enable(bufnr) | ||||
|   reset_bufstate(bufnr, true) | ||||
|  | ||||
|   api.nvim_create_autocmd('LspNotify', { | ||||
|     buffer = bufnr, | ||||
|     group = document_color_augroup, | ||||
|     desc = 'Refresh document_color on document changes', | ||||
|     callback = function(args) | ||||
|       local method = args.data.method --- @type string | ||||
|  | ||||
|       if | ||||
|         (method == ms.textDocument_didChange or method == ms.textDocument_didOpen) | ||||
|         and bufstates[args.buf].enabled | ||||
|       then | ||||
|         buf_refresh(args.buf, args.data.client_id) | ||||
|       end | ||||
|     end, | ||||
|   }) | ||||
|  | ||||
|   api.nvim_create_autocmd('LspAttach', { | ||||
|     buffer = bufnr, | ||||
|     group = document_color_augroup, | ||||
|     desc = 'Enable document_color when LSP client attaches', | ||||
|     callback = function(args) | ||||
|       api.nvim_buf_attach(args.buf, false, { | ||||
|         on_reload = function(_, buf) | ||||
|           buf_clear(buf) | ||||
|           if bufstates[buf].enabled then | ||||
|             buf_refresh(buf) | ||||
|           end | ||||
|         end, | ||||
|         on_detach = function(_, buf) | ||||
|           buf_disable(buf) | ||||
|         end, | ||||
|       }) | ||||
|     end, | ||||
|   }) | ||||
|  | ||||
|   api.nvim_create_autocmd('LspDetach', { | ||||
|     buffer = bufnr, | ||||
|     group = document_color_augroup, | ||||
|     desc = 'Disable document_color if all supporting clients detach', | ||||
|     callback = function(args) | ||||
|       local clients = lsp.get_clients({ bufnr = args.buf, method = ms.textDocument_documentColor }) | ||||
|  | ||||
|       if | ||||
|         not vim.iter(clients):any(function(c) | ||||
|           return c.id ~= args.data.client_id | ||||
|         end) | ||||
|       then | ||||
|         -- There are no clients left in the buffer that support document color, so turn it off. | ||||
|         buf_disable(args.buf) | ||||
|       end | ||||
|     end, | ||||
|   }) | ||||
|  | ||||
|   buf_refresh(bufnr) | ||||
| end | ||||
|  | ||||
| --- Query whether document colors are enabled in the given buffer. | ||||
| --- | ||||
| --- @param bufnr? integer Buffer handle, or 0 for current. (default: 0) | ||||
| --- @return boolean | ||||
| function M.is_enabled(bufnr) | ||||
|   vim.validate('bufnr', bufnr, 'number', true) | ||||
|  | ||||
|   return bufstates[vim._resolve_bufnr(bufnr)].enabled | ||||
| end | ||||
|  | ||||
| --- Enables document highlighting from the given language client in the given buffer. | ||||
| --- | ||||
| --- You can enable document highlighting from a supporting client as follows: | ||||
| --- ```lua | ||||
| --- vim.api.nvim_create_autocmd('LspAttach', { | ||||
| ---   callback = function(args) | ||||
| ---     local client = vim.lsp.get_client_by_id(args.data.client_id) | ||||
| --- | ||||
| ---     if client:supports_method('textDocument/documentColor') | ||||
| ---       vim.lsp.document_color.enable(true, args.buf) | ||||
| ---     end | ||||
| ---   end | ||||
| --- }) | ||||
| --- ``` | ||||
| --- | ||||
| --- To "toggle", pass the inverse of `is_enabled()`: | ||||
| --- | ||||
| --- ```lua | ||||
| --- vim.lsp.document_color.enable(not vim.lsp.document_color.is_enabled()) | ||||
| --- ``` | ||||
| --- | ||||
| --- @param enable? boolean True to enable, false to disable. (default: `true`) | ||||
| --- @param bufnr? integer Buffer handle, or 0 for current. (default: 0) | ||||
| --- @param opts? vim.lsp.document_color.enable.Opts | ||||
| function M.enable(enable, bufnr, opts) | ||||
|   vim.validate('enable', enable, 'boolean', true) | ||||
|   vim.validate('bufnr', bufnr, 'number', true) | ||||
|   vim.validate('opts', opts, 'table', true) | ||||
|  | ||||
|   enable = enable == nil or enable | ||||
|   bufnr = vim._resolve_bufnr(bufnr) | ||||
|   document_color_opts = vim.tbl_extend('keep', opts or {}, document_color_opts) | ||||
|  | ||||
|   if enable then | ||||
|     buf_enable(bufnr) | ||||
|   else | ||||
|     buf_disable(bufnr) | ||||
|   end | ||||
| end | ||||
|  | ||||
| api.nvim_create_autocmd('ColorScheme', { | ||||
|   pattern = '*', | ||||
|   group = document_color_augroup, | ||||
|   desc = 'Refresh document_color', | ||||
|   callback = function() | ||||
|     color_cache = {} | ||||
|  | ||||
|     for _, bufnr in ipairs(api.nvim_list_bufs()) do | ||||
|       buf_clear(bufnr) | ||||
|       if api.nvim_buf_is_loaded(bufnr) and bufstates[bufnr].enabled then | ||||
|         buf_refresh(bufnr) | ||||
|       else | ||||
|         reset_bufstate(bufnr, false) | ||||
|       end | ||||
|     end | ||||
|   end, | ||||
| }) | ||||
|  | ||||
| api.nvim_set_decoration_provider(document_color_ns, { | ||||
|   on_win = function(_, _, bufnr) | ||||
|     if not bufstates[bufnr] then | ||||
|       reset_bufstate(bufnr, false) | ||||
|     end | ||||
|     local bufstate = assert(bufstates[bufnr]) | ||||
|  | ||||
|     local all_applied = #bufstate.applied_version > 0 | ||||
|       and vim.iter(pairs(bufstate.applied_version)):all(function(_, buf_version) | ||||
|         return buf_version == bufstate.buf_version | ||||
|       end) | ||||
|  | ||||
|     if bufstate.buf_version ~= util.buf_versions[bufnr] or all_applied then | ||||
|       return | ||||
|     end | ||||
|  | ||||
|     api.nvim_buf_clear_namespace(bufnr, document_color_ns, 0, -1) | ||||
|  | ||||
|     local style = document_color_opts.style | ||||
|  | ||||
|     for client_id, client_hls in pairs(bufstate.hl_info) do | ||||
|       if bufstate.applied_version[client_id] ~= bufstate.buf_version then | ||||
|         for _, hl in ipairs(client_hls) do | ||||
|           if type(style) == 'function' then | ||||
|             style(bufnr, hl.range, hl.hex_code) | ||||
|           elseif style == 'foreground' or style == 'background' then | ||||
|             api.nvim_buf_set_extmark(bufnr, document_color_ns, hl.range[1], hl.range[2], { | ||||
|               end_row = hl.range[3], | ||||
|               end_col = hl.range[4], | ||||
|               hl_group = hl.hl_group, | ||||
|               strict = false, | ||||
|             }) | ||||
|           else | ||||
|             -- Default swatch: \uf0c8 | ||||
|             local swatch = style == 'virtual' and ' ' or style | ||||
|             api.nvim_buf_set_extmark(bufnr, document_color_ns, hl.range[1], hl.range[2], { | ||||
|               virt_text = { { swatch, hl.hl_group } }, | ||||
|               virt_text_pos = 'inline', | ||||
|             }) | ||||
|           end | ||||
|         end | ||||
|  | ||||
|         bufstate.applied_version[client_id] = bufstate.buf_version | ||||
|       end | ||||
|     end | ||||
|   end, | ||||
| }) | ||||
|  | ||||
| return M | ||||
| @@ -532,6 +532,9 @@ function protocol.make_client_capabilities() | ||||
|       callHierarchy = { | ||||
|         dynamicRegistration = false, | ||||
|       }, | ||||
|       colorProvider = { | ||||
|         dynamicRegistration = false, | ||||
|       }, | ||||
|     }, | ||||
|     workspace = { | ||||
|       symbol = { | ||||
|   | ||||
| @@ -278,6 +278,7 @@ local config = { | ||||
|       'inlay_hint.lua', | ||||
|       'tagfunc.lua', | ||||
|       'semantic_tokens.lua', | ||||
|       'document_color.lua', | ||||
|       'handlers.lua', | ||||
|       'util.lua', | ||||
|       'log.lua', | ||||
|   | ||||
							
								
								
									
										211
									
								
								test/functional/plugin/lsp/document_color_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								test/functional/plugin/lsp/document_color_spec.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,211 @@ | ||||
| local t = require('test.testutil') | ||||
| local n = require('test.functional.testnvim')() | ||||
| local t_lsp = require('test.functional.plugin.lsp.testutil') | ||||
| local Screen = require('test.functional.ui.screen') | ||||
|  | ||||
| local dedent = t.dedent | ||||
| local eq = t.eq | ||||
|  | ||||
| local api = n.api | ||||
| local exec_lua = n.exec_lua | ||||
| local insert = n.insert | ||||
|  | ||||
| local clear_notrace = t_lsp.clear_notrace | ||||
| local create_server_definition = t_lsp.create_server_definition | ||||
|  | ||||
| describe('vim.lsp.document_color', function() | ||||
|   local text = dedent([[ | ||||
| body { | ||||
|   color: #FFF; | ||||
|   background-color: rgb(0, 255, 255); | ||||
| } | ||||
| ]]) | ||||
|  | ||||
|   local grid_without_colors = [[ | ||||
|   body {                                               | | ||||
|     color: #FFF;                                       | | ||||
|     background-color: rgb(0, 255, 255);                | | ||||
|   }                                                    | | ||||
|   ^                                                     | | ||||
|   {1:~                                                    }|*8 | ||||
|                                                        | | ||||
|   ]] | ||||
|  | ||||
|   local grid_with_colors = [[ | ||||
|   body {                                               | | ||||
|     color: {2:#FFF};                                       | | ||||
|     background-color: {3:rgb(0, 255, 255)};                | | ||||
|   }                                                    | | ||||
|   ^                                                     | | ||||
|   {1:~                                                    }|*8 | ||||
|                                                        | | ||||
|   ]] | ||||
|  | ||||
|   --- @type test.functional.ui.screen | ||||
|   local screen | ||||
|  | ||||
|   --- @type integer | ||||
|   local client_id | ||||
|  | ||||
|   --- @type integer | ||||
|   local bufnr | ||||
|  | ||||
|   before_each(function() | ||||
|     clear_notrace() | ||||
|     exec_lua(create_server_definition) | ||||
|  | ||||
|     screen = Screen.new() | ||||
|     screen:set_default_attr_ids { | ||||
|       [1] = { bold = true, foreground = Screen.colors.Blue1 }, | ||||
|       [2] = { background = Screen.colors.Gray100, foreground = Screen.colors.Gray0 }, | ||||
|       [3] = { background = Screen.colors.Cyan1, foreground = Screen.colors.Gray0 }, | ||||
|       [4] = { foreground = Screen.colors.Grey100 }, | ||||
|       [5] = { foreground = Screen.colors.Cyan1 }, | ||||
|     } | ||||
|  | ||||
|     bufnr = n.api.nvim_get_current_buf() | ||||
|     client_id = exec_lua(function() | ||||
|       _G.server = _G._create_server({ | ||||
|         capabilities = { | ||||
|           colorProvider = true, | ||||
|         }, | ||||
|         handlers = { | ||||
|           ['textDocument/documentColor'] = function(_, _, callback) | ||||
|             callback(nil, { | ||||
|               { | ||||
|                 range = { | ||||
|                   start = { line = 1, character = 9 }, | ||||
|                   ['end'] = { line = 1, character = 13 }, | ||||
|                 }, | ||||
|                 color = { red = 1, green = 1, blue = 1 }, | ||||
|               }, | ||||
|               { | ||||
|                 range = { | ||||
|                   start = { line = 2, character = 20 }, | ||||
|                   ['end'] = { line = 2, character = 36 }, | ||||
|                 }, | ||||
|                 color = { red = 0, green = 1, blue = 1 }, | ||||
|               }, | ||||
|             }) | ||||
|           end, | ||||
|         }, | ||||
|       }) | ||||
|  | ||||
|       return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }) | ||||
|     end) | ||||
|  | ||||
|     insert(text) | ||||
|  | ||||
|     exec_lua(function() | ||||
|       vim.lsp.document_color.enable(true, bufnr) | ||||
|     end) | ||||
|  | ||||
|     screen:expect({ grid = grid_with_colors }) | ||||
|   end) | ||||
|  | ||||
|   after_each(function() | ||||
|     api.nvim_exec_autocmds('VimLeavePre', { modeline = false }) | ||||
|   end) | ||||
|  | ||||
|   it('clears document colors when sole client detaches', function() | ||||
|     exec_lua(function() | ||||
|       vim.lsp.stop_client(client_id) | ||||
|     end) | ||||
|  | ||||
|     screen:expect({ grid = grid_without_colors }) | ||||
|   end) | ||||
|  | ||||
|   it('does not clear document colors when one of several clients detaches', function() | ||||
|     local client_id2 = exec_lua(function() | ||||
|       _G.server2 = _G._create_server({ | ||||
|         capabilities = { | ||||
|           colorProvider = true, | ||||
|         }, | ||||
|         handlers = { | ||||
|           ['textDocument/documentColor'] = function(_, _, callback) | ||||
|             callback(nil, {}) | ||||
|           end, | ||||
|         }, | ||||
|       }) | ||||
|       local client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd }) | ||||
|       vim.lsp.document_color.enable(true, bufnr) | ||||
|       return client_id2 | ||||
|     end) | ||||
|  | ||||
|     exec_lua(function() | ||||
|       vim.lsp.stop_client(client_id2) | ||||
|     end) | ||||
|  | ||||
|     screen:expect({ grid = grid_with_colors, unchanged = true }) | ||||
|   end) | ||||
|  | ||||
|   describe('is_enabled()', function() | ||||
|     it('returns true when document colors is enabled', function() | ||||
|       eq( | ||||
|         true, | ||||
|         exec_lua(function() | ||||
|           return vim.lsp.document_color.is_enabled(bufnr) | ||||
|         end) | ||||
|       ) | ||||
|  | ||||
|       exec_lua(function() | ||||
|         vim.lsp.stop_client(client_id) | ||||
|       end) | ||||
|  | ||||
|       eq( | ||||
|         false, | ||||
|         exec_lua(function() | ||||
|           return vim.lsp.document_color.is_enabled(bufnr) | ||||
|         end) | ||||
|       ) | ||||
|     end) | ||||
|   end) | ||||
|  | ||||
|   describe('enable()', function() | ||||
|     it('supports foreground styling', function() | ||||
|       local grid_with_fg_colors = [[ | ||||
| body {                                               | | ||||
|   color: {4:#FFF};                                       | | ||||
|   background-color: {5:rgb(0, 255, 255)};                | | ||||
| }                                                    | | ||||
| ^                                                     | | ||||
| {1:~                                                    }|*8 | ||||
|                                                      | | ||||
|       ]] | ||||
|  | ||||
|       exec_lua(function() | ||||
|         vim.lsp.document_color.enable(true, bufnr, { style = 'foreground' }) | ||||
|       end) | ||||
|  | ||||
|       screen:expect({ grid = grid_with_fg_colors }) | ||||
|     end) | ||||
|  | ||||
|     it('supports custom swatch text', function() | ||||
|       local grid_with_swatches = [[ | ||||
| body {                                               | | ||||
|   color: {4: :) }#FFF;                                   | | ||||
|   background-color: {5: :) }rgb(0, 255, 255);            | | ||||
| }                                                    | | ||||
| ^                                                     | | ||||
| {1:~                                                    }|*8 | ||||
|                                                      | | ||||
|       ]] | ||||
|  | ||||
|       exec_lua(function() | ||||
|         vim.lsp.document_color.enable(true, bufnr, { style = ' :) ' }) | ||||
|       end) | ||||
|  | ||||
|       screen:expect({ grid = grid_with_swatches }) | ||||
|     end) | ||||
|  | ||||
|     it('will not create highlights with custom style function', function() | ||||
|       exec_lua(function() | ||||
|         vim.lsp.document_color.enable(true, bufnr, { | ||||
|           style = function() end, | ||||
|         }) | ||||
|       end) | ||||
|  | ||||
|       screen:expect({ grid = grid_without_colors }) | ||||
|     end) | ||||
|   end) | ||||
| end) | ||||
		Reference in New Issue
	
	Block a user