summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
authorTJ DeVries <devries.timothyj@gmail.com>2020-07-17 00:03:20 -0400
committerTJ DeVries <devries.timothyj@gmail.com>2020-07-17 00:03:20 -0400
commitababfbfd88334ca6d94d5d0a8b6324dd6600d602 (patch)
tree99dd820cca2d906175b9a645694cb778add58499 /lua
parentc6f0142fc651dcbd2431630956d034c046293e7e (diff)
Another stream
Diffstat (limited to 'lua')
-rw-r--r--lua/telescope/algos/string_distance.lua49
-rw-r--r--lua/telescope/finders.lua58
-rw-r--r--lua/telescope/init.lua16
-rw-r--r--lua/telescope/mappings.lua2
-rw-r--r--lua/telescope/pickers.lua83
-rw-r--r--lua/telescope/previewers.lua35
-rw-r--r--lua/telescope/sorters.lua32
-rw-r--r--lua/telescope/utils.lua14
8 files changed, 225 insertions, 64 deletions
diff --git a/lua/telescope/algos/string_distance.lua b/lua/telescope/algos/string_distance.lua
new file mode 100644
index 0000000..de40e14
--- /dev/null
+++ b/lua/telescope/algos/string_distance.lua
@@ -0,0 +1,49 @@
+
+local function min(a, b, c)
+ local min_val = a
+
+ if b < min_val then min_val = b end
+ if c < min_val then min_val = c end
+
+ return min_val
+
+end
+
+----------------------------------
+--- Levenshtein distance function.
+-- @tparam string s1
+-- @tparam string s2
+-- @treturn number the levenshtein distance
+-- @within Metrics
+return function(s1, s2)
+ if s1 == s2 then return 0 end
+ if s1:len() == 0 then return s2:len() end
+ if s2:len() == 0 then return s1:len() end
+ if s1:len() < s2:len() then s1, s2 = s2, s1 end
+
+ local t = {}
+ for i=1, #s1+1 do
+ t[i] = {i-1}
+ end
+
+ for i=1, #s2+1 do
+ t[1][i] = i-1
+ end
+
+ local cost
+ for i=2, #s1+1 do
+
+ for j=2, #s2+1 do
+ cost = (s1:sub(i-1,i-1) == s2:sub(j-1,j-1) and 0) or 1
+ t[i][j] = min(
+ t[i-1][j] + 1,
+ t[i][j-1] + 1,
+ t[i-1][j-1] + cost)
+ end
+
+ end
+
+ return t[#s1+1][#s2+1]
+
+end
+
diff --git a/lua/telescope/finders.lua b/lua/telescope/finders.lua
index 1601d09..0b7e185 100644
--- a/lua/telescope/finders.lua
+++ b/lua/telescope/finders.lua
@@ -2,8 +2,11 @@ local a = vim.api
local finders = {}
+---@class Finder
local Finder = {}
+
Finder.__index = Finder
+Finder.__call = function(t, ... ) return t:_find(...) end
--- Create a new finder command
---
@@ -26,52 +29,37 @@ function Finder:new(opts)
return setmetatable({
fn_command = opts.fn_command,
responsive = opts.responsive,
+ state = {},
job_id = -1,
}, Finder)
end
-function Finder:get_results(win, bufnr, prompt)
- if self.job_id > 0 then
- -- Make sure we kill old jobs.
+-- Probably should use the word apply here, since we're apply the callback passed to us by
+-- the picker... But I'm not sure how we want to say that.
+
+-- find_incremental
+-- find_prompt
+-- process_prompt
+-- process_search
+-- do_your_job
+-- process_plz
+function Finder:_find(prompt, process_result)
+ if (self.state.job_id or 0) > 0 then
vim.fn.jobstop(self.job_id)
end
- self.job_id = vim.fn.jobstart(self.fn_command(prompt), {
- -- TODO: Decide if we want this or don't want this.
+ -- TODO: How to just literally pass a list...
+ -- TODO: How to configure what should happen here
+ -- TODO: How to run this over and over?
+ self.job_id = vim.fn.jobstart(self:fn_command(prompt), {
stdout_buffered = true,
on_stdout = function(_, data, _)
- a.nvim_buf_set_lines(bufnr, -1, -1, false, data)
- end,
-
- on_exit = function()
- -- TODO: Add possibility to easily highlight prompt within buffer
- -- without having to do weird stuff and with it actually working...
- if false then
- vim.fn.matchadd("Type", "\\<" .. prompt .. "\\>", 1, -1, {window = win})
+ for _, line in ipairs(data) do
+ process_result(line)
end
- end,
+ end
})
-
- --[[
- local function get_rg_results(bufnr, search_string)
- local start_time = vim.fn.reltime()
-
- vim.fn.jobstart(string.format('rg %s', search_string), {
- cwd = '/home/tj/build/neovim',
-
- on_stdout = function(job_id, data, event)
- vim.api.nvim_buf_set_lines(bufnr, -1, -1, false, data)
- end,
-
- on_exit = function()
- print("Finished in: ", vim.fn.reltimestr(vim.fn.reltime(start_time)))
- end,
-
- stdout_buffer = true,
- })
- end
- --]]
end
--- Return a new Finder
@@ -81,4 +69,6 @@ finders.new = function(...)
return Finder:new(...)
end
+finders.Finder = Finder
+
return finders
diff --git a/lua/telescope/init.lua b/lua/telescope/init.lua
index 76abb5a..75f6d38 100644
--- a/lua/telescope/init.lua
+++ b/lua/telescope/init.lua
@@ -6,12 +6,16 @@
local finders = require('telescope.finders')
local pickers = require('telescope.pickers')
local previewers = require('telescope.previewers')
+local sorters = require('telescope.sorters')
local state = require('telescope.state')
local telescope = {
+ -- <module>.new { }
finders = finders,
pickers = pickers,
previewers = previewers,
+ sorters = sorters,
+
state = state,
}
@@ -22,16 +26,4 @@ function __TelescopeOnLeave(prompt_bufnr)
picker:close_windows(status)
end
--- TODO: Probably could attach this with nvim_buf_attach, and then I don't have to do the ugly global function stuff
-function __TelescopeOnChange(prompt_bufnr, prompt, results_bufnr, results_win)
- local line = vim.api.nvim_buf_get_lines(prompt_bufnr, 0, -1, false)[1]
- local prompt_input = string.sub(line, #prompt + 1)
-
- local status = state.get_status(prompt_bufnr)
- local finder = status.finder
-
- vim.api.nvim_buf_set_lines(results_bufnr, 0, -1, false, {})
- local results = finder:get_results(results_win, results_bufnr, prompt_input)
-end
-
return telescope
diff --git a/lua/telescope/mappings.lua b/lua/telescope/mappings.lua
index b779b2f..3c6de18 100644
--- a/lua/telescope/mappings.lua
+++ b/lua/telescope/mappings.lua
@@ -49,7 +49,7 @@ local function update_current_selection(prompt_bufnr, results_bufnr, row)
if status.previewer then
vim.g.got_here = true
- status.previewer.fn(
+ status.previewer:preview(
status.preview_win,
status.preview_bufnr,
status.results_bufnr,
diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua
index a8624b0..f9f64df 100644
--- a/lua/telescope/pickers.lua
+++ b/lua/telescope/pickers.lua
@@ -3,6 +3,7 @@ local popup = require('popup')
local mappings = require('telescope.mappings')
local state = require('telescope.state')
+local utils = require('telescope.utils')
local pickers = {}
@@ -19,8 +20,15 @@ function Picker:new(opts)
end
-function Picker:find(finder)
- local prompt_string = 'Find File'
+function Picker:find(opts)
+ opts = opts or {}
+
+ local finder = opts.finder
+ assert(finder, "Finder is required to do picking")
+
+ local sorter = opts.sorter
+
+ local prompt_string = opts.prompt
-- Create three windows:
-- 1. Prompt window
-- 2. Options window
@@ -75,26 +83,71 @@ function Picker:find(finder)
-- a.nvim_buf_set_option(prompt_bufnr, 'buftype', 'prompt')
-- vim.fn.prompt_setprompt(prompt_bufnr, prompt_string)
- vim.api.nvim_buf_attach(prompt_bufnr, true, {
- on_lines = vim.schedule_wrap(function(_, _, _, first_line, last_line)
- local line = vim.api.nvim_buf_get_lines(prompt_bufnr, first_line, last_line, false)[1]
+ local on_lines = function(_, _, _, first_line, last_line)
+ local prompt = vim.api.nvim_buf_get_lines(prompt_bufnr, first_line, last_line, false)[1]
+
+ vim.api.nvim_buf_set_lines(results_bufnr, 0, -1, false, {})
+
+ -- Create a closure that has all the data we need
+ -- We pass a function called "newResult" to get_results
+ -- get_results calles "newResult" every time it gets a new result
+ -- picker then (if available) calls sorter
+ -- and then appropriately places new result in the buffer.
+
+ local line_scores = {}
+
+ -- TODO: We need to fix the sorting
+ -- TODO: We should provide a simple fuzzy matcher in Lua for people
+ -- TODO: We should get all the stuff on the bottom line directly, not floating around
+ -- TODO: We need to handle huge lists in a good way, cause currently we'll just put too much stuff in the buffer
+ -- TODO: Stop having things crash if we have an error.
+ finder(prompt, function(line)
+ if sorter then
+ local sort_score = sorter:score(prompt, line)
+ if sort_score == -1 then
+ return
+ end
+
+ -- { 7, 3, 1, 1 }
+ -- 2
+ for row, row_score in utils.reversed_ipairs(line_scores) do
+ if row_score > sort_score then
+ -- Insert line at row
+ vim.api.nvim_buf_set_lines(results_bufnr, row, row, false, {
+ string.format("%s // %s %s", line, sort_score, row)
+ })
+
+ -- Insert current score in the table
+ table.insert(line_scores, row + 1, sort_score)
+
+ -- All done :)
+ return
+ end
+ end
+
+ -- Worst score so far, so add to end
+ vim.api.nvim_buf_set_lines(results_bufnr, -1, -1, false, {line})
+ table.insert(line_scores, sort_score)
+ else
+ -- Just always append to the end of the buffer if this is all you got.
+ vim.api.nvim_buf_set_lines(results_bufnr, -1, -1, false, {line})
+ end
+ end)
+ -- local results = finder:get_results(results_win, results_bufnr, line)
+ end
- vim.api.nvim_buf_set_lines(results_bufnr, 0, -1, false, {})
- local results = finder:get_results(results_win, results_bufnr, line)
- end),
+ -- Call this once to pre-populate if it makes sense
+ vim.schedule_wrap(on_lines(nil, nil, nil, 0, 1))
+
+ -- Register attach
+ vim.api.nvim_buf_attach(prompt_bufnr, true, {
+ on_lines = vim.schedule_wrap(on_lines),
on_detach = function(...)
-- print("DETACH:", ...)
end,
})
- -- -- TODO: Please use the cool autocmds once you get off your lazy bottom and finish the PR ;)
- -- local autocmd_string = string.format(
- -- [[ autocmd TextChanged,TextChangedI <buffer> :lua __TelescopeOnChange(%s, "%s", %s, %s)]],
- -- prompt_bufnr,
- -- '',
- -- results_bufnr,
- -- results_win)
-- TODO: Use WinLeave as well?
local on_buf_leave = string.format(
diff --git a/lua/telescope/previewers.lua b/lua/telescope/previewers.lua
index a36ec5a..ccbd7db 100644
--- a/lua/telescope/previewers.lua
+++ b/lua/telescope/previewers.lua
@@ -3,14 +3,45 @@ local previewers = {}
local Previewer = {}
Previewer.__index = Previewer
-function Previewer:new(fn)
+function Previewer:new(opts)
+ opts = opts or {}
+
return setmetatable({
- fn = fn,
+ preview_fn = opts.preview_fn,
}, Previewer)
end
+function Previewer:preview(preview_win, preview_bufnr, results_bufnr, row)
+ return self.preview_fn(preview_win, preview_bufnr, results_bufnr, row)
+end
+
previewers.new = function(...)
return Previewer:new(...)
end
+previewers.vim_buffer = previewers.new {
+ preview_fn = function(preview_win, preview_bufnr, results_bufnr, row)
+ assert(preview_bufnr)
+
+ local line = vim.api.nvim_buf_get_lines(results_bufnr, row, row + 1, false)[1]
+ local file_name = vim.split(line, ":")[1]
+
+ -- print(file_name)
+ -- vim.fn.termopen(
+ -- string.format("bat --color=always --style=grid %s"),
+ -- vim.fn.fnamemodify(file_name, ":p")
+ local bufnr = vim.fn.bufadd(file_name)
+ vim.fn.bufload(bufnr)
+
+ -- TODO: We should probably call something like this because we're not always getting highlight and all that stuff.
+ -- api.nvim_command('doautocmd filetypedetect BufRead ' .. vim.fn.fnameescape(filename))
+ vim.api.nvim_win_set_buf(preview_win, bufnr)
+ vim.api.nvim_win_set_option(preview_win, 'wrap', false)
+ vim.api.nvim_win_set_option(preview_win, 'winhl', 'Normal:Normal')
+ vim.api.nvim_win_set_option(preview_win, 'winblend', 20)
+ vim.api.nvim_win_set_option(preview_win, 'signcolumn', 'no')
+ vim.api.nvim_win_set_option(preview_win, 'foldlevel', 100)
+ end,
+}
+
return previewers
diff --git a/lua/telescope/sorters.lua b/lua/telescope/sorters.lua
new file mode 100644
index 0000000..d5fb6f9
--- /dev/null
+++ b/lua/telescope/sorters.lua
@@ -0,0 +1,32 @@
+local sorters = {}
+
+
+local Sorter = {}
+Sorter.__index = Sorter
+
+---@class Sorter
+--- Sorter sorts a list of results by return a single integer for a line,
+--- given a prompt
+---
+--- Lower number is better (because it's like a closer match)
+--- But, any number below 0 means you want that line filtered out.
+--- @param scoring_function function Function that has the interface:
+-- (sorter, prompt, line): number
+function Sorter:new(opts)
+ opts = opts or {}
+
+ return setmetatable({
+ state = {},
+ scoring_function = opts.scoring_function,
+ }, Sorter)
+end
+
+function Sorter:score(prompt, line)
+ return self:scoring_function(prompt, line)
+end
+
+function sorters.new(...)
+ return Sorter:new(...)
+end
+
+return sorters
diff --git a/lua/telescope/utils.lua b/lua/telescope/utils.lua
new file mode 100644
index 0000000..196453a
--- /dev/null
+++ b/lua/telescope/utils.lua
@@ -0,0 +1,14 @@
+local utils = {}
+
+local function reversedipairsiter(t, i)
+ i = i - 1
+ if i ~= 0 then
+ return i, t[i]
+ end
+end
+
+utils.reversed_ipairs = function(t)
+ return reversedipairsiter, t, #t + 1
+end
+
+return utils