ccls and LSP Semantic Tokens
2024-10-20 15:0:0 Author: maskray.me(查看原文) 阅读量:0 收藏

My C++ language server ccls implements a semantic highlighting features through the non-standard messages $ccls/publishSemanticHighlight and $ccls/publishSkippedRanges, supported by both emacs-ccls and vscode-ccls.

For years, my primary editor was Emacs. In 2018, I created emacs-ccls (a fork of emacs-cquery) and enjoyed its rainbow semantic highlighting. My setup also relied heavily on two features:

My elisp skills have gotten a bit rusty since I haven't been coding in it for a while. Switching to Neovim presented a challenge: it lacked the rainbow highlighting I loved.

Thankfully, Neovim supports "semantic tokens" from LSP 3.16, a standardized approach adopted by many editors.

I've made changes to ccls (available on a branch) to support semantic tokens. This basically adapts the $ccls/publishSemanticHighlight code to support textDocument/semanticTokens/full and textDocument/semanticTokens/range.

While semantic tokens do not differentiate symbols, we can define custom modifiers to achieve similar results.

ccls assigns the same modifier ID to tokens belonging to the same symbol. For different symbols, it attempts to assign unique IDs. While we have only 10 predefined IDs (each linked to a specific color), there's a chance that two symbols might share the same ID. However, this is uncommon and generally acceptable.

For a token with type variable, Neovim's built-in LSP plugin assigns it a highlight group @lsp.typemod.variable.id$i.cpp where $i is an integer between 0 and 9. We can customize a foreground color for each modifier ID. The complete Lua code follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
local func_colors = {
'#e5b124', '#927754', '#eb992c', '#e2bf8f', '#d67c17',
'#88651e', '#e4b953', '#a36526', '#b28927', '#d69855',
}
local type_colors = {
'#e1afc3', '#d533bb', '#9b677f', '#e350b6', '#a04360',
'#dd82bc', '#de3864', '#ad3f87', '#dd7a90', '#e0438a',
}
local param_colors = {
'#e5b124', '#927754', '#eb992c', '#e2bf8f', '#d67c17',
'#88651e', '#e4b953', '#a36526', '#b28927', '#d69855',
}
local var_colors = {
'#429921', '#58c1a4', '#5ec648', '#36815b', '#83c65d',
'#419b2f', '#43cc71', '#7eb769', '#58bf89', '#3e9f4a',
}
local all_colors = {
class = type_colors,
enumMember = var_colors,
field = var_colors,
['function'] = func_colors,
parameter = param_colors,
struct = type_colors,
variable = var_colors
}
for type, colors in pairs(all_colors) do
for i = 1,#colors do
vim.api.nvim_set_hl(0, string.format('@lsp.typemod.%s.id%s.cpp', type, i-1), {fg=colors[i]})
end
end

vim.cmd([[
hi @lsp.mod.classScope.cpp gui=italic
hi @lsp.mod.static.cpp gui=bold
hi @lsp.typemod.variable.namespaceScope.cpp gui=bold,underline
]], {})

This is quite appealing, but I need assistance to get code lens working.

When this feature branch is merged, Emacs users can just remove the following two lines:

TODO: How to change lsp-semantic-token-modifier-faces to support rainbow semantic tokens in lsp-mode and emacs-ccls?

Help is needed to remove $ccls/publishSemanticHighlight to use the built-in semantic tokens support. Unfortunately, vscode-ccls is not actively maintained, and I lack the expertise to maintain the plugin of an editor I do not commonly use.


文章来源: https://maskray.me/blog/2024-10-20-ccls-and-lsp-semantic-tokens
如有侵权请联系:admin#unsafe.sh