Use floating window for completion menus (#224)

* WIP

* WIP

* Fix #226

* Insert text

* Emulate vim native

* テキトウ

* Tekito

* Move scrollbar impl

* aaa

* Ignore unexpected event

* fix

* fix scroll

* Refactor (conflict...)

* Fix bug

* Positive integer

* Refactor a bit

* Fix for pumheight=0

* fx

* Improve matching highlight

* Improve colorscheme handling

* fmt

* Add cmp.visible

* Fix pum pos

* ABBR_MARGIN

* Fix cel calculation

* up

* refactor

* fix

* a

* a

* compat

* Remove current completion state

* Fix ghost text

* Add feature toggle

* highlight customization

* Update

* Add breaking change announcement

* Add README.md

* Remove unused function

* extmark ephemeral ghost text

* Support native comp

* Fix docs  pos

* a

* Remove if native menu visible

* theme async

* Improvement idea: option to disables insert on select item (#240)

* use ghost text instead of insertion on prev/next item

* add disables_insert_on_selection option

* move disable_insert_on_select option as argumet on

* update README

* use an enum behavior to disable insert on select

* Adopt contribution

* Preselect

* Improve

* Change configuration option

* a

* Improve

* Improve

* Implement proper <C-e> behavior to native/custom

* Support <C-c> maybe

* Improve docs view

* Improve

* Avoid syntax leak

* TODO: refactor

* Fix

* Revert win pos

* fmt

* ghost text remaining

* Don't use italic by default

* bottom

* dedup by label

* Ignore events

* up

* Hacky native view partial support

* up

* perf

* improve

* more cache

* fmt

* Fix format option

* fmt

* recheck

* Fix

* Improve

* Improve

* compat

* implement redraw

* improve

* up

* fmt/lint

* immediate ghost text

* source timeout

* up

* Support multibyte

* disable highlight

* up

* improve

* fmt

* fmt

* fix

* fix

* up

* up

* Use screenpos

* Add undojoin check

* Fix height

* matcher bug

* Fix dot-repeat

* Remove undojoin

* macro

* Support dot-repeat

* MacroSafe

* Default item count is 200

* fmt

Co-authored-by: Eric Puentes <eric.puentes@mercadolibre.com.co>
This commit is contained in:
hrsh7th
2021-10-08 18:27:33 +09:00
committed by GitHub
parent 5bed2dc9f3
commit ada9ddeff7
31 changed files with 1802 additions and 718 deletions

View File

@@ -1,9 +1,8 @@
local char = require('cmp.utils.char')
local str = require('cmp.utils.str')
local matcher = {}
matcher.WORD_BOUNDALY_ORDER_FACTOR = 5
matcher.WORD_BOUNDALY_ORDER_FACTOR = 10
matcher.PREFIX_FACTOR = 8
matcher.NOT_FUZZY_FACTOR = 6
@@ -78,12 +77,12 @@ end
matcher.match = function(input, word, words)
-- Empty input
if #input == 0 then
return matcher.PREFIX_FACTOR + matcher.NOT_FUZZY_FACTOR
return matcher.PREFIX_FACTOR + matcher.NOT_FUZZY_FACTOR, {}
end
-- Ignore if input is long than word
if #input > #word then
return 0
return 0, {}
end
--- Gather matched regions
@@ -107,17 +106,27 @@ matcher.match = function(input, word, words)
end
if #matches == 0 then
return 0
return 0, {}
end
matcher.debug(word, matches)
-- 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
prefix = true
local o = 1
for i = matches[1].input_match_start, matches[1].input_match_end do
if not char.match(string.byte(w, o), string.byte(input, i)) then
prefix = false
break
end
o = o + 1
end
if prefix then
break
end
end
@@ -125,7 +134,7 @@ matcher.match = function(input, word, words)
-- Compute prefix match score
local score = prefix and matcher.PREFIX_FACTOR or 0
local boundary_fixer = prefix and matches[1].index - 1 or 0
local offset = prefix and matches[1].index - 1 or 0
local idx = 1
for _, m in ipairs(matches) do
local s = 0
@@ -135,20 +144,21 @@ matcher.match = function(input, word, words)
end
idx = idx + 1
if s > 0 then
s = s * (m.strict_match and 1.2 or 1)
score = score + (s * (1 + math.max(0, matcher.WORD_BOUNDALY_ORDER_FACTOR - (m.index - boundary_fixer)) / matcher.WORD_BOUNDALY_ORDER_FACTOR))
s = s * (1 + m.strict_ratio)
s = s * (1 + math.max(0, matcher.WORD_BOUNDALY_ORDER_FACTOR - (m.index - offset)) / matcher.WORD_BOUNDALY_ORDER_FACTOR)
score = score + s
end
end
-- Check remaining input as fuzzy
if matches[#matches].input_match_end < #input then
if matcher.fuzzy(input, word, matches) then
return score
if prefix and matcher.fuzzy(input, word, matches) then
return score, matches
end
return 0
return 0, {}
end
return score + matcher.NOT_FUZZY_FACTOR
return score + matcher.NOT_FUZZY_FACTOR, matches
end
--- fuzzy
@@ -178,16 +188,37 @@ matcher.fuzzy = function(input, word, matches)
local matched = false
local word_offset = 0
local word_index = last_match.word_match_end + 1
local input_match_start = -1
local input_match_end = -1
local word_match_start = -1
local strict_count = 0
local match_count = 0
while word_offset + word_index <= #word and input_index <= #input do
if char.match(string.byte(word, word_index + word_offset), string.byte(input, input_index)) then
local c1, c2 = string.byte(word, word_index + word_offset), string.byte(input, input_index)
if char.match(c1, c2) then
if not matched then
input_match_start = input_index
word_match_start = word_index + word_offset
end
matched = true
input_index = input_index + 1
strict_count = strict_count + (c1 == c2 and 1 or 0)
match_count = match_count + 1
elseif matched then
input_index = last_input_index
input_match_end = input_index - 1
end
word_offset = word_offset + 1
end
if input_index > #input then
table.insert(matches, {
input_match_start = input_match_start,
input_match_end = input_match_end,
word_match_start = word_match_start,
word_match_end = word_index + word_offset - 1,
strict_ratio = strict_count / match_count,
fuzzy = true,
})
return true
end
return false
@@ -208,10 +239,11 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
return nil
end
local strict_match_count = 0
local input_match_start = -1
local input_index = input_end_index
local word_offset = 0
local strict_count = 0
local match_count = 0
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)
@@ -221,11 +253,8 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
input_match_start = input_index
end
-- Increase strict_match_count
if c1 == c2 then
strict_match_count = strict_match_count + 1
end
strict_count = strict_count + (c1 == c2 and 1 or 0)
match_count = match_count + 1
word_offset = word_offset + 1
else
-- Match end (partial region)
@@ -235,7 +264,8 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
input_match_end = input_index - 1,
word_match_start = word_index,
word_match_end = word_index + word_offset - 1,
strict_match = strict_match_count == input_index - input_match_start,
strict_ratio = strict_count / match_count,
fuzzy = false,
}
else
return nil
@@ -251,7 +281,8 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
input_match_end = input_index - 1,
word_match_start = word_index,
word_match_end = word_index + word_offset - 1,
strict_match = strict_match_count == input_index - input_match_start,
strict_ratio = strict_count / match_count,
fuzzy = false,
}
end