feat: Improve filtering ideas for sorters.

This commit is contained in:
TJ DeVries
2020-10-25 08:09:07 -04:00
parent 59ef37ded4
commit 477261e5c0
3 changed files with 203 additions and 1 deletions

View File

@@ -394,6 +394,10 @@ function Picker:find()
local prompt = vim.trim(vim.api.nvim_buf_get_lines(prompt_bufnr, first_line, last_line, false)[1]:sub(#prompt_prefix))
if self.sorter then
self.sorter:_start(prompt)
end
-- TODO: Statusbar possibilities here.
-- vim.api.nvim_buf_set_virtual_text(prompt_bufnr, 0, 1, { {"hello", "Error"} }, {})

View File

@@ -20,6 +20,8 @@ local ngram_highlighter = function(ngram_len, prompt, display)
return highlights
end
local FILTERED = -1
local Sorter = {}
Sorter.__index = Sorter
@@ -39,12 +41,68 @@ function Sorter:new(opts)
state = {},
scoring_function = opts.scoring_function,
highlighter = opts.highlighter,
discard = opts.discard,
_discard_state = {
filtered = {},
prompt = '',
},
}, Sorter)
end
-- TODO: We could make this a bit smarter and cache results "as we go" and where they got filtered.
-- Then when we hit backspace, we don't have to re-caculate everything.
-- Prime did a lot of the hard work already, but I don't want to copy as much memory around
-- as he did in his example.
-- Example can be found in ./scratch/prime_prompt_cache.lua
function Sorter:_start(prompt)
if not self.discard then
return
end
local previous = self._discard_state.prompt
local len_previous = #previous
if #prompt < len_previous then
log.debug("Reset discard because shorter prompt")
self._discard_state.filtered = {}
elseif string.sub(prompt, 1, len_previous) ~= previous then
log.debug("Reset discard no match")
self._discard_state.filtered = {}
end
self._discard_state.prompt = prompt
end
-- TODO: Consider doing something that makes it so we can skip the filter checks
-- if we're not discarding. Also, that means we don't have to check otherwise as well :)
function Sorter:score(prompt, entry)
if not entry or not entry.ordinal then return -1 end
return self:scoring_function(prompt or "", entry.ordinal, entry)
local ordinal = entry.ordinal
if self:_was_discarded(prompt, ordinal) then
return FILTERED
end
local score = self:scoring_function(prompt or "", ordinal, entry)
if score == FILTERED then
self:_mark_discarded(prompt, ordinal)
end
return score
end
function Sorter:_was_discarded(prompt, ordinal)
return self.discard and self._discard_state.filtered[ordinal]
end
function Sorter:_mark_discarded(prompt, ordinal)
if not self.discard then
return
end
self._discard_state.filtered[ordinal] = true
end
function sorters.new(...)
@@ -313,6 +371,8 @@ sorters.get_fzy_sorter = function()
local OFFSET = -fzy.get_score_floor()
return sorters.Sorter:new{
discard = true,
scoring_function = function(_, prompt, line)
-- Check for actual matches before running the scoring alogrithm.
if not fzy.has_match(prompt, line) then