function M.roslyn(completion_item, ls)
    local label = completion_item.label
    local description = completion_item.labelDetails and completion_item.labelDetails.description
    local kind = completion_item.kind
    local text = label
    if not kind then
        return utils.highlight_range(text, ls, 0, #text)
    end
    local highlight_name
    if kind == Kind.Class or kind == Kind.Interface or kind == Kind.Enum then
        highlight_name = "@type"
    elseif kind == Kind.Constructor then
        highlight_name = "@type"
    elseif kind == Kind.Constant then
        highlight_name = "@constant"
    elseif kind == Kind.Function or kind == Kind.Method then
        highlight_name = "@function"
    elseif kind == Kind.Property or kind == Kind.Field then
        highlight_name = "@property"
    elseif kind == Kind.Variable then
        highlight_name = "@variable"
    elseif kind == Kind.Keyword then
        highlight_name = "@keyword"
    else
        highlight_name = config.fallback_highlight
    end
    local highlights = {
        {
            highlight_name,
            range = { 0, #label },
        },
    }
    if description then
        text = label .. " " .. description
        table.insert(highlights, {
            config.ls.roslyn.extra_info_hl,
            range = { #label + 1, #text },
        })
    end
    return {
        text = text,
        highlights = highlights,
    }
end

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.ts_server(completion_item, ls)
    local label = completion_item.label
    local detail = completion_item.detail
    local kind = completion_item.kind
    -- Combine label + detail for final display
    local text = (detail and config.ls.ts_ls.extra_info_hl ~= false) and (label .. " " .. detail) or label

    if not kind then
        return utils.highlight_range(text, ls, 0, #text)
    end

    local highlight_name
    if kind == Kind.Class or kind == Kind.Interface or kind == Kind.Enum then
        highlight_name = "@type"
    elseif kind == Kind.Constructor then
        highlight_name = "@type"
    elseif kind == Kind.Constant then
        highlight_name = "@constant"
    elseif kind == Kind.Function or kind == Kind.Method then
        highlight_name = "@function"
    elseif kind == Kind.Property or kind == Kind.Field then
        highlight_name = "@property"
    elseif kind == Kind.Variable then
        highlight_name = "@variable"
    elseif kind == Kind.Keyword then
        highlight_name = "@keyword"
    else
        highlight_name = config.fallback_highlight
    end

    local highlights = {
        {
            highlight_name,
            range = { 0, #label },
        },
    }

    if detail and config.ls.ts_ls.extra_info_hl ~= false then
        local extra_info_hl = config.ls.ts_ls.extra_info_hl
        table.insert(highlights, {
            extra_info_hl,
            range = { #label + 1, #label + 1 + #detail },
        })
    end

    return {
        text = text,
        highlights = highlights,
    }
end

-- see https://github.com/zed-industries/zed/pull/13043
-- Untested.
---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.vtsls(completion_item, ls)
    local function one_line(s)
        s = s:gsub("    ", "")
        s = s:gsub("\n", " ")
        return s
    end

    local label = completion_item.label

    local kind = completion_item.kind
    if not kind then
        return utils.highlight_range(label, ls, 0, #label)
    end

    local highlight_name
    if kind == Kind.Class or kind == Kind.Interface or kind == Kind.Enum then
        highlight_name = "@type"
    elseif kind == Kind.Constructor then
        highlight_name = "@type"
    elseif kind == Kind.Constant then
        highlight_name = "@constant"
    elseif kind == Kind.Function or kind == Kind.Method then
        highlight_name = "@function"
    elseif kind == Kind.Property or kind == Kind.Field then
        highlight_name = "@property"
    elseif kind == Kind.Variable then
        highlight_name = "@variable"
    else
        highlight_name = config.fallback_highlight
    end

    local description = completion_item.labelDetails and completion_item.labelDetails.description
    local detail = completion_item.detail

    local highlights = {
        {
            highlight_name,
            range = { 0, #label },
        },
    }
    local text = label
    if config.ls.vtsls.extra_info_hl ~= false then
        if description then
            text = label .. " " .. one_line(description)
            table.insert(highlights, {
                config.ls.vtsls.extra_info_hl,
                range = { #label + 1, #text },
            })
        elseif detail then
            text = label .. " " .. one_line(detail)
            table.insert(highlights, {
                config.ls.vtsls.extra_info_hl,
                range = { #label + 1, #text },
            })
        end
    end

    return {
        text = text,
        highlights = highlights,
    }
end

return M

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

local function align_spaces(abbr, detail)
    if config.ls.clangd.align_type_to_right == false then
        return ""
    end
    return utils.align_spaces_bell(abbr, detail)
end

local function path_align_spaces(abbr, detail)
    if config.ls.clangd.align_type_to_right == false then
        return "  "
    end
    return utils.align_spaces_bell(abbr, detail)
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
local function _clangd(completion_item, ls)
    local label = completion_item.label
    local kind = completion_item.kind
    local detail = completion_item.detail
    local labelDetails = completion_item.labelDetails

    -- If no kind, just fallback to highlighting the cleaned-up label
    if not kind then
        return utils.highlight_range(label, ls, 0, #label)
    end

    -- Constants or Variables with detail => "detail label", highlight entire text
    if (kind == Kind.Constant or kind == Kind.Variable) and detail then
        local text = string.format("%s;%s%s", label, align_spaces(label .. " ", detail), detail)
        -- void foo() {int x;std::unique_ptr<Foo> x;}
        --             |         |
        --          @variable    |-- @type
        -- later factor to `x std::unique_ptr<Foo>`.
        local source = string.format("void foo(){ int %s x;}", text)
        return utils.highlight_range(source, ls, 16, 16 + #text)

        -- Functions or Methods with detail => "detail label", might find '('
    elseif kind == Kind.Field and detail then
        local text = string.format("%s;%s%s", label, align_spaces(label .. " ", detail), detail)
        -- void foo() {f->x;std::unique_ptr<Foo> x;}
        --                |         |
        --                @field    |-- @type
        -- later factor to `x std::unique_ptr<Foo>`.
        local source = string.format("void foo(){ f->%s x;}", text)
        return utils.highlight_range(source, ls, 15, 15 + #text)
        --
    elseif (kind == Kind.Function or kind == Kind.Method) and detail then
        local signature = ""
        if labelDetails and labelDetails.detail then
            signature = labelDetails.detail
        end
        local text = string.format(
            "void %s%s;%s%s x;",
            label,
            signature,
            align_spaces(label .. signature .. ";", detail),
            detail
        )
        return utils.highlight_range(text, ls, 5, #text - 3)
        --
    else
        local highlight_name = nil
        local lang = vim.bo.filetype == "c" and "c" or "cpp"
        if kind == Kind.Struct or kind == Kind.Interface then
            highlight_name = "@type"
        elseif kind == Kind.Class then
            highlight_name = utils.hl_exist_or("@lsp.type.class", "@variant", lang)
        elseif kind == Kind.EnumMember then
            highlight_name = utils.hl_exist_or("@lsp.type.enumMember", "@variant", lang)
        elseif kind == Kind.Enum then
            highlight_name = utils.hl_exist_or("@lsp.type.enum", "@type", lang)
        elseif kind == Kind.Keyword then
            highlight_name = "@keyword"
        elseif kind == Kind.Value or kind == Kind.Constant then
            highlight_name = "@constant"
        else
            highlight_name = config.fallback_highlight
        end

        -- If we found a special highlight name, highlight the portion before '('
        if highlight_name then
            local paren_index = string.find(label, "%(", 1, true)
            local end_index = paren_index and (paren_index - 1) or #label

            return {
                text = label,
                highlights = {
                    {
                        highlight_name,
                        range = { vim.startswith(label, "•") and 3 or 0, end_index },
                    },
                },
            }
        end
    end

    return {
        text = label,
        highlights = {},
    }
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.clangd(completion_item, ls)
    local vim_item = _clangd(completion_item, ls)
    local max_width = require("colorful-menu.utils").max_width()
    if vim_item.text ~= nil then
        if vim.startswith(vim_item.text, "•") then
            table.insert(vim_item.highlights, 1, {
                config.ls.clangd.import_dot_hl,
                range = { 0, 3 },
            })
        end
        vim_item.text = vim_item.text:gsub(";", " ")
        -- If it is already overflow, just return.
        if max_width and max_width > 0 then
            local display_width = vim.fn.strdisplaywidth(vim_item.text)
            if display_width >= max_width then
                return vim_item
            end
        end

        -- Append path.
        local document = completion_item.documentation
        if document and document.value and vim.startswith(document.value, "From ") then
            local len = #vim_item.text
            local include_path = vim.trim(vim.split(document.value:gsub("\r\n?", "\n"), "\n")[1])
                :sub(6, #document.value)
            if include_path:sub(1, 1) == "`" and include_path:sub(#include_path, #include_path) == "`" then
                include_path = include_path:sub(2, #include_path - 1)
            end
            local spaces = path_align_spaces(vim_item.text, include_path)
            vim_item.text = string.gsub(vim_item.text .. spaces .. include_path, "\n", " ")
            table.insert(vim_item.highlights, {
                config.ls.clangd.extra_info_hl,
                range = { len + #spaces, #vim_item.text },
            })
        end
    end
    return vim_item
end

return M

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
local function _lua_compute_completion_highlights(completion_item, ls)
    local label = completion_item.label
    local kind = completion_item.kind

    if not kind then
        return utils.highlight_range(label, ls, 0, #label)
    end

    if kind == Kind.Field then
        local text = string.format("%s", label)
        local source = string.format("v.%s", text)
        return utils.highlight_range(source, ls, 2, 2 + #text)
    end

    local highlight_name
    if kind == Kind.Constant then
        highlight_name = "@constant.lua"
    elseif kind == Kind.Function or kind == Kind.Method then
        highlight_name = "@function.lua"
    elseif kind == Kind.Property then
        highlight_name = "@property.lua"
    elseif kind == Kind.Variable then
        highlight_name = "@variable.lua"
    elseif kind == Kind.Keyword then
        highlight_name = "@keyword.lua"
    else
        highlight_name = config.fallback_highlight
    end

    return {
        text = label,
        highlights = {
            {
                highlight_name,
                range = { 0, #label },
            },
        },
    }
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.lua_ls(completion_item, ls)
    local vim_item = _lua_compute_completion_highlights(completion_item, ls)
    if vim_item.text ~= nil then
        local s, e = string.find(vim_item.text, "%b()")
        if s ~= nil and e ~= nil then
            table.insert(vim_item.highlights, {
                config.ls.lua_ls.arguments_hl,
                range = { s - 1, e },
            })
        end
    end
    return vim_item
end

return M

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local insertTextFormat = require("colorful-menu").insertTextFormat
local config = require("colorful-menu").config

local M = {}

local function align_spaces(abbr, detail)
    if config.ls["rust-analyzer"].align_type_to_right == false then
        return " "
    end
    return utils.align_spaces_bell(abbr, detail)
end

local cashed_self_hl = nil
---@return CMHighlightRange[]
local function iter_chain()
    if cashed_self_hl == nil then
        local source = "fn iter(){}"
        local hl = utils.highlight_range(source, "rust-analyzer", 3, #source - 2)
        cashed_self_hl = hl.highlights
    end
    return cashed_self_hl
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
local function _rust_analyzer(completion_item, ls)
    local label = completion_item.label
    local detail = completion_item.labelDetails and completion_item.labelDetails.detail or completion_item.detail
    local function_signature = completion_item.labelDetails and completion_item.labelDetails.description
        or completion_item.detail

    local kind = completion_item.kind
    if not kind then
        return utils.highlight_range(completion_item.label, ls, 0, #completion_item.label)
    end

    if kind == Kind.Field and detail then
        local name = completion_item.label
        local text = string.format("%s:%s%s", name, align_spaces(name .. " ", detail), detail)
        local source = string.format("struct S { %s }", text)
        local hl = utils.highlight_range(source, ls, 11, 11 + #text)
        if config.ls["rust-analyzer"].align_type_to_right == false then
            return hl
        end
        hl.text = hl.text:sub(1, #name) .. " " .. hl.text:sub(#name + 2, #text)
        return hl
        --
    elseif
        completion_item.insertTextFormat == insertTextFormat.Snippet
        and (label:find("::", nil, true) ~= nil or label == "Some(…)" or label == "None" or label == "Ok(…)" or label == "Err(…)")
        and label:sub(1, 1) >= "A"
        and label:sub(1, 1) <= "Z"
    then
        local source = string.format("match s { %s }", label)
        return utils.highlight_range(source, ls, 10, 10 + #label)
    elseif
        (kind == Kind.Constant or kind == Kind.Variable)
        and detail
        and completion_item.insertTextFormat ~= insertTextFormat.Snippet
    then
        local name = completion_item.label
        local text = string.format(
            "%s:%s%s",
            name,
            align_spaces(name .. " ", completion_item.detail),
            completion_item.detail or detail
        )
        local source = string.format("let %s = ();", text)
        local hl = utils.highlight_range(source, ls, 4, 4 + #text)
        if config.ls["rust-analyzer"].align_type_to_right == false then
            return hl
        end
        hl.text = hl.text:sub(1, #name) .. " " .. hl.text:sub(#name + 2, #text)
        return hl
        --
    elseif (kind == Kind.EnumMember) and detail then
        local source = string.format("enum S { %s }", detail)
        return utils.highlight_range(source, ls, 9, 9 + #detail)
        --
    elseif (kind == Kind.Function or kind == Kind.Method) and detail then
        local pattern = "%((.-)%)"

        local ignored = nil
        if label:match("^iter%(%)%..+") ~= nil then
            ignored = "iter()."
            label = completion_item.label:sub(string.len(ignored) + 1)
        end
        if label:match("^self%..+") ~= nil then
            ignored = "self."
            label = completion_item.label:sub(string.len(ignored) + 1)
        end
        local function adjust(hl)
            if ignored == "self." then
                utils.adjust_range(hl, string.len(ignored) + 1, ignored)
            elseif ignored == "iter()." then
                utils.adjust_range(hl, string.len(ignored) + 1, ignored, nil, iter_chain())
            end
        end

        local result = string.match(label, pattern)
        if not result then
            label = label .. "()"
        end
        local regex_pattern = "%b()"
        local prefix, suffix = string.match(function_signature or "", "^(.*fn)(.*)$")
        if prefix ~= nil and suffix ~= nil then
            local start_pos = string.find(suffix, "(", nil, true)
            if start_pos then
                suffix = suffix:sub(start_pos, #suffix)
            end

            if
                config.ls["rust-analyzer"].preserve_type_when_truncate
                and config.ls["rust-analyzer"].align_type_to_right
            then
                local params, type = string.match(suffix, "(%b()) %-> (.*)")
                if params == nil and type == nil then
                    params = suffix
                    type = ""
                end
                local call, num_subs = string.gsub(label, regex_pattern, params, 1)
                if num_subs == 0 then
                    call = completion_item.label
                end
                local source = string.format(
                    "%s %s->%s%s{}",
                    prefix,
                    call,
                    align_spaces(call .. "  ", ignored ~= nil and type .. ignored or type),
                    type or ""
                )
                local hl = utils.highlight_range(source, ls, #prefix + 1, #source - 2)
                hl.text = hl.text:sub(1, #call) .. "  " .. hl.text:sub(#call + 3)
                if ignored ~= nil then
                    adjust(hl)
                end
                return hl
            else
                local call, num_subs = string.gsub(label, regex_pattern, suffix, 1)
                if num_subs == 0 then
                    call = label
                end
                local source = string.format("%s %s {}", prefix, call)
                local hl = utils.highlight_range(source, ls, #prefix + 1, #source - 3)
                if ignored ~= nil then
                    adjust(hl)
                end
                return hl
            end
        else
            -- Check if the detail starts with "macro_rules! "
            if completion_item.detail and vim.startswith(completion_item.detail, "macro") then
                local source = completion_item.label
                return utils.highlight_range(source, ls, 0, #source)
            else
                -- simd_swizzle!()
                return {
                    text = completion_item.label,
                    highlights = {
                        {
                            config.fallback_highlight,
                            range = { 0, #completion_item.label },
                        },
                    },
                }
            end
        end
        --
    else
        local highlight_name = nil
        if kind == Kind.Struct then
            highlight_name = "@type"
        elseif kind == Kind.Enum then
            highlight_name = utils.hl_exist_or("@lsp.type.enum", "@type", "rust")
        elseif kind == Kind.EnumMember then
            highlight_name = utils.hl_exist_or("@lsp.type.enumMember", "@constant", "rust")
        elseif kind == Kind.Interface then
            highlight_name = utils.hl_exist_or("@lsp.type.interface", "@type", "rust")
        elseif kind == Kind.Keyword then
            highlight_name = "@keyword"
        elseif kind == Kind.Value or kind == Kind.Constant then
            highlight_name = "@constant"
        else
            highlight_name = config.fallback_highlight
        end

        if detail then
            detail = vim.trim(detail)
            if vim.startswith(detail, "(") then
                local space = align_spaces(completion_item.label, detail)
                return {
                    text = completion_item.label .. space .. detail,
                    highlights = {
                        {
                            highlight_name,
                            range = { 0, #completion_item.label },
                        },
                        {
                            config.ls["rust-analyzer"].extra_info_hl,
                            range = { #completion_item.label + #space, #completion_item.label + #space + #detail },
                        },
                    },
                }
            end
        end

        return {
            text = completion_item.label,
            highlights = {
                {
                    highlight_name,
                    range = { 0, #completion_item.label },
                },
            },
        }
    end
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.rust_analyzer(completion_item, ls)
    local vim_item = _rust_analyzer(completion_item, ls)
    if vim_item.text ~= nil then
        for _, match in ipairs({ "%(use .-%)", "%(as .-%)", "%(alias .-%)" }) do
            local s, e = string.find(vim_item.text, match)
            if s ~= nil and e ~= nil then
                table.insert(vim_item.highlights, {
                    config.ls["rust-analyzer"].extra_info_hl,
                    range = { s - 1, e },
                })
            end
        end
    end
    return vim_item
end

return M

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

local function align_spaces(abbr, detail)
    if config.ls.zls.align_type_to_right == false then
        return " "
    end
    return utils.align_spaces(abbr, detail)
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.zls(completion_item, ls)
    local label = completion_item.label
    local detail = completion_item.detail
        or (completion_item.labelDetails and completion_item.labelDetails.detail or completion_item.detail)
    if detail ~= nil then
        detail = vim.split(detail, "\n")[1]
    end
    local kind = completion_item.kind

    if not kind then
        return utils.highlight_range(label, ls, 0, #label)
    end

    if (kind == Kind.Constant or kind == Kind.Variable or kind == Kind.Struct or kind == Kind.Enum) and detail then
        if detail == "type" then
            local source = string.format("fn(s: %s)", label)
            return utils.highlight_range(source, ls, 6, 6 + #label)
        else
            local text = string.format("%s:%s%s", label, align_spaces(label, detail .. " "), detail)
            local source = string.format("fn(%s)", text)
            local hl = utils.highlight_range(source, ls, 3, 3 + #text)
            for _, highlight in ipairs(hl.highlights) do
                if vim.startswith(highlight[1], "@variable.parameter") then
                    highlight[1] = highlight[1]:gsub("%.parameter", "")
                end
            end
            if config.ls.zls.align_type_to_right == false then
                return hl
            end
            hl.text = hl.text:sub(1, #label) .. " " .. hl.text:sub(#label + 2, #text)
            return hl
        end
        --
    elseif (kind == Kind.Field or kind == Kind.EnumMember) and detail then
        -- For some reason `const x = struct { name: *Foo }` can't get the type color for Foo.
        -- Here is the trick:
        -- xfn(foo:     *Foo)
        -- x            *Foo
        local source = string.format("%sfn(foo:%s%s)", label, align_spaces(label, detail), detail)
        local items = utils.highlight_range(
            source:sub(#label + 1),
            ls,
            config.ls.zls.align_type_to_right and 7 or 6,
            #source:sub(#label + 1) - 1
        )
        return utils.adjust_range(
            items,
            #label + 1,
            source,
            utils.hl_exist_or("@lsp.type.property", "@variable.member", "zig")
        )
    elseif (kind == Kind.Function or kind == Kind.Method) and detail then
        if detail:sub(1, 2) == "fn" then
            local ret_type = vim.split(
                (vim.tbl_get(completion_item, "labelDetails", "description") or ""):gsub("\r\n?", "\n"),
                "\n"
            )[1]
            local params =
                vim.split((vim.tbl_get(completion_item, "labelDetails", "detail") or ""):gsub("\r\n?", "\n"), "\n")[1]
            local text, source
            if ret_type ~= "" and params ~= "" and config.ls.zls.align_type_to_right then
                text = string.format("%s%s%s%s", label, params, align_spaces(label .. params, ret_type), ret_type)
                source = string.format("fn %s {}", text)
            else
                local signature = detail:sub(4)
                text = string.format("%s%s", label, signature)
                source = string.format("fn %s {}", text)
            end
            return utils.highlight_range(source, ls, 3, 3 + #text)
        elseif detail:sub(1, 1) == "@" then
            return utils.highlight_range(detail, ls, 0, #detail)
        else
            return {
                text = completion_item.label,
                highlights = {
                    {
                        "@function",
                        range = { 0, #completion_item.label },
                    },
                },
            }
        end
        --
    else
        local highlight_name = nil
        if kind == Kind.Keyword then
            highlight_name = "@keyword"
        elseif kind == Kind.Field then
            highlight_name = utils.hl_exist_or("@lsp.type.property", "@variable.member", "zig")
        else
            highlight_name = config.fallback_highlight
        end
        return {
            text = completion_item.label,
            highlights = {
                {
                    highlight_name,
                    range = { 0, #completion_item.label },
                },
            },
        }
    end
end

return M

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.intelephense(completion_item, ls)
    local label = completion_item.label
    local detail = completion_item.labelDetails and completion_item.labelDetails.detail or completion_item.detail
    local kind = completion_item.kind

    if (kind == Kind.Function or kind == Kind.Method) and detail and #detail > 0 then
        local signature = detail:sub(#label + 1)
        local text = string.format("%s <?php fn %s {}", label, signature)
        local item = utils.highlight_range(text, ls, 6 + #label, #text - 2)
        return utils.adjust_range(item, #label + 1, label)
        --
    elseif kind == Kind.EnumMember and detail and #detail > 0 then
        local text = string.format("%s <?php %s;", label, detail)
        local item = utils.highlight_range(text, ls, #label + 6, #text - 1)
        return utils.adjust_range(item, #label + 1, label)
        --
    elseif (kind == Kind.Property or kind == Kind.Variable) and detail and #detail > 0 then
        detail = string.gsub(detail, ".*\\(.)", "%1")
        local text = string.format("%s <?php fn(): %s;", label, detail)
        local item = utils.highlight_range(text, ls, #label + 12, #text - 1)
        return utils.adjust_range(item, #label + 1, label)
        --
    elseif kind == Kind.Constant and detail and #detail > 0 then
        local text = string.format("%s <?php %s;", label, detail)
        local item = utils.highlight_range(text, ls, #label + 6, #text - 1)
        return utils.adjust_range(item, #label + 1, label)
        --
    else
        -- Handle other kinds
        local highlight_name = nil
        if kind == Kind.Keyword then
            highlight_name = "@keyword"
        else
            highlight_name = config.fallback_highlight
        end

        return {
            text = completion_item.label,
            highlights = {
                {
                    highlight_name,
                    range = { 0, #completion_item.label },
                },
            },
        }
    end
end

return M

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

local function parse_signature(signature)
    local params, returns = "", ""
    local pm, rm = signature:match("^(%b())%s*(%(?.*%)?)")
    params = pm ~= nil and pm or ""
    returns = rm ~= nil and rm or ""
    return params, returns
end

local function align_spaces(abbr, detail)
    if config.ls.gopls.align_type_to_right == false then
        return " "
    end
    return utils.align_spaces_bell(abbr, detail)
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.gopls(completion_item, ls)
    if config.ls.gopls.align_type_to_right then
        -- This makes no sense then.
        config.ls.gopls.add_colon_before_type = false
    end

    local label = completion_item.label
    local kind = completion_item.kind
    local detail = completion_item.labelDetails and completion_item.labelDetails.detail or completion_item.detail
    if detail then
        -- In unimported one, we remove useless information
        -- assign.Analyzer var from("golang.org/x/tools/go/analysis/passes/assign")
        -- =>
        -- assign.Analyzer "golang.org/x/tools/go/analysis/passes/assign"
        local path = detail:match(".*%(from(.*)%)")
        if path then
            local highlight_name = utils.hl_by_kind(kind)
            local spaces = align_spaces(label, path)
            local text = label .. align_spaces(label, path) .. path
            return {
                text = text,
                highlights = {
                    {
                        highlight_name,
                        range = { 0, #label },
                    },
                    {
                        "@string",
                        range = { #label + #spaces, #text },
                    },
                },
            }
        end
    end

    if not kind then
        return utils.highlight_range(label, ls, 0, #label)
    end

    -- Gopls returns nested fields and methods as completions.
    -- To syntax highlight these, combine their final component
    -- with their detail.
    local name_offset = label:reverse():find("%.") or 0
    if name_offset > 0 then
        name_offset = #label - name_offset + 2
    else
        name_offset = 0
    end

    if kind == Kind.Module and detail then
        local text = string.format("%s%s%s", label, align_spaces(label, detail), detail)
        local source = string.format("import %s", text)
        return utils.highlight_range(source, ls, 7, 7 + #text)
        --
    elseif (kind == Kind.Constant or kind == Kind.Variable) and detail then
        local text
        if config.ls.gopls.add_colon_before_type then
            text = string.format("%s:%s%s", label, align_spaces(label, detail), detail)
        else
            text = string.format("%s%s%s", label, align_spaces(label, detail), detail)
        end
        local var_part = text:sub(name_offset)
        local source = string.format("var %s", var_part)
        local item = utils.highlight_range(source, ls, 4, 4 + #var_part)
        if kind == Kind.Constant then
            if #item.highlights >= 1 then
                item.highlights[1][1] = utils.hl_exist_or("@constant", "@variable", "go")
            end
        end
        return utils.adjust_range(item, name_offset, text)
        --
    elseif kind == Kind.Struct then
        detail = "struct{}"
        local text = string.format("%s%s%s", label, align_spaces(label, detail), detail)
        local source = string.format("type %s struct {}", text:sub(name_offset))
        local item = utils.highlight_range(source, ls, 5, 5 + #text:sub(name_offset))
        return utils.adjust_range(item, name_offset, text)
        --
    elseif kind == Kind.Interface then
        detail = "interface{}"
        local text = string.format("%s%s%s", label, align_spaces(label, detail), detail)
        local source = string.format("type %s interface {}", text:sub(name_offset))
        local item = utils.highlight_range(source, ls, 5, 5 + #text:sub(name_offset))
        return utils.adjust_range(item, name_offset, text)
        --
    elseif kind == Kind.Field and detail then
        local text
        if config.ls.gopls.add_colon_before_type then
            text = string.format("%s:%s%s", label, align_spaces(label, detail), detail)
        else
            text = string.format("%s%s%s", label, align_spaces(label, detail), detail)
        end
        local source = string.format("type T struct { %s }", text:sub(name_offset))
        local item = utils.highlight_range(source, ls, 16, 16 + #text:sub(name_offset))
        return utils.adjust_range(item, name_offset, text)
        --
    elseif (kind == Kind.Function or kind == Kind.Method) and detail then
        local signature = vim.trim(detail)
        if detail:sub(1, 4) == "func" then
            signature = detail:sub(5)
        end

        local text = string.format("%s%s", label, signature)
        if signature ~= "()" then
            local params, returns = parse_signature(signature)
            text = label .. params .. align_spaces(label, params .. returns) .. returns
        end

        local source = string.format("func %s {}", text:sub(name_offset))
        local item = utils.highlight_range(source, ls, 5, 5 + #text:sub(name_offset))
        return utils.adjust_range(item, name_offset, text)
        --
    else
        -- Handle other kinds
        local highlight_name = nil
        if kind == Kind.Keyword then
            highlight_name = "@keyword"
        else
            highlight_name = config.fallback_highlight
        end
        return {
            text = completion_item.label,
            highlights = {
                {
                    highlight_name,
                    range = { 0, #completion_item.label },
                },
            },
        }
    end
end

return M

local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

local query_cache = {}

---@param str string
---@param ls string
---@return CMHighlights
local function compute_highlights(str, ls)
    local highlights = {}

    local lang = vim.treesitter.language.get_lang(vim.bo.filetype)
    if not lang then
        return {}
    end

    local query, ok
    if query_cache[ls] == nil then
        ok, query = pcall(vim.treesitter.query.get, lang, "highlights")
        if not ok then
            return {}
        end
        query_cache[ls] = query
    else
        query = query_cache[ls]
    end

    ---@diagnostic disable-next-line: redefined-local
    local ok, parser = pcall(vim.treesitter.get_string_parser, str, lang)
    if not ok then
        return {}
    end

    if not parser then
        vim.notify(string.format("No Tree-sitter parser found for filetype: %s", lang), vim.log.levels.WARN)
        return highlights
    end

    -- Parse the string
    local tree = parser:parse(true)[1]
    if not tree then
        vim.notify("Failed to parse the string with Tree-sitter.", vim.log.levels.ERROR)
        return {}
    end

    local root = tree:root()

    if not query then
        return {}
    end

    -- Iterate over all captures in the query
    for id, node in query:iter_captures(root, str, 0, -1) do
        local name = "@" .. query.captures[id] .. "." .. lang
        local range = { node:range() }
        local _, nscol, _, necol = range[1], range[2], range[3], range[4]
        table.insert(highlights, {
            hl_group = name,
            range = { nscol, necol },
        })
    end

    return highlights
end

-- `left` is inclusive and `right` is exclusive (also zero indexed), to better fit
-- `nvim_buf_set_extmark` semantic, so `M.highlight_range(text, ft, 0, #text)` is the entire range.
--
---@param text string
---@param ls string
---@param left integer
---@param right integer
---@return CMHighlights
function M.highlight_range(text, ls, left, right)
    local highlights = {}
    local full_hl = compute_highlights(text, ls)

    for _, hl in ipairs(full_hl) do
        local s, e = hl.range[1], hl.range[2]
        if e < left then
            goto continue
        end
        if s > right or e > right + 1 then
            break
        end

        table.insert(highlights, {
            hl.hl_group,
            range = { hl.range[1] - left, hl.range[2] - left },
            text = text:sub(s + 1, e),
        })
        ::continue::
    end

    return {
        text = text:sub(left + 1, right),
        highlights = highlights,
    }
end

-- Shift a highlight range right by name_offset,
-- insert a color with fallback_hl for label with range (0, name_offset).
---@param item CMHighlights
---@param name_offset integer
---@param label string
---@param fallback_hl string?
---@param custom_hl CMHighlightRange[]?
---@return CMHighlights
function M.adjust_range(item, name_offset, label, fallback_hl, custom_hl)
    if name_offset == 0 then
        return item
    end
    name_offset = name_offset - 1
    for _, highlight in ipairs(item.highlights) do
        highlight.range[1] = highlight.range[1] + name_offset
        highlight.range[2] = highlight.range[2] + name_offset
    end
    item.text = label:sub(1, name_offset) .. item.text
    if custom_hl then
        for _, hl in ipairs(custom_hl) do
            table.insert(item.highlights, hl)
        end
    else
        table.insert(item.highlights, {
            fallback_hl or "@variable",
            range = { 0, name_offset },
        })
    end
    return item
end

---@param hl_group string
---@param fallback string
---@param lang? string
function M.hl_exist_or(hl_group, fallback, lang)
    local f = function()
        local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = hl_group })
        if ok and hl ~= nil and not vim.tbl_isempty(hl) then
            return hl_group
        end
        return fallback
    end

    local ok, hl
    if lang ~= nil then
        local lang_hl = hl_group .. "." .. lang
        ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = lang_hl })
        if ok and hl ~= nil and not vim.tbl_isempty(hl) then
            return lang_hl
        else
            return f()
        end
    else
        return f()
    end
end

---@param kind? integer
---@param lang? string
---@return string
function M.hl_by_kind(kind, lang)
    local highlight_name
    if kind == Kind.Method then
        highlight_name = M.hl_exist_or("@lsp.type.method", "@function", lang)
    elseif kind == Kind.Function then
        highlight_name = M.hl_exist_or("@lsp.type.function", "@function", lang)
    elseif kind == Kind.Constructor then
        highlight_name = "@constructor"
    elseif kind == Kind.Variable then
        highlight_name = M.hl_exist_or("@lsp.type.variable", "@variable", lang)
    elseif kind == Kind.Field then
        highlight_name = M.hl_exist_or("@lsp.type.field", "@field", lang)
    elseif kind == Kind.Keyword then
        highlight_name = "@keyword"
    elseif kind == Kind.Property then
        highlight_name = M.hl_exist_or("@lsp.type.property", "@property", lang)
    elseif kind == Kind.Module then
        highlight_name = M.hl_exist_or("@lsp.type.namespace", "@namespace", lang)
    elseif kind == Kind.Class then
        highlight_name = M.hl_exist_or("@lsp.type.class", "@type", lang)
    elseif kind == Kind.Struct then
        highlight_name = M.hl_exist_or("@lsp.type.struct", "@type", lang)
    elseif kind == Kind.Constant then
        highlight_name = "@constant"
    else
        highlight_name = config.fallback_highlight
    end

    return highlight_name
end

---@param item CMHighlights
---@param rang {left:integer, right:integer}
local function remove_color_in_range(item, rang)
    for i = #item.highlights, 1, -1 do
        local hl = item.highlights[i]
        local r = hl.range
        if r[1] > rang.left and r[1] < rang.right then
            table.remove(item.highlights, i)
        elseif r[1] <= rang.left and r[2] > rang.left then
            r[2] = rang.left
        end
    end
end

local function left_brace_one_more_than_right_brace(s)
    local left = 0
    local right = 0
    for i = 1, #s do
        local char = s:sub(i, i)
        if char == "(" then
            left = left + 1
        elseif char == ")" then
            right = right + 1
        end
    end
    return left == right + 1
end

---@param item CMHighlights
---@param max_width integer
---@param direct boolean -- without type info
local function cut_label(item, max_width, direct)
    if vim.fn.strdisplaywidth(item.text) <= max_width then
        return
    end
    local text = item.text
    --- Given
    --- self.foo(asdasd)
    --- self.foo(asdasd…
    --- self.foo(asdas…)
    if direct and left_brace_one_more_than_right_brace(vim.fn.strcharpart(text, 0, max_width)) then
        local truncated = vim.fn.strcharpart(text, 0, max_width - 2) .. "…)"
        item.text = truncated
        local truncated_width = #truncated
        remove_color_in_range(item, { left = truncated_width, right = math.huge })
        table.insert(item.highlights, {
            "@comment",
            range = { truncated_width - 4, truncated_width - 1 },
        })
        table.insert(item.highlights, {
            "@punctuation.bracket",
            range = { truncated_width - 1, truncated_width },
        })
    else
        local truncated = vim.fn.strcharpart(text, 0, max_width - 1) .. "…"
        item.text = truncated
        local truncated_width = #truncated
        remove_color_in_range(item, { left = truncated_width, right = math.huge })
        table.insert(item.highlights, {
            "@comment",
            range = { truncated_width - 3, truncated_width },
        })
    end
end

---@param item CMHighlights
---@param offset integer
---@param start integer
local function shift_color_by(item, offset, start)
    for _, highlight in ipairs(item.highlights) do
        if highlight.range[1] > start then
            highlight.range[1] = highlight.range[1] - offset
            highlight.range[2] = highlight.range[2] - offset
        end
    end
end

---@param completion_item lsp.CompletionItem
---@param item CMHighlights
function M.validate_newline(completion_item, item)
    if string.find(item.text, "\n") ~= nil or string.find(item.text, "\r") ~= nil then
        vim.notify_once(
            '[colorful-menu.nvim]: Completion "'
                .. completion_item.label
                .. '" has new line character, please open an issue',
            vim.log.levels.WARN
        )
        return require("colorful-menu.languages.default").default_highlight(
            completion_item,
            nil,
            nil,
            require("colorful-menu").config.ls.fallback_extra_info_hl
        )
    end
    return item
end

---@param item CMHighlights
---@param ls string
---@return CMHighlights?
function M.apply_post_processing(completion_item, item, ls)
    -- if the user override or fallback logic didn't produce a table, bail
    if type(item) ~= "table" or not item.text then
        return item
    end

    for i = #item.highlights, 1, -1 do
        local hl = item.highlights[i]
        local range = hl.range
        if range[2] < 0 then
            table.remove(item.highlights, i)
        elseif range[1] < 0 then
            range[1] = 0
        end
    end

    local max_width = require("colorful-menu.utils").max_width()
    if not (max_width and max_width > 0) then
        return
    end

    local label = completion_item.label
    local display_width = vim.fn.strdisplaywidth(item.text)
    if display_width > (item.text:find("\7") ~= nil and (max_width + 1) or max_width) then
        local long_label, type = item.text:match("(.*)\7%s*(.*)")
        local is_func = completion_item.kind == Kind.Function or completion_item.kind == Kind.Method
        if
            item.text == label
            or type == nil
            or #type == 0
            or not is_func
            or not config.ls[ls]
            or not config.ls[ls].preserve_type_when_truncate
        then
            item.text = item.text:gsub("\7", " ")
            cut_label(item, max_width, is_func)
            return
        end

        local _, le = item.text:find("\7")
        local ts = item.text:find(type, le, true)
        local space_between = ts - le
        item.text = item.text:gsub("\7", " ")

        -- Now we need to deal with color shifting stuff.
        -- Foo(a string b string) "some random stuff"
        -- |                    | |                 |
        --   long_label_width           type_width
        --
        -- | short |  |  type_width     |
        -- Foo(a st…  "some random stuff"
        -- |         max_width          |
        local long_label_width, type_width = #long_label, #type
        local short_label_width = math.max(max_width - type_width - 2 - space_between, #label)
        local should_cut_all = short_label_width == #label
        if should_cut_all then
            remove_color_in_range(item, { left = short_label_width, right = long_label_width })
            local pretty_end = "(…)"
            if label:sub(short_label_width, short_label_width) == ")" then
                pretty_end = "…)"
            end
            shift_color_by(item, long_label_width - short_label_width - string.len(pretty_end), long_label_width)
            item.text = item.text:sub(1, short_label_width) .. pretty_end .. item.text:sub(long_label_width + 1)
            table.insert(item.highlights, {
                "@comment",
                range = {
                    short_label_width + (pretty_end == "(…)" and 1 or 0),
                    short_label_width + (pretty_end == "(…)" and string.len("…)") or string.len("…")),
                },
            })
            cut_label(item, max_width, false)
        else
            -- Caculate display_width and real byte diff.
            local diff = short_label_width - vim.fn.strdisplaywidth(item.text:sub(1, short_label_width))
            -- We increase the cut threshold if display_width is lower than
            -- byte count, otherwise the hole is not enough.
            short_label_width = short_label_width + diff
            local ascii_pos = short_label_width
            for i = short_label_width, 1, -1 do
                if item.text:sub(i, i):match("[a-zA-Z(]") ~= nil then
                    ascii_pos = i
                    break
                end
            end
            remove_color_in_range(item, { left = ascii_pos, right = long_label_width })
            shift_color_by(item, long_label_width - short_label_width - string.len("…)"), long_label_width)
            item.text = item.text:sub(1, ascii_pos)
                .. "…)"
                .. string.rep(" ", short_label_width - ascii_pos)
                .. item.text:sub(long_label_width + 1)
            table.insert(item.highlights, {
                "@comment",
                range = { ascii_pos, ascii_pos + string.len("…)") - 1 },
            })
        end
    else
        item.text = item.text:gsub("\7", " ")
    end
end

function M.align_spaces_bell(abbr, detail)
    local blank = M.max_width() - vim.fn.strdisplaywidth(abbr) - vim.fn.strdisplaywidth(detail)
    if blank <= 2 then
        return "\7  "
    end
    return "\7" .. string.rep(" ", blank - 1)
end

function M.align_spaces(abbr, detail)
    local blank = M.max_width() - vim.fn.strdisplaywidth(abbr) - vim.fn.strdisplaywidth(detail)
    if blank <= 2 then
        return "   "
    end
    return string.rep(" ", blank)
end

function M.max_width()
    local max_width = config.max_width
    if max_width < 1 and max_width > 0 then
        max_width = math.floor(max_width * vim.api.nvim_win_get_width(0))
    end
    return max_width
end

return M

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

local function align_spaces(abbr, detail)
    return utils.align_spaces(abbr, detail)
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.dartls(completion_item, ls)
    local label = completion_item.label
    local kind = completion_item.kind
    local detail = completion_item.labelDetails and completion_item.labelDetails.detail or completion_item.detail
    if detail ~= nil and detail:find("Auto") ~= nil then
        detail = detail:gsub("Auto import.*\n\n", "")
        detail = vim.split(detail:gsub("\r\n?", "\n"), "\n")[1]
    end

    if not kind then
        return utils.highlight_range(label, ls, 0, #label)
    end

    if (kind == Kind.Constant or kind == Kind.Variable) and detail then
        -- x int
        local text = string.format("%s%s%s", label, align_spaces(label, detail), detail)
        -- var x int x
        local source = string.format("var %s x", text)
        return utils.highlight_range(source, ls, 4, 4 + #text)
        --
    elseif (kind == Kind.Field or kind == Kind.Property) and detail then
        -- Here is the trick same as zls:
        -- xvoid(       *Foo)
        -- x            *Foo
        local source = string.format("%svoid(%s%s)", label, align_spaces(label, detail), detail)
        local items = utils.highlight_range(source:sub(#label + 1), ls, 5, #source:sub(#label + 1) - 1)
        return utils.adjust_range(
            items,
            #label + 1,
            source,
            utils.hl_exist_or("@lsp.type.property", "@variable.member", "dart")
        )
        --
    elseif (kind == Kind.Function or kind == Kind.Method or kind == Kind.Constructor) and detail then
        -- elseif (kind == Kind.Function or kind == Kind.Method) and detail then
        -- label: fetchData(..)
        -- detail: (int a, int b) -> Future<String>
        -- fetchData(int a, int b);(Future<String> s)
        local params = string.match(detail or "", "^(%b())")
        local type = string.match(detail or "", "→ (.*)")
        if params ~= nil then
            label = label:gsub("%b()$", "") .. params
        end
        if type ~= nil and kind ~= Kind.Constructor then
            local text = string.format("%s%s;(%s)", label, align_spaces(label, type):sub(3), type)
            local comma_pos = #text - #type - 3
            local ranges = utils.highlight_range(text, ls, 0, #text - 1)
            ranges.text = ranges.text:sub(1, comma_pos) .. "  " .. ranges.text:sub(comma_pos + 3, #ranges.text)
            return ranges
        end
        return utils.highlight_range(label, ls, 0, #label)
        --
    else
        return require("colorful-menu.languages.default").default_highlight(
            completion_item,
            detail,
            "dart",
            config.ls[ls].extra_info_hl
        )
    end
end

return M

local M = {}

M.insertTextFormat = { PlainText = 1, Snippet = 2 }
-- stylua: ignore
M.Kind = { Text = 1, Method = 2, Function = 3, Constructor = 4, Field = 5, Variable = 6, Class = 7, Interface = 8, Module = 9, Property = 10, Unit = 11, Value = 12, Enum = 13, Keyword = 14, Snippet = 15, Color = 16, File = 17, Reference = 18, Folder = 19, EnumMember = 20, Constant = 21, Struct = 22, Event = 23, Operator = 24, TypeParameter = 25 }

---@alias CMHighlightRange {hl_group: string, range: integer[], text: string}
---
---@class CMHighlights
---@field text string
---@field highlights CMHighlightRange[]

---@class ColorfulMenuConfig
M.config = {
    ls = {
        lua_ls = {
            -- Maybe you want to dim arguments a bit.
            arguments_hl = "@comment",
        },
        gopls = {
            -- When true, label for field and variable will format like "foo: Foo"
            -- instead of go's original syntax "foo Foo".
            add_colon_before_type = false,
            align_type_to_right = true,
            -- See https://github.com/xzbdmw/colorful-menu.nvim/pull/36
            preserve_type_when_truncate = true,
        },
        ts_ls = {
            -- false means do not include any extra info,
            -- see https://github.com/xzbdmw/colorful-menu.nvim/issues/42
            extra_info_hl = "@comment",
        },
        vtsls = {
            -- false means do not include any extra info,
            -- see https://github.com/xzbdmw/colorful-menu.nvim/issues/42
            extra_info_hl = "@comment",
        },
        zls = {
            align_type_to_right = true,
        },
        ["rust-analyzer"] = {
            -- Such as (as Iterator), (use std::io).
            extra_info_hl = "@comment",
            align_type_to_right = true,
            -- See https://github.com/xzbdmw/colorful-menu.nvim/pull/36
            preserve_type_when_truncate = true,
        },
        clangd = {
            -- Such as "<stdio.h>".
            extra_info_hl = "@comment",
            -- the hl of leading dot of "•std::filesystem::permissions(..)"
            import_dot_hl = "@comment",
            align_type_to_right = true,
            -- See https://github.com/xzbdmw/colorful-menu.nvim/pull/36
            preserve_type_when_truncate = true,
        },
        roslyn = {
            extra_info_hl = "@comment",
        },
        -- The same applies to pyright/pylance
        basedpyright = {
            extra_info_hl = "@comment",
        },
        pylsp = {
            extra_info_hl = "@comment",
            -- Dim the function argument area, which is the main
            -- difference with pyright.
            arguments_hl = "@comment",
        },
        dartls = {
            extra_info_hl = "@comment",
        },
        fallback = true,
        fallback_extra_info_hl = "@comment",
    },
    fallback_highlight = "@variable",
    max_width = 60,
}

local hl_cache = {}
local hl_cache_size = 0
-- about 30M max memory usage.
local MAX_HL_CACHE_SIZE = 10000

---@param completion_item lsp.CompletionItem
---@param ls string
---@return string
local function cache_key(completion_item, ls)
    return string.format(
        "%s!%s!%s!%s!%s%s",
        completion_item.label or "",
        completion_item.detail or "",
        completion_item.labelDetails
                and (completion_item.labelDetails.detail or "") .. (completion_item.labelDetails.description or "")
            or "",
        completion_item.kind and tostring(completion_item.kind) or "",
        ls,
        require("colorful-menu.utils").max_width()
    )
end

---@param completion_item lsp.CompletionItem
---@param ls string?
---@return CMHighlights?
local function _highlights(completion_item, ls)
    if completion_item == nil or ls == nil or ls == "" or vim.b.ts_highlight == false then
        return nil
    end

    local item

    local key = cache_key(completion_item, ls)
    if hl_cache[key] ~= nil then
        return hl_cache[key]
    end

    if ls == "gopls" then
        item = require("colorful-menu.languages.go").gopls(completion_item, ls)
        --
    elseif ls == "rust-analyzer" or ls == "rust_analyzer" then
        item = require("colorful-menu.languages.rust").rust_analyzer(completion_item, ls)
        ls = "rust-analyzer"
        --
    elseif ls == "lua_ls" then
        item = require("colorful-menu.languages.lua").lua_ls(completion_item, ls)
        --
    elseif ls == "clangd" then
        item = require("colorful-menu.languages.cpp").clangd(completion_item, ls)
        --
    elseif ls == "typescript-language-server" or ls == "ts_ls" or ls == "tsserver" or ls == "typescript-tools" then
        item = require("colorful-menu.languages.typescript").ts_server(completion_item, ls)
        --
    elseif ls == "vtsls" then
        item = require("colorful-menu.languages.typescript").vtsls(completion_item, ls)
        --
    elseif ls == "zls" then
        item = require("colorful-menu.languages.zig").zls(completion_item, ls)
        --
    elseif ls == "intelephense" then
        item = require("colorful-menu.languages.php").intelephense(completion_item, ls)
        --
    elseif ls == "roslyn" then
        item = require("colorful-menu.languages.cs").roslyn(completion_item, ls)
        --
    elseif ls == "dartls" then
        item = require("colorful-menu.languages.dart").dartls(completion_item, ls)
        --
    elseif ls == "basedpyright" or ls == "pyright" or ls == "pylance" or ls == "pylsp" then
        item = require("colorful-menu.languages.python").py(completion_item, ls)
        --
    else
        -- No languages detected so check if we should highlight with default or not
        if not M.config.ls.fallback then
            return nil
        end
        item = require("colorful-menu.languages.default").default_highlight(
            completion_item,
            completion_item.labelDetails and completion_item.labelDetails.detail or completion_item.detail,
            nil,
            M.config.ls.fallback_extra_info_hl
        )
    end

    if item then
        item = require("colorful-menu.utils").validate_newline(completion_item, item)
        require("colorful-menu.utils").apply_post_processing(completion_item, item, ls)
    end

    hl_cache_size = hl_cache_size + 1
    if hl_cache_size > MAX_HL_CACHE_SIZE then
        hl_cache_size = 0
        hl_cache = {}
    end
    hl_cache[key] = item

    return item
end

---@diagnostic disable-next-line: undefined-doc-name
---@param entry cmp.Entry
function M.cmp_highlights(entry)
    local client = vim.tbl_get(entry, "source", "source", "client") -- For example `lua_ls` etc
    if client and not client:is_stopped() then
        ---@diagnostic disable-next-line: undefined-field
        return _highlights(entry:get_completion_item(), client.name)
    end
    return nil
end

---@diagnostic disable-next-line: undefined-doc-name
---@param ctx blink.cmp.DrawItemContext
function M.blink_components_text(ctx)
    local highlights_info = M.blink_highlights(ctx)
    if highlights_info ~= nil then
        return highlights_info.label
    else
        ---@diagnostic disable-next-line: undefined-field
        return ctx.label
    end
end

---@diagnostic disable-next-line: undefined-doc-name
---@param ctx blink.cmp.DrawItemContext
function M.blink_components_highlight(ctx)
    local highlights = {}
    local highlights_info = M.blink_highlights(ctx)
    if highlights_info ~= nil then
        highlights = highlights_info.highlights
    end
    ---@diagnostic disable-next-line: undefined-field
    for _, idx in ipairs(ctx.label_matched_indices) do
        table.insert(highlights, { idx, idx + 1, group = "BlinkCmpLabelMatch" })
    end
    return highlights
end

---@diagnostic disable-next-line: undefined-doc-name
---@param ctx blink.cmp.DrawItemContext
function M.blink_highlights(ctx)
    ---@diagnostic disable-next-line: undefined-field
    local client = vim.lsp.get_client_by_id(ctx.item.client_id)
    local highlights = {}
    if client and not client:is_stopped() then
        ---@diagnostic disable-next-line: undefined-field
        local highlights_info = _highlights(ctx.item, client.name)
        if highlights_info ~= nil then
            for _, info in ipairs(highlights_info.highlights or {}) do
                table.insert(highlights, {
                    info.range[1],
                    info.range[2],
                    ---@diagnostic disable-next-line: undefined-field
                    group = ctx.deprecated and "BlinkCmpLabelDeprecated" or info[1],
                })
            end
        else
            return nil
        end
        return { label = highlights_info.text, highlights = highlights }
    end
    return nil
end

---@param completion_item lsp.CompletionItem
---@param ls string?
---@return CMHighlights?
function M.highlights(completion_item, ls)
    if ls == vim.bo.filetype then
        vim.notify_once(
            "colorful-menu.nvim: Integration with nvim-cmp or blink.cmp has been simplified, and legacy per-filetype options is also deprecated"
                .. " to prefer per-language-server options, please see README",
            vim.log.levels.WARN
        )
        return nil
    end

    return _highlights(completion_item, ls)
end

---@param opts ColorfulMenuConfig
function M.setup(opts)
    opts = opts or {}
    M.config = vim.tbl_deep_extend("force", M.config, opts)
end

return M

local utils = require("colorful-menu.utils")

local M = {}

---@param completion_item lsp.CompletionItem
---@param detail? string
---@param lang? string
---@param extra_info_hl? string
---@return CMHighlights
function M.default_highlight(completion_item, detail, lang, extra_info_hl)
    extra_info_hl = extra_info_hl or "@comment"
    local label = completion_item.label
    local highlight_name = utils.hl_by_kind(completion_item.kind, lang)

    local highlights = {
        {
            highlight_name,
            range = { 0, #label },
        },
    }

    local text = label
    if detail and string.find(detail, "\n") == nil and string.find(detail, "\r") == nil then
        local spaces = utils.align_spaces(label, detail)
        -- If there are any information, append it
        text = label .. spaces .. detail
        table.insert(highlights, {
            extra_info_hl,
            range = { #label + 1, #text },
        })
    end

    return {
        text = text,
        highlights = highlights,
    }
end

return M

local config = require("colorful-menu").config
local Kind = require("colorful-menu").Kind

local M = {}

---@param completion_item lsp.CompletionItem
---@return CMHighlights
local function pylsp(completion_item)
    local path = vim.tbl_get(completion_item, "labelDetails", "description")
    local hls = require("colorful-menu.languages.default").default_highlight(
        completion_item,
        path,
        "python",
        config.ls.pylsp.extra_info_hl
    )
    if hls.text ~= nil and (completion_item.kind == Kind.Function or completion_item.kind == Kind.Method) then
        local s, e = string.find(hls.text, "%b()")
        if s ~= nil and e ~= nil then
            table.insert(hls.highlights, {
                config.ls.pylsp.arguments_hl,
                range = { s - 1, e },
            })
        end
    end
    return hls
end

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.py(completion_item, ls)
    if ls == "pylsp" then
        return pylsp(completion_item)
    else
        local path = vim.tbl_get(completion_item, "labelDetails", "description")
        return require("colorful-menu.languages.default").default_highlight(
            completion_item,
            path,
            "python",
            config.ls.basedpyright.extra_info_hl
        )
    end
end

return M

local root = vim.fn.fnamemodify("./.repro", ":p")
-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
    vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end
-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
    vim.fn.system({
        "git",
        "clone",
        "--filter=blob:none",
        "--single-branch",
        "https://github.com/folke/lazy.nvim.git",
        lazypath,
    })
end
vim.opt.runtimepath:prepend(lazypath)
-- install plugins
local plugins = {
    -- do not remove the colorscheme!
    "folke/tokyonight.nvim",
    "neovim/nvim-lspconfig",
    {
        "hrsh7th/nvim-cmp",
        lazy = false,
        dependencies = {
            "hrsh7th/cmp-nvim-lsp",
            {
                "xzbdmw/colorful-menu.nvim",
                config = function()
                    require("colorful-menu").setup({})
                end,
            },
        },
        config = function(_, opts)
            local cmp = require("cmp")
            require("cmp").setup({
                mapping = cmp.mapping.preset.insert({
                    ["<cr>"] = cmp.mapping(function(fallback)
                        if cmp.visible() then
                            cmp.confirm()
                        end
                    end, { "i" }),
                }),
                completion = {
                    completeopt = "menu,menuone,noinsert",
                },
                formatting = {
                    format = function(entry, vim_item)
                        local highlights_info = require("colorful-menu").cmp_highlights(entry)
                        if highlights_info ~= nil then
                            vim_item.abbr_hl_group = highlights_info.highlights
                            vim_item.abbr = highlights_info.text
                        end
                        return vim_item
                    end,
                },
                sources = require("cmp").config.sources({
                    { name = "nvim_lsp" },
                }, {}),
            })
        end,
    },
}
require("lazy").setup(plugins, {
    root = root .. "/plugins",
})
require("lspconfig").lua_ls.setup({
    settings = {
        capabilities = require("cmp_nvim_lsp").default_capabilities(),
        Lua = {
            runtime = {
                version = "LuaJIT",
            },
            workspace = {
                library = {
                    "/usr/local/share/nvim/runtime",
                },
            },
            completion = {
                callSnippet = "Replace",
            },
        },
    },
})
vim.cmd([[colorscheme tokyonight]])

local root = vim.fn.fnamemodify("./.repro", ":p")
-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
    vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end
-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
    vim.fn.system({
        "git",
        "clone",
        "--filter=blob:none",
        "--single-branch",
        "https://github.com/folke/lazy.nvim.git",
        lazypath,
    })
end
vim.opt.runtimepath:prepend(lazypath)
-- install plugins
local plugins = {
    -- do not remove the colorscheme!
    "folke/tokyonight.nvim",
    "neovim/nvim-lspconfig",
    "xzbdmw/colorful-menu.nvim",
    {
        "saghen/blink.cmp",
        version = "v0.*",
        config = function()
            require("blink.cmp").setup({
                completion = {
                    menu = {
                        draw = {
                            -- We don't need label_description now because label and label_description are already
                            -- conbined together in label by colorful-menu.nvim.
                            columns = { { "kind_icon" }, { "label", gap = 1 } },
                            components = {
                                label = {
                                    text = require("colorful-menu").blink_components_text,
                                    highlight = require("colorful-menu").blink_components_highlight,
                                },
                            },
                        },
                    },
                },
            })
        end,
    },
}
require("lazy").setup(plugins, {
    root = root .. "/plugins",
})
require("lspconfig").lua_ls.setup({
    settings = {
        Lua = {
            runtime = {
                version = "LuaJIT",
            },
        },
    },
})
vim.cmd([[colorscheme tokyonight]])

This code segment functions to: Map completion item types to syntax highlighting tokens and construct annotated text with corresponding highlight regions based on metadata attributes.

```lua
[TASK_BEGIN]
function M.get_completion_kind_hl(completion_item, ls)
    local kind_name = Kind.get_completion_kind(completion_item.kind)
    local hl_name = config.hl_completion_kind[kind_name] or "CMCompletionItemKindDefault"

    return {
        fg = utils.get_hl(hl_name, "fg") or utils.get_hl("CMCompletionItemKindDefault", "fg"),
        bg = utils.get_hl(hl_name, "bg") or utils.get_hl("CMCompletionItemKindDefault", "bg")
    }
end
[TASK_END]
```


local utils = require("colorful-menu.utils")

local M = {}

---@param completion_item lsp.CompletionItem
---@param detail? string
---@param lang? string
---@param extra_info_hl? string
---@return CMHighlights

function M.default_highlight(completion_item, detail, lang, extra_info_hl)
    extra_info_hl = extra_info_hl or "@comment"
    local label = completion_item.label
    local highlight_name = utils.hl_by_kind(completion_item.kind, lang)
    local highlights = {
        {
            highlight_name,
            range = { 0, #label },
        },
    }
    local text = label
    if detail and string.find(detail, "\n") == nil and string.find(detail, "\r") == nil then
        local spaces = utils.align_spaces(label, detail)
        text = label .. spaces .. detail
        table.insert(highlights, {
            extra_info_hl,
            range = { #label + 1, #text },
        })
    end
    return {
        text = text,
        highlights = highlights,
    }
end

local utils = require("colorful-menu.utils")
local Kind = require("colorful-menu").Kind
local config = require("colorful-menu").config

local M = {}

---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.roslyn(completion_item, ls)
    local label = completion_item.label
    local description = completion_item.labelDetails and completion_item.labelDetails.description
    local kind = completion_item.kind

    local text = label

    if not kind then
        return utils.highlight_range(text, ls, 0, #text)
    end

    local highlight_name
    if kind == Kind.Class or kind == Kind.Interface or kind == Kind.Enum then
        highlight_name = "@type"
    elseif kind == Kind.Constructor then
        highlight_name = "@type"
    elseif kind == Kind.Constant then
        highlight_name = "@constant"
    elseif kind == Kind.Function or kind == Kind.Method then
        highlight_name = "@function"
    elseif kind == Kind.Property or kind == Kind.Field then
        highlight_name = "@property"
    elseif kind == Kind.Variable then
        highlight_name = "@variable"
    elseif kind == Kind.Keyword then
        highlight_name = "@keyword"
    else
        highlight_name = config.fallback_highlight
    end

    local highlights = {
        {
            highlight_name,
            range = { 0, #label },
        },
    }

    if description then
        text = label .. " " .. description
        table.insert(highlights, {
            config.ls.roslyn.extra_info_hl,
            range = { #label + 1, #text },
        })
    end

    return {
        text = text,
        highlights = highlights,
    }
end

return M

This code segment functions to: Format textual elements with contextual styling information and dynamically combine multiple data components while applying distinct visual properties to different sections of the resulting output.

```lua
[TASK_BEGIN]
function M.get_highlights(completion_item, detail, lang, extra_info_hl)
  local kind = completion_item.kind or 1
  local highlights = {
    kind = {
      text = utils.get_icon(kind),
      hl_group = "CmpItemKind"..utils.camel_to_upper(vim.lsp.protocol.CompletionItemKind[kind] or "")
    }
  }

  if detail then
    highlights.detail = {
      text = detail,
      hl_group = highlights.kind.hl_group.."Detail"
    }
  end

  if lang then
    highlights.lang = {
      text = lang,
      hl_group = extra_info_hl or "CmpItemMenu"
    }
  end

  return highlights
end
[TASK_END]
```


---@param completion_item lsp.CompletionItem
---@param ls string
---@return CMHighlights
function M.lua_ls(completion_item, ls)
    local vim_item = _lua_compute_completion_highlights(completion_item, ls)
    if vim_item.text ~= nil then
        local s, e = string.find(vim_item.text, "%b()")
        if s ~= nil and e ~= nil then
            table.insert(vim_item.highlights, {
                config.ls.lua_ls.arguments_hl,
                range = { s - 1, e },
            })
        end
    end
    return vim_item
end

return M

local function _lua_compute_completion_highlights(completion_item, ls)
    local label = completion_item.label
    local kind = completion_item.kind
    if not kind then
        return utils.highlight_range(label, ls, 0, #label)
    end
    if kind == Kind.Field then
        local text = string.format("%s", label)
        local source = string.format("v.%s", text)
        return utils.highlight_range(source, ls, 2, 2 + #text)
    end
    local highlight_name
    if kind == Kind.Constant then
        highlight_name = "@constant.lua"
    elseif kind == Kind.Function or kind == Kind.Method then
        highlight_name = "@function.lua"
    elseif kind == Kind.Property then
        highlight_name = "@property.lua"
    elseif kind == Kind.Variable then
        highlight_name = "@variable.lua"
    elseif kind == Kind.Keyword then
        highlight_name = "@keyword.lua"
    else
        highlight_name = config.fallback_highlight
    end
    return {
        text = label,
        highlights = {
            {
                highlight_name,
                range = { 0, #label },
            },
        },
    }
end

This code segment functions to: Dynamically assign syntax highlighting rules to code completion elements based on their semantic category and format specialized visual markers for specific data types.

```lua
[TASK_BEGIN]
local function _lua_compute_completion_highlights(completion_item, ls)
    local vim_item = {
        highlights = {}
    }

    local label = completion_item.label or ""
    vim_item.text = label

    local kind = completion_item.kind or Kind.Unknown
    local hl = config.ls[ls][Kind[kind]]

    if hl then
        table.insert(vim_item.highlights, {
            hl,
            range = {0, #label}
        })
    end

    return vim_item
end
[TASK_END]
```


This code segment functions to: Categorize language elements by syntactic type and apply visual formatting rules to composite text components with contextual metadata.

```lua
[TASK_BEGIN]
function M.get_kind_highlights(completion_item, ls)
    local kind = Kind.get(completion_item.kind or 1)
    local icon = config.icons[kind]
    return {
        parts = {
            { color = icon.color, text = icon.icon .. " " },
            { color = config.colors.default, text = ls },
        }
    }
end
[TASK_END]
```


This code segment functions to: Map semantic item categories to syntax highlighting groups and construct annotated text with associated visual styles based on input metadata characteristics.

```lua
[TASK_BEGIN]
function M.completion_highlight(completion_item, ls)
    local kind_number = completion_item.kind or 1
    local kind = Kind.completion_kind[kind_number]
    local hl_group = utils.get_highlight(config.completion_highlights[kind] or config.completion_highlights.Text)

    return {
        label = hl_group,
        kind = hl_group,
        details = completion_item.detail and hl_group or nil,
    }
end
[TASK_END]
```