hrsh7th / cmp-cmdline

nvim-cmp source for vim's cmdline
MIT License
564 stars 45 forks source link

Incorrect completion order for customlist completion due to sorting #72

Open wookayin opened 1 year ago

wookayin commented 1 year ago

With the default config/setup, completion for command line would also have the same sorting comparator applied as the normal cmp, but this would result in a different order for completelist. cmp-cmdline will sort all the completion items based on similarity, or based on the length if completion text is empty. This is undesirable because it would be different than the default completion order as vim's vanilla wildmenu.

As a workaround, one could disable the comparators for cmdline:

cmp.setup.cmdline(':', {
  mapping = cmp.mapping.preset.cmdline(),
  sources = cmp.config.sources({
    { name = 'path' }
  }, {
    { name = 'cmdline' }
  }),
  sorting = {
    comparators = {}
  },
})

but in some cases normal comparator would be still useful (like exact, length, etc.). What would be a recommended way or practice to deal with this situation?

rbong commented 1 year ago

This looks like an issue for nvim-cmp - this plugin is returning items in the order given.

rbong commented 1 year ago

This is what you want:

local cmp_compare = require('cmp.config.compare')

-- commands with custom completion
local custom_commands = {
    Floggit = true,
}

-- default cmp comparators
local default_cmp_comparators = {
    cmp_compare.offset,
    cmp_compare.exact,
    cmp_compare.score,
    cmp_compare.recently_used,
    cmp_compare.locality,
    cmp_compare.kind,
    cmp_compare.length,
    cmp_compare.order,
}

-- compare cmp cmdline entries
function cmp_compare_cmdline(e1, e2)
    -- complete custom command
    if custom_commands[vim.fn.getcmdline():match("%S+")] then
        return cmp_compare.order(e1, e2)
    end
    -- complete default
    for _, fn in ipairs(default_cmp_comparators) do
        local diff = fn(e1, e2)
        if diff ~= nil then
            return diff
        end
    end
end

-- setup : completion
cmp.setup.cmdline(':', {
    mapping = cmp.mapping.preset.cmdline(),
    sources = cmp.config.sources({
        { name = 'path' }
    }, {
        { name = 'cmdline' }
    }),
    sorting = {
        comparators = {
            cmp_compare_cmdline,
        },
    },
    entry_filter = function()
        return ''
    end
})

If you don't care about sorting non-custom functions by default you can just do:

local cmp_compare = require('cmp.config.compare')

cmp.setup.cmdline(':', {
    mapping = cmp.mapping.preset.cmdline(),
    sources = cmp.config.sources({
        { name = 'path' }
    }, {
        { name = 'cmdline' }
    }),
    sorting = {
        comparators = {
            cmp_compare.order,
        },
    },
})