Skip to content

feat: allow more completion highlight control#1972

Merged
hrsh7th merged 2 commits into
hrsh7th:mainfrom
dmun:more-highlight-control
Oct 21, 2024
Merged

feat: allow more completion highlight control#1972
hrsh7th merged 2 commits into
hrsh7th:mainfrom
dmun:more-highlight-control

Conversation

@dmun

@dmun dmun commented Jun 30, 2024

Copy link
Copy Markdown
Contributor

Related: #1887

This PR allows more highlight control by allowing vim.CompletedItem.{field}_hl_group values to be of type table with the following structure:

-- inside the cmp.FormattingConfig.format method
vim_item.abbr_hl_group = {
    { '@function', range = { 0, 5 } },
    { 'Comment', range = { 5, 10 } },
}

Examples

Simple

A simple use case of this is having different highlights for function parameters:

image
Code
local format = function(entry, vim_item)
    local kind = entry:get_kind()

    if vim.tbl_contains({ 2, 3 }, kind) then -- if kind is a Function (2) or Method (3)
        local start_index, end_index = vim_item.abbr:find('%(.*')
        if start_index then
            vim_item.abbr_hl_group = {
                { '@function', range = { 0, start_index - 1 } },
                { 'Comment', range = { start_index - 1, end_index } },
            }
        else
            vim_item.abbr_hl_group = '@function'
        end
    end

    return vim_item
end

Treesitter-based

You can also have more complex highlights by using treesitter for example:

image
Code (borrowed from @xzbdmw)
format = function(entry, vim_item)
    local highlights = {}

    -- you will likely not want to get this query every single time for performance but this is an example
    local query = vim.treesitter.query.get(vim.bo.filetype, 'highlights')

    local success, parser = pcall(vim.treesitter.get_string_parser, str, vim.bo.filetype)
    if success then
        local tree = parser:parse(true)[1]
        local root = tree:root()
        for id, node in query:iter_captures(root, str, 0, -1) do
            local name = '@' .. query.captures[id] .. '.' .. vim.bo.filetype
            local hl = vim.api.nvim_get_hl_id_by_name(name)
            local range = { node:range() }
            local _, nscol, _, necol = range[1], range[2], range[3], range[4]

            table.insert(highlights, { hl, range = { nscol, necol } })
        end
    end

    vim_item.abbr_hl_group = highlights

    return vim_item
end,

Notes

LSP doesn't specify exactly how to use the label fields of a CompletionItem, as a result the usage of these values differ a lot between LSP implementations (see table below). This makes getting syntactically correct function signatures inconsistent across different LSP implementations.

LS label detail labelDetails.detail labelDetails.description
lua_ls require(modname) function - -
zls addManyAt fn (self: *Self, index: usize, count: usize) Allocator.Error![]T (index: usize, count: usize) Allocator.Error![]T
rust-analyzer find_map(…) fn(&mut self, F) -> Option<B> (as Iterator) fn(&mut self, F) -> Option<B>

I don't think nvim-cmp should be responsible for properly formatting/highlighting the function signatures. Instead, that logic should be configurable by the user, or delegated to some other plugin in similar style of lspkind-nvim.

Suggestions are very welcome!

@xzbdmw

xzbdmw commented Jul 1, 2024

Copy link
Copy Markdown

That’s much simpler in cmp side👍

@hrsh7th

hrsh7th commented Oct 21, 2024

Copy link
Copy Markdown
Owner

thank you!

@hrsh7th hrsh7th merged commit 29fb485 into hrsh7th:main Oct 21, 2024
nizamiza pushed a commit to nizamiza/nvim-cmp that referenced this pull request Feb 28, 2025
* feat(view): allow hl_group to be a table

* feat: improve table field naming
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants