Add fuzzy git file finderZ

This commit is contained in:
TJ DeVries
2020-08-24 12:31:57 -04:00
parent cfddae42f5
commit 1995ca53f3
6 changed files with 147 additions and 26 deletions

View File

@@ -4,28 +4,36 @@ A collection of builtin pipelines for telesceope.
Meant for both example and for easy startup.
--]]
local Finder = require('telescope.finder')
local pickers = require('telescope.pickers')
local builtin = {}
builtin.rg_vimgrep = setmetatable({}, {
__call = function(t, ...)
-- builtin.rg_vimgrep("--type lua function")
print(t, ...)
end
})
builtin.git_files = function(_)
-- TODO: Auto select bottom row
-- TODO: filter out results when they don't match at all anymore.
builtin.rg_vimgrep.finder = Finder:new {
fn_command = function(prompt)
return string.format('rg --vimgrep %s', prompt)
end,
local telescope = require('telescope')
responsive = false
}
local file_finder = telescope.finders.new {
static = true,
builtin.rg_vimgrep.picker = pickers.new {
}
fn_command = function() return 'git ls-files' end,
}
local file_previewer = telescope.previewers.vim_buffer
local file_picker = telescope.pickers.new {
previewer = file_previewer
}
-- local file_sorter = telescope.sorters.get_ngram_sorter()
-- local file_sorter = require('telescope.sorters').get_levenshtein_sorter()
local file_sorter = telescope.sorters.get_norcalli_sorter()
file_picker:find {
prompt = 'Simple File',
finder = file_finder,
sorter = file_sorter,
}
end
return builtin

View File

@@ -8,6 +8,7 @@ local pickers = require('telescope.pickers')
local previewers = require('telescope.previewers')
local sorters = require('telescope.sorters')
local state = require('telescope.state')
local builtin = require('telescope.builtin')
local telescope = {
-- <module>.new { }
@@ -17,6 +18,8 @@ local telescope = {
sorters = sorters,
state = state,
builtin = builtin,
}
function __TelescopeOnLeave(prompt_bufnr)

View File

@@ -148,6 +148,11 @@ function Picker:find(opts)
function(index, line)
local row = self.max_results - index + 1
-- If it's less than 0, then we don't need to show it at all.
if row < 0 then
return
end
log.trace("Setting row", row, "with value", line)
vim.api.nvim_buf_set_lines(results_bufnr, row, row + 1, false, {line})
end
@@ -161,8 +166,17 @@ function Picker:find(opts)
log.trace("Processing result... ", line)
local sort_score = 0
local sort_ok
if sorter then
sort_score = sorter:score(prompt, line)
sort_ok, sort_score = pcall(function ()
return sorter:score(prompt, line)
end)
if not sort_ok then
log.warn("Sorting failed with:", prompt, line, sort_score)
return
end
if sort_score == -1 then
log.trace("Filtering out result: ", line)
return
@@ -347,7 +361,7 @@ pickers.line_manager = function(max_results, set_line)
-- line = ...
-- metadata ? ...
-- }
local state = {}
local line_state = {}
set_line = set_line or function() end
@@ -355,7 +369,7 @@ pickers.line_manager = function(max_results, set_line)
add_result = function(self, score, line)
score = score or 0
for index, item in ipairs(state) do
for index, item in ipairs(line_state) do
if item.score > score then
return self:insert(index, {
score = score,
@@ -378,17 +392,17 @@ pickers.line_manager = function(max_results, set_line)
insert = function(self, index, item)
if item == nil then
item = index
index = #state + 1
index = #line_state + 1
end
-- To insert something, we place at the next available index (or specified index)
-- and then shift all the corresponding items one place.
local next_item
repeat
next_item = state[index]
next_item = line_state[index]
set_line(index, item.line)
state[index] = item
line_state[index] = item
index = index + 1
item = next_item
@@ -396,11 +410,11 @@ pickers.line_manager = function(max_results, set_line)
end,
num_results = function()
return #state
return #line_state
end,
_get_state = function()
return state
return line_state
end,
}, {
-- insert =

View File

@@ -81,7 +81,6 @@ previewers.vim_buffer_or_bat = previewers.new {
end,
}
previewers.Previewer = Previewer
return previewers

View File

@@ -1,3 +1,5 @@
local ceil = math.ceil
local log = require('telescope.log')
local util = require('telescope.utils')
@@ -70,4 +72,80 @@ sorters.get_levenshtein_sorter = function()
}
end
sorters.get_norcalli_sorter = function()
local ngramlen = 2
local cached_ngrams = {}
local function overlapping_ngrams(s, n)
if cached_ngrams[s] and cached_ngrams[s][n] then
return cached_ngrams[s][n]
end
local R = {}
for i = 1, s:len() - n + 1 do
R[#R+1] = s:sub(i, i+n-1)
end
if not cached_ngrams[s] then
cached_ngrams[s] = {}
end
cached_ngrams[s][n] = R
return R
end
return Sorter:new {
scoring_function = function(_, prompt, line)
if prompt == 0 or #prompt < ngramlen then
return 0
end
local prompt_ngrams = overlapping_ngrams(prompt, ngramlen)
local prompt_lower = prompt:lower()
local line_lower = line:lower()
local N = #prompt
local contains_string = line_lower:find(prompt_lower, 1, true)
local consecutive_matches = 0
local previous_match_index = 0
local match_count = 0
for i = 1, #prompt_ngrams do
local match_start = line_lower:find(prompt_ngrams[i], 1, true)
if match_start then
match_count = match_count + 1
if match_start > previous_match_index then
consecutive_matches = consecutive_matches + 1
end
previous_match_index = match_start
end
end
-- TODO: Copied from ashkan.
local denominator = (
(10 * match_count / #prompt_ngrams)
-- biases for shorter strings
-- TODO(ashkan): this can bias towards repeated finds of the same
-- subpattern with overlapping_ngrams
+ 3 * match_count * ngramlen / #line
+ consecutive_matches
+ N / (contains_string or (2 * #line))
-- + 30/(c1 or 2*N)
)
if denominator == 0 or denominator ~= denominator then
return -1
end
return 1 / denominator
end
}
end
return sorters

View File

@@ -1,5 +1,8 @@
require('plenary.test_harness'):setup_busted()
local log = require('telescope.log')
-- log.use_console = false
local pickers = require('telescope.pickers')
local utils = require('telescope.utils')
@@ -179,4 +182,20 @@ describe('Picker', function()
end)
end)
describe('Sorters', function()
describe('norcalli_sorter', function()
it('sort matches well', function()
local sorter = require('telescope.sorters').get_norcalli_sorter()
local exact_match = sorter:score('hello', 'hello')
local no_match = sorter:score('abcdef', 'ghijkl')
local ok_match = sorter:score('abcdef', 'ab')
assert(exact_match < no_match)
assert(exact_match < ok_match)
assert(ok_match < no_match)
end)
end)
end)