Improve matching and sorting on specific cases

This commit is contained in:
hrsh7th
2021-08-05 15:21:16 +09:00
parent 570b00e6c3
commit 56d22edbbf
4 changed files with 23 additions and 9 deletions

View File

@@ -58,7 +58,6 @@ return function()
return diff return diff
end end
end end
return true
end) end)
return entries return entries
end end

View File

@@ -1,4 +1,5 @@
local char = require('cmp.utils.char') local char = require('cmp.utils.char')
local str = require('cmp.utils.str')
local matcher = {} local matcher = {}
@@ -72,8 +73,9 @@ end
---Match entry ---Match entry
---@param input string ---@param input string
---@param word string ---@param word string
---@param words string[]
---@return number ---@return number
matcher.match = function(input, word) matcher.match = function(input, word, words)
-- Empty input -- Empty input
if #input == 0 then if #input == 0 then
return matcher.PREFIX_FACTOR + matcher.NOT_FUZZY_FACTOR return matcher.PREFIX_FACTOR + matcher.NOT_FUZZY_FACTOR
@@ -108,8 +110,22 @@ matcher.match = function(input, word)
return 0 return 0
end end
-- Add prefix bonus
local prefix = false
if matches[1].input_match_start == 1 and matches[1].word_match_start == 1 then
prefix = true
else
for _, w in ipairs(words or {}) do
if str.has_prefix(w, string.sub(input, matches[1].input_match_start, matches[1].input_match_end)) then
prefix = true
break
end
end
end
-- Compute prefix match score -- Compute prefix match score
local score = 0 local score = prefix and matcher.PREFIX_FACTOR or 0
local boundary_fixer = prefix and matches[1].index - 1 or 0
local idx = 1 local idx = 1
for _, m in ipairs(matches) do for _, m in ipairs(matches) do
local s = 0 local s = 0
@@ -119,14 +135,11 @@ matcher.match = function(input, word)
end end
idx = idx + 1 idx = idx + 1
if s > 0 then if s > 0 then
score = score + (s * (1 + math.max(0, matcher.WORD_BOUNDALY_ORDER_FACTOR - m.index) / matcher.WORD_BOUNDALY_ORDER_FACTOR)) score = score + (s * (1 + math.max(0, matcher.WORD_BOUNDALY_ORDER_FACTOR - (m.index - boundary_fixer)) / matcher.WORD_BOUNDALY_ORDER_FACTOR))
score = score + (m.strict_match and 0.1 or 0) score = score + (m.strict_match and 0.1 or 0)
end end
end end
-- Add prefix bonus
score = score + ((matches[1].input_match_start == 1 and matches[1].word_match_start == 1) and matcher.PREFIX_FACTOR or 0)
-- Check remaining input as fuzzy -- Check remaining input as fuzzy
if matches[#matches].input_match_end < #input then if matches[#matches].input_match_end < #input then
if matcher.fuzzy(input, word, matches) then if matcher.fuzzy(input, word, matches) then

View File

@@ -20,6 +20,7 @@ describe('matcher', function()
assert.is.truthy(matcher.match('candlesingle', 'candle#accept#single') >= 1) assert.is.truthy(matcher.match('candlesingle', 'candle#accept#single') >= 1)
assert.is.truthy(matcher.match('conso', 'console') > matcher.match('conso', 'ConstantSourceNode')) assert.is.truthy(matcher.match('conso', 'console') > matcher.match('conso', 'ConstantSourceNode'))
assert.is.truthy(matcher.match('var_', 'var_dump') >= 1) assert.is.truthy(matcher.match('var_', 'var_dump') >= 1)
assert.is.truthy(matcher.match('my_', 'my_awesome_variable') > matcher.match('my_', 'completion_matching_strategy_list'))
end) end)
it('debug', function() it('debug', function()

View File

@@ -112,9 +112,10 @@ source.get_entries = function(self, ctx)
if not inputs[o] then if not inputs[o] then
inputs[o] = string.sub(ctx.cursor_before_line, o) inputs[o] = string.sub(ctx.cursor_before_line, o)
end end
e.score = matcher.match(inputs[o], e:get_filter_text()) e.score = matcher.match(inputs[o], e:get_filter_text(), { e:get_word() })
e.exact = inputs[o] == e:get_filter_text() e.exact = false
if e.score >= 1 then if e.score >= 1 then
e.exact = vim.tbl_contains({ e:get_filter_text(), e:get_word() }, inputs[o])
table.insert(entries, e) table.insert(entries, e)
end end
end end