Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/cmp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,12 @@ matching.disallow_symbol_nonprefix_matching
`boolean`
Whether to allow symbols in matches if the match is not a prefix match.

cmp-config.matching.disallow_case_insensetive_matching
matching.disallow_case_insensetive_matching
`boolean`
Whether to perform a case sensetive matching and return 0 score if the cases
don't match.

*cmp-config.sorting.priority_weight*
sorting.priority_weight~
`number`
Expand Down
1 change: 1 addition & 0 deletions lua/cmp/config/default.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ return function()
disallow_partial_matching = false,
disallow_prefix_unmatching = false,
disallow_symbol_nonprefix_matching = true,
disallow_case_insensetive_matching = false
},

sorting = {
Expand Down
13 changes: 12 additions & 1 deletion lua/cmp/entry.lua
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,17 @@ end
entry.match = function(self, input, matching_config)
-- https://www.lua.org/pil/11.6.html
-- do not use '..' to allocate multiple strings
local cache_key = string.format('%s:%d:%d:%d:%d:%d:%d', input, self.resolved_completion_item and 1 or 0, matching_config.disallow_fuzzy_matching and 1 or 0, matching_config.disallow_partial_matching and 1 or 0, matching_config.disallow_prefix_unmatching and 1 or 0, matching_config.disallow_partial_fuzzy_matching and 1 or 0, matching_config.disallow_symbol_nonprefix_matching and 1 or 0)

local cache_key = string.format('%s:%d:%d:%d:%d:%d:%d:%d',
input,
self.resolved_completion_item and 1 or 0,
matching_config.disallow_fuzzy_matching and 1 or 0,
matching_config.disallow_partial_matching and 1 or 0,
matching_config.disallow_prefix_unmatching and 1 or 0,
matching_config.disallow_partial_fuzzy_matching and 1 or 0,
matching_config.disallow_symbol_nonprefix_matching and 1 or 0,
matching_config.disallow_case_insensetive_matching and 1 or 0)

local matched = self.match_cache:get(cache_key)
if matched then
if self.match_view_args_ret and self.match_view_args_ret.input ~= input then
Expand All @@ -417,6 +427,7 @@ entry._match = function(self, input, matching_config)
disallow_partial_matching = matching_config.disallow_partial_matching,
disallow_prefix_unmatching = matching_config.disallow_prefix_unmatching,
disallow_symbol_nonprefix_matching = matching_config.disallow_symbol_nonprefix_matching,
disallow_case_insensentive_matching = matching_config.disallow_case_insensetive_matching,
synonyms = {
self.word,
self.completion_item.label,
Expand Down
25 changes: 15 additions & 10 deletions lua/cmp/matcher.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ end
---Match entry
---@param input string
---@param word string
---@param option { synonyms: string[], disallow_fullfuzzy_matching: boolean, disallow_fuzzy_matching: boolean, disallow_partial_fuzzy_matching: boolean, disallow_partial_matching: boolean, disallow_prefix_unmatching: boolean, disallow_symbol_nonprefix_matching: boolean }
---@param option { synonyms: string[], disallow_fullfuzzy_matching: boolean, disallow_fuzzy_matching: boolean, disallow_partial_fuzzy_matching: boolean, disallow_partial_matching: boolean, disallow_prefix_unmatching: boolean, disallow_symbol_nonprefix_matching: boolean, disallow_case_insensetive_matching: boolean}
---@return integer, table
matcher.match = function(input, word, option)
option = option or {}
Expand All @@ -98,7 +98,7 @@ matcher.match = function(input, word, option)

-- Check prefix matching.
if option.disallow_prefix_unmatching then
if not char.match(string.byte(input, 1), string.byte(word, 1)) then
if not char.match(string.byte(input, 1), string.byte(word, 1), option.disallow_case_insensetive_matching) then
return 0, {}
end
end
Expand All @@ -111,7 +111,7 @@ matcher.match = function(input, word, option)
local word_bound_index = 1
local no_symbol_match = false
while input_end_index <= #input and word_index <= #word do
local m = matcher.find_match_region(input, input_start_index, input_end_index, word, word_index)
local m = matcher.find_match_region(input, input_start_index, input_end_index, word, word_index, option)
if m and input_end_index <= m.input_match_end then
m.index = word_bound_index
input_start_index = m.input_match_start + 1
Expand All @@ -131,7 +131,9 @@ matcher.match = function(input, word, option)
end

if #matches == 0 then
if not option.disallow_fuzzy_matching and not option.disallow_prefix_unmatching and not option.disallow_partial_fuzzy_matching then
if not option.disallow_fuzzy_matching
and not option.disallow_prefix_unmatching
and not option.disallow_partial_fuzzy_matching then
if matcher.fuzzy(input, word, matches, option) then
return 1, matches
end
Expand All @@ -150,7 +152,8 @@ matcher.match = function(input, word, option)
prefix = true
local o = 1
for i = matches[1].input_match_start, matches[1].input_match_end do
if not char.match(string.byte(synonym, o), string.byte(input, i)) then
if not char.match(string.byte(synonym, o), string.byte(input, i),
option.disallow_case_insensetive_matching) then
prefix = false
break
end
Expand Down Expand Up @@ -212,7 +215,9 @@ matcher.fuzzy = function(input, word, matches, option)
local word_offset = 0
local word_index = char.get_next_semantic_index(word, curr_match.word_match_end)
while word_offset + word_index < next_match.word_match_start and input_index <= #input do
if char.match(string.byte(word, word_index + word_offset), string.byte(input, input_index)) then
if char.match(string.byte(word, word_index + word_offset),
string.byte(input, input_index),
option.disallow_case_insensetive_matching) then
input_index = input_index + 1
word_offset = word_offset + 1
else
Expand All @@ -233,7 +238,7 @@ matcher.fuzzy = function(input, word, matches, option)
local match_count = 0
while word_offset + word_index <= #word and input_index <= #input do
local c1, c2 = string.byte(word, word_index + word_offset), string.byte(input, input_index)
if char.match(c1, c2) then
if char.match(c1, c2, option.disallow_case_insensetive_matching ) then
if not matched then
input_match_start = input_index
word_match_start = word_index + word_offset
Expand Down Expand Up @@ -277,10 +282,10 @@ matcher.fuzzy = function(input, word, matches, option)
end

--- find_match_region
matcher.find_match_region = function(input, input_start_index, input_end_index, word, word_index)
matcher.find_match_region = function(input, input_start_index, input_end_index, word, word_index, option)
-- determine input position ( woroff -> word_offset )
while input_start_index < input_end_index do
if char.match(string.byte(input, input_end_index), string.byte(word, word_index)) then
if char.match(string.byte(input, input_end_index), string.byte(word, word_index), option.disallow_case_insensetive_matching) then
break
end
input_end_index = input_end_index - 1
Expand All @@ -300,7 +305,7 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
while input_index <= #input and word_index + word_offset <= #word do
local c1 = string.byte(input, input_index)
local c2 = string.byte(word, word_index + word_offset)
if char.match(c1, c2) then
if char.match(c1, c2, option.disallow_case_insensetive_matching) then
-- Match start.
if input_match_start == -1 then
input_match_start = input_index
Expand Down
7 changes: 7 additions & 0 deletions lua/cmp/matcher_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('matcher', function()
disallow_prefix_unmatching = false,
disallow_partial_fuzzy_matching = false,
disallow_symbol_nonprefix_matching = true,
disallow_case_insensetive_matching = false,
})
assert.is.truthy(score >= 1)
assert.equals(matches[1].word_match_start, 5)
Expand All @@ -62,6 +63,7 @@ describe('matcher', function()
disallow_prefix_unmatching = false,
disallow_partial_fuzzy_matching = true,
disallow_symbol_nonprefix_matching = true,
disallow_case_insensetive_matching = false,
})
assert.is.truthy(score == 0)
end)
Expand Down Expand Up @@ -93,6 +95,11 @@ describe('matcher', function()
assert.is.truthy(matcher.match('foo_', 'b foo_bar', { disallow_symbol_nonprefix_matching = false }) >= 1)
end)

it('disallow_case_insensetive_matching', function()
assert.is.truthy(matcher.match('Test', 'test', { disallow_case_insensetive_matching = true }) == 0)
assert.is.truthy(matcher.match('Test', 'test', { disallow_case_insensetive_matching = false}) >= 1)
end)

it('debug', function()
matcher.debug = function(...)
print(vim.inspect({ ... }))
Expand Down
1 change: 1 addition & 0 deletions lua/cmp/types/cmp.lua
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ cmp.ItemField = {
---@field public disallow_partial_matching boolean
---@field public disallow_prefix_unmatching boolean
---@field public disallow_symbol_nonprefix_matching boolean
---@field public disallow_case_insensetive_matching boolean

---@class cmp.SortingConfig
---@field public priority_weight integer
Expand Down
9 changes: 7 additions & 2 deletions lua/cmp/utils/char.lua
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,16 @@ char.get_next_semantic_index = function(text, current_index)
return #text + 1
end

---Ignore case match
---Ignore case match by default
---@param byte1 integer
---@param byte2 integer
---@param is_case_sensetive boolean? default:false whether the match should be case sensetive
---@return boolean
char.match = function(byte1, byte2)
char.match = function(byte1, byte2, is_case_sensetive)
if is_case_sensetive then
return byte1 == byte2
end

if not char.is_alpha(byte1) or not char.is_alpha(byte2) then
return byte1 == byte2
end
Expand Down