diff options
| author | TJ DeVries <devries.timothyj@gmail.com> | 2020-08-24 12:31:57 -0400 |
|---|---|---|
| committer | TJ DeVries <devries.timothyj@gmail.com> | 2020-08-24 12:31:57 -0400 |
| commit | 1995ca53f38bb89f58a25b523cac59a07c09a0b8 (patch) | |
| tree | a170df7448d40ba9f1ddf307cb5849ceb5697905 /lua | |
| parent | cfddae42f59eacbd792a8853be089f4711bbf4ba (diff) | |
Add fuzzy git file finderZ
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/telescope/builtin.lua | 42 | ||||
| -rw-r--r-- | lua/telescope/init.lua | 3 | ||||
| -rw-r--r-- | lua/telescope/pickers.lua | 30 | ||||
| -rw-r--r-- | lua/telescope/previewers.lua | 1 | ||||
| -rw-r--r-- | lua/telescope/sorters.lua | 78 | ||||
| -rw-r--r-- | lua/tests/telescope_spec.lua | 19 |
6 files changed, 147 insertions, 26 deletions
diff --git a/lua/telescope/builtin.lua b/lua/telescope/builtin.lua index 7016b0a..ff5a16d 100644 --- a/lua/telescope/builtin.lua +++ b/lua/telescope/builtin.lua @@ -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. + + local telescope = require('telescope') + + local file_finder = telescope.finders.new { + static = true, + + fn_command = function() return 'git ls-files' end, + } + + local file_previewer = telescope.previewers.vim_buffer -builtin.rg_vimgrep.finder = Finder:new { - fn_command = function(prompt) - return string.format('rg --vimgrep %s', prompt) - end, + local file_picker = telescope.pickers.new { + previewer = file_previewer + } - responsive = false -} + -- 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() -builtin.rg_vimgrep.picker = pickers.new { -} + file_picker:find { + prompt = 'Simple File', + finder = file_finder, + sorter = file_sorter, + } +end return builtin diff --git a/lua/telescope/init.lua b/lua/telescope/init.lua index 75f6d38..22d3f83 100644 --- a/lua/telescope/init.lua +++ b/lua/telescope/init.lua @@ -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) diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua index f2acfac..d0785ae 100644 --- a/lua/telescope/pickers.lua +++ b/lua/telescope/pickers.lua @@ -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 = diff --git a/lua/telescope/previewers.lua b/lua/telescope/previewers.lua index ee99d11..91f0060 100644 --- a/lua/telescope/previewers.lua +++ b/lua/telescope/previewers.lua @@ -81,7 +81,6 @@ previewers.vim_buffer_or_bat = previewers.new { end, } - previewers.Previewer = Previewer return previewers diff --git a/lua/telescope/sorters.lua b/lua/telescope/sorters.lua index 0299c91..d09b53b 100644 --- a/lua/telescope/sorters.lua +++ b/lua/telescope/sorters.lua @@ -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 diff --git a/lua/tests/telescope_spec.lua b/lua/tests/telescope_spec.lua index c671579..9960772 100644 --- a/lua/tests/telescope_spec.lua +++ b/lua/tests/telescope_spec.lua @@ -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) + |
