Closed paulodiovani closed 9 months ago
This is not how ordering works. The order you list your sources in has no impact on how they appear. Comparator functions are how you control the ordering of completion. Please read the relevant cmp documentation on comparators
The nvim-cmp
docs say that the order we list the sources determines their order in the results list.
The order of the sources determines their order in the completion results.
Source: https://github.com/hrsh7th/nvim-cmp/blob/main/doc/cmp.txt#L578-L582
The
nvim-cmp
docs say that the order we list the sources determines their order in the results list.The order of the sources determines their order in the completion results.
Source: https://github.com/hrsh7th/nvim-cmp/blob/main/doc/cmp.txt#L578-L582
Huh, I think that must be new, TIL. The standard way to do this though is through comparators. It's not perfect, as I just tested and it seems when the response first pops in it appears to be getting sent to the top, but once It's cached it sorts properly. I'll reopen this try to find a way to fix this, but it may require upstream changes. For reference though, here's the way you should go about sorting entries:
(fun(entry1: cmp.Entry, entry2: cmp.Entry): boolean | nil)[]
The function to customize the sorting behavior.
You can use built-in comparators via cmp.config.compare.*
Completions are a list of completion items, comparators are functions which determine how that list is sorted, which is what determines their order in your completion menu.
Source priority is for things like the buffer text source, where it is only really useful as a fallback if a better source like an LSP doesn't give any response at all.
You can view example comparator functions in comparators.lua
local comparators = {}
-- places completions with a higher score (if applicable) higher
comparators.score = function (entry1, entry2)
if entry1.score and entry2.score then
return entry1.score > entry2.score
end
end
-- Places Copilot completions higher
comparators.prioritize = function (entry1, entry2)
if entry1.copilot and not entry2.copilot then
return true
elseif entry2.copilot and not entry1.copilot then
return false
end
end
return comparators
If you wanted copilot completions to be sent to the very bottom, you could place this in your cmp config:
local copilot = require("copilot_cmp.comparators")
local reverse_prioritize = function(entry1, entry2)
if entry1.copilot and not entry2.copilot then
return false
elseif entry2.copilot and not entry1.copilot then
return true
end
end
cmp.setup({
...
sorting = {
--keep priority weight at 2 for much closer matches to appear above copilot
--set to 1 to make copilot always appear on top
priority_weight = 1,
comparators = {
reverse_prioritize,
cmp.config.compare.exact,
cmp.config.compare.offset,
cmp.config.compare.score,
cmp.config.compare.recently_used,
cmp.config.compare.locality,
cmp.config.compare.kind,
cmp.config.compare.sort_text,
cmp.config.compare.length,
cmp.config.compare.order,
},
},
It worked, thanks. I just changed it a bit to (re)use default sorting:
-- Set up nvim-cmp.
local cmp = require 'cmp'
local cmp_config_default = require('cmp.config.default')()
local copilot_prioritize = require('copilot_cmp.comparators').prioritize
-- move copilot down
local copilot_reverse_prioritize = function(entry1, entry2)
return not copilot_prioritize(entry1, entry2)
end
---@cast cmp -nil
cmp.setup({
-- ...
sorting = {
comparators = table.insert(cmp_config_default.sorting.comparators, 1, copilot_reverse_prioritize),
},
})
After tweaking a bit with the comparators I managed to prioritize LSP first. Of course, that depends on the final score and Copilot can still show first in some cases.
In the end, my initial goal was not achieved, which was to prevent Copilot completions from showing "under the cursor", ofter making me select the wrong item. But since this issue's description was not clear on that point I'm closing it.
Thanks for the help.
In case anyone else finds this issue and still wants to de-prioritize copilot suggestions, this is what currently works for me.
local reverse_prioritize = function(entry1, entry2)
if entry1.source.name == "copilot" and entry2.source.name ~= "copilot" then
return false
elseif entry2.copilot == "copilot" and entry1.source.name ~= "copilot" then
return true
end
end
I found that just checking either entry for .copilot
never actually worked when using the comparators. I'm not sure if that is unique to my setup but the above function can be included in the list of nvim-cmp comparators and it will ensure that copilot suggestions are always at the bottom of nvim-cmp.
reverse_prioritize
works good
Worked on a first test. I'll check if it works on my daily workflow and report back later.
I have set
copilot
as my second to last source, because I want to always have LSP and Snippets first.But it just ignores my setting and injects its completion opinions at the top anyway, at the first or second lines.