WIP: Actually get the UI to work and add some tests
This commit is contained in:
@@ -29,6 +29,7 @@ function Finder:new(opts)
|
||||
-- list
|
||||
-- ...
|
||||
return setmetatable({
|
||||
results = opts.results,
|
||||
fn_command = opts.fn_command,
|
||||
static = opts.static,
|
||||
state = {},
|
||||
@@ -46,6 +47,16 @@ end
|
||||
-- do_your_job
|
||||
-- process_plz
|
||||
function Finder:_find(prompt, process_result, process_complete)
|
||||
if self.results then
|
||||
assert(type(self.results) == 'table', "self.results must be a table")
|
||||
for _, v in ipairs(self.results) do
|
||||
process_result(v)
|
||||
end
|
||||
|
||||
process_complete()
|
||||
return
|
||||
end
|
||||
|
||||
if (self.state.job_id or 0) > 0 then
|
||||
vim.fn.jobstop(self.job_id)
|
||||
end
|
||||
|
||||
@@ -1,83 +1,4 @@
|
||||
-- https://raw.githubusercontent.com/rxi/log.lua/master/log.lua
|
||||
-- log.lua
|
||||
--
|
||||
-- Copyright (c) 2016 rxi
|
||||
--
|
||||
-- This library is free software; you can redistribute it and/or modify it
|
||||
-- under the terms of the MIT license. See LICENSE for details.
|
||||
--
|
||||
|
||||
local log = { _version = "0.1.0" }
|
||||
|
||||
log.usecolor = true
|
||||
log.outfile = vim.fn.stdpath('data') .. '/telescope.log'
|
||||
log.console = false
|
||||
log.level = "trace"
|
||||
|
||||
|
||||
local modes = {
|
||||
{ name = "trace", color = "\27[34m", },
|
||||
{ name = "debug", color = "\27[36m", },
|
||||
{ name = "info", color = "\27[32m", },
|
||||
{ name = "warn", color = "\27[33m", },
|
||||
{ name = "error", color = "\27[31m", },
|
||||
{ name = "fatal", color = "\27[35m", },
|
||||
return require('plenary.log').new {
|
||||
plugin = 'telescope',
|
||||
level = 'debug',
|
||||
}
|
||||
|
||||
|
||||
local levels = {}
|
||||
for i, v in ipairs(modes) do
|
||||
levels[v.name] = i
|
||||
end
|
||||
|
||||
|
||||
local round = function(x, increment)
|
||||
increment = increment or 1
|
||||
x = x / increment
|
||||
return (x > 0 and math.floor(x + .5) or math.ceil(x - .5)) * increment
|
||||
end
|
||||
|
||||
for i, x in ipairs(modes) do
|
||||
local nameupper = x.name:upper()
|
||||
log[x.name] = function(...)
|
||||
-- Return early if we're below the log level
|
||||
if i < levels[log.level] then
|
||||
return
|
||||
end
|
||||
|
||||
local passed = {...}
|
||||
local fmt = table.remove(passed, 1)
|
||||
local inspected = {}
|
||||
for _, v in ipairs(passed) do
|
||||
table.insert(inspected, vim.inspect(v))
|
||||
end
|
||||
local msg = string.format(fmt, unpack(inspected))
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
local lineinfo = info.short_src .. ":" .. info.currentline
|
||||
|
||||
-- Output to console
|
||||
if log.console then
|
||||
print(string.format("%s[%-6s%s]%s %s: %s",
|
||||
log.usecolor and x.color or "",
|
||||
nameupper,
|
||||
os.date("%H:%M:%S"),
|
||||
log.usecolor and "\27[0m" or "",
|
||||
lineinfo,
|
||||
msg))
|
||||
end
|
||||
|
||||
-- Output to log file
|
||||
if log.outfile then
|
||||
local fp = io.open(log.outfile, "a")
|
||||
local str = string.format("[%-6s%s] %s: %s\n",
|
||||
nameupper, os.date(), lineinfo, msg)
|
||||
fp:write(str)
|
||||
fp:close()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
log.info("Logger Succesfully Loaded")
|
||||
|
||||
return log
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
local a = vim.api
|
||||
local fun = require('fun')
|
||||
local popup = require('popup')
|
||||
|
||||
|
||||
local zip = fun.zip
|
||||
local tomap = fun.tomap
|
||||
|
||||
local log = require('telescope.log')
|
||||
local mappings = require('telescope.mappings')
|
||||
local state = require('telescope.state')
|
||||
@@ -13,6 +9,8 @@ local utils = require('telescope.utils')
|
||||
|
||||
local pickers = {}
|
||||
|
||||
--- Picker is the main UI that shows up to interact w/ your results.
|
||||
-- Takes a filter & a previewr
|
||||
local Picker = {}
|
||||
Picker.__index = Picker
|
||||
|
||||
@@ -133,98 +131,77 @@ function Picker:find(opts)
|
||||
local on_lines = function(_, _, _, first_line, last_line)
|
||||
local prompt = vim.api.nvim_buf_get_lines(prompt_bufnr, first_line, last_line, false)[1]
|
||||
|
||||
|
||||
-- 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.
|
||||
|
||||
|
||||
-- Sorted table by scores.
|
||||
-- Lowest score gets lowest index.
|
||||
self.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.
|
||||
|
||||
local replace_line = function(score, row, line)
|
||||
log.trace("Replacing @ %s w/ text '%s' (%s)", row, line, score)
|
||||
vim.api.nvim_buf_set_lines(results_bufnr, row, row + 1, false, {line})
|
||||
end
|
||||
|
||||
local insert_line = function(score, row, line)
|
||||
log.trace("Inserting @ %s w/ text '%s' (%s)", row, line, score)
|
||||
vim.api.nvim_buf_set_lines(results_bufnr, row, row, false, {line})
|
||||
end
|
||||
local line_manager = pickers.line_manager(
|
||||
self.max_results,
|
||||
function(index, line)
|
||||
local row = self.max_results - index + 1
|
||||
|
||||
log.trace("Setting row", row, "with value", line)
|
||||
vim.api.nvim_buf_set_lines(results_bufnr, row, row + 1, false, {line})
|
||||
end
|
||||
)
|
||||
|
||||
local process_result = function(line)
|
||||
if vim.trim(line) == "" then
|
||||
return
|
||||
end
|
||||
|
||||
log.trace("Processing result... ", line)
|
||||
|
||||
local sort_score = 0
|
||||
if sorter then
|
||||
local sort_score = sorter:score(prompt, line)
|
||||
sort_score = sorter:score(prompt, line)
|
||||
if sort_score == -1 then
|
||||
log.trace("Filtering out result: ", line)
|
||||
return
|
||||
end
|
||||
|
||||
-- { 7, 3, 1, 1 }
|
||||
-- 2
|
||||
for row, row_score in utils.reversed_ipairs(self.line_scores) do
|
||||
if row_score > sort_score then
|
||||
-- Insert line at row
|
||||
insert_line(sort_score, self.max_results - row, line)
|
||||
|
||||
-- Insert current score in the table
|
||||
table.insert(self.line_scores, row + 1, sort_score)
|
||||
|
||||
-- All done :)
|
||||
return
|
||||
end
|
||||
|
||||
-- Don't keep inserting stuff
|
||||
if row > self.max_results then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Worst score so far, so add to end
|
||||
|
||||
-- example: 5 max results, 8
|
||||
local worst_line = self.max_results - #self.line_scores
|
||||
replace_line(sort_score, worst_line, line)
|
||||
table.insert(self.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
|
||||
|
||||
line_manager:add_result(sort_score, line)
|
||||
end
|
||||
|
||||
local process_complete = function()
|
||||
local worst_line = self.max_results - #self.line_scores
|
||||
local empty_lines = {}
|
||||
for _ = 1, worst_line do table.insert(empty_lines, "") end
|
||||
vim.api.nvim_buf_set_lines(results_bufnr, 0, worst_line, false, empty_lines)
|
||||
local worst_line = self.max_results - line_manager.num_results()
|
||||
local empty_lines = utils.repeated_table(worst_line, "")
|
||||
-- vim.api.nvim_buf_set_lines(results_bufnr, 0, worst_line + 1, false, empty_lines)
|
||||
|
||||
log.info("Worst Line after process_complete: %s", worst_line)
|
||||
log.trace("%s", tomap(zip(
|
||||
a.nvim_buf_get_lines(results_bufnr, worst_line, self.max_results, false),
|
||||
self.line_scores
|
||||
)))
|
||||
log.debug("Worst Line after process_complete: %s", worst_line, results_bufnr)
|
||||
|
||||
-- local fun = require('fun')
|
||||
-- local zip = fun.zip
|
||||
-- local tomap = fun.tomap
|
||||
|
||||
-- log.trace("%s", tomap(zip(
|
||||
-- a.nvim_buf_get_lines(results_bufnr, worst_line, self.max_results, false),
|
||||
-- self.line_scores
|
||||
-- )))
|
||||
end
|
||||
|
||||
pcall(function()
|
||||
local ok, msg = pcall(function()
|
||||
return finder(prompt, process_result, process_complete)
|
||||
end)
|
||||
|
||||
if not ok then
|
||||
log.warn("Failed with msg: ", msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Call this once to pre-populate if it makes sense
|
||||
-- vim.schedule_wrap(on_lines(nil, nil, nil, 0, 1))
|
||||
-- TODO: Uncomment
|
||||
vim.schedule(function()
|
||||
on_lines(nil, nil, nil, 0, 1)
|
||||
end)
|
||||
|
||||
-- Register attach
|
||||
vim.api.nvim_buf_attach(prompt_bufnr, true, {
|
||||
@@ -359,4 +336,82 @@ pickers.new = function(...)
|
||||
return Picker:new(...)
|
||||
end
|
||||
|
||||
-- TODO: We should consider adding `process_bulk` or `bulk_line_manager` for things
|
||||
-- that we always know the items and can score quickly, so as to avoid drawing so much.
|
||||
pickers.line_manager = function(max_results, set_line)
|
||||
log.debug("Creating line_manager...")
|
||||
|
||||
-- state contains list of
|
||||
-- {
|
||||
-- score = ...
|
||||
-- line = ...
|
||||
-- metadata ? ...
|
||||
-- }
|
||||
local state = {}
|
||||
|
||||
set_line = set_line or function() end
|
||||
|
||||
return setmetatable({
|
||||
add_result = function(self, score, line)
|
||||
score = score or 0
|
||||
|
||||
for index, item in ipairs(state) do
|
||||
if item.score > score then
|
||||
return self:insert(index, {
|
||||
score = score,
|
||||
line = line,
|
||||
})
|
||||
end
|
||||
|
||||
-- Don't add results that are too bad.
|
||||
if index >= max_results then
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
return self:insert({
|
||||
score = score,
|
||||
line = line,
|
||||
})
|
||||
end,
|
||||
|
||||
insert = function(self, index, item)
|
||||
if item == nil then
|
||||
item = index
|
||||
index = #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]
|
||||
|
||||
set_line(index, item.line)
|
||||
state[index] = item
|
||||
|
||||
index = index + 1
|
||||
item = next_item
|
||||
until not next_item
|
||||
end,
|
||||
|
||||
num_results = function()
|
||||
return #state
|
||||
end,
|
||||
|
||||
_get_state = function()
|
||||
return state
|
||||
end,
|
||||
}, {
|
||||
-- insert =
|
||||
|
||||
-- __index = function(_, line)
|
||||
-- end,
|
||||
|
||||
-- __newindex = function(_, index, line)
|
||||
-- end,
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
return pickers
|
||||
|
||||
@@ -29,7 +29,7 @@ previewers.vim_buffer = previewers.new {
|
||||
end
|
||||
local file_name = vim.split(line, ":")[1]
|
||||
|
||||
log.info("Previewing File: %s", file_name)
|
||||
log.trace("Previewing File: %s", file_name)
|
||||
|
||||
-- vim.fn.termopen(
|
||||
-- string.format("bat --color=always --style=grid %s"),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
local log = require('telescope.log')
|
||||
local util = require('telescope.utils')
|
||||
|
||||
local sorters = {}
|
||||
@@ -12,7 +13,7 @@ Sorter.__index = Sorter
|
||||
---
|
||||
--- 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:
|
||||
--- @field scoring_function function Function that has the interface:
|
||||
-- (sorter, prompt, line): number
|
||||
function Sorter:new(opts)
|
||||
opts = opts or {}
|
||||
@@ -59,4 +60,14 @@ sorters.get_ngram_sorter = function()
|
||||
}
|
||||
end
|
||||
|
||||
sorters.get_levenshtein_sorter = function()
|
||||
return Sorter:new {
|
||||
scoring_function = function(_, prompt, line)
|
||||
local result = require('telescope.algos.string_distance')(prompt, line)
|
||||
log.info("Sorting result for", prompt, line, " = ", result)
|
||||
return result
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
return sorters
|
||||
|
||||
@@ -19,6 +19,15 @@ utils.default_table_mt = {
|
||||
end
|
||||
}
|
||||
|
||||
utils.repeated_table = function(n, val)
|
||||
local empty_lines = {}
|
||||
for _ = 1, n do
|
||||
table.insert(empty_lines, val)
|
||||
end
|
||||
return empty_lines
|
||||
end
|
||||
|
||||
|
||||
local NGram = {}
|
||||
NGram.__index = NGram
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require('plenary.test_harness'):setup_busted()
|
||||
|
||||
local pickers = require('telescope.pickers')
|
||||
local utils = require('telescope.utils')
|
||||
|
||||
--[[
|
||||
@@ -13,6 +14,81 @@ describe('Picker', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('process_result', function()
|
||||
it('works with one entry', function()
|
||||
local lines_manager = pickers.line_manager(5, nil)
|
||||
|
||||
lines_manager:add_result(1, "hello")
|
||||
|
||||
assert.are.same(1, lines_manager:_get_state()[1].score)
|
||||
end)
|
||||
|
||||
it('works with two entries', function()
|
||||
local lines_manager = pickers.line_manager(5, nil)
|
||||
|
||||
lines_manager:add_result(1, "hello")
|
||||
lines_manager:add_result(2, "later")
|
||||
|
||||
assert.are.same("hello", lines_manager:_get_state()[1].line)
|
||||
assert.are.same("later", lines_manager:_get_state()[2].line)
|
||||
end)
|
||||
|
||||
it('calls functions when inserting', function()
|
||||
local called_count = 0
|
||||
local lines_manager = pickers.line_manager(5, function() called_count = called_count + 1 end)
|
||||
|
||||
assert(called_count == 0)
|
||||
lines_manager:add_result(1, "hello")
|
||||
assert(called_count == 1)
|
||||
end)
|
||||
|
||||
it('calls functions when inserting twice', function()
|
||||
local called_count = 0
|
||||
local lines_manager = pickers.line_manager(5, function() called_count = called_count + 1 end)
|
||||
|
||||
assert(called_count == 0)
|
||||
lines_manager:add_result(1, "hello")
|
||||
lines_manager:add_result(2, "world")
|
||||
assert(called_count == 2)
|
||||
end)
|
||||
|
||||
it('correctly sorts lower scores', function()
|
||||
local called_count = 0
|
||||
local lines_manager = pickers.line_manager(5, function() called_count = called_count + 1 end)
|
||||
lines_manager:add_result(5, "worse result")
|
||||
lines_manager:add_result(2, "better result")
|
||||
|
||||
assert.are.same("better result", lines_manager:_get_state()[1].line)
|
||||
assert.are.same("worse result", lines_manager:_get_state()[2].line)
|
||||
|
||||
-- once to insert "worse"
|
||||
-- once to insert "better"
|
||||
-- and then to move "worse"
|
||||
assert.are.same(3, called_count)
|
||||
end)
|
||||
|
||||
it('respects max results', function()
|
||||
local called_count = 0
|
||||
local lines_manager = pickers.line_manager(1, function() called_count = called_count + 1 end)
|
||||
lines_manager:add_result(2, "better result")
|
||||
lines_manager:add_result(5, "worse result")
|
||||
|
||||
assert.are.same("better result", lines_manager:_get_state()[1].line)
|
||||
|
||||
-- once to insert "worse"
|
||||
-- once to insert "better"
|
||||
-- and then to move "worse"
|
||||
assert.are.same(1, called_count)
|
||||
end)
|
||||
|
||||
-- TODO: We should decide if we want to add this or not.
|
||||
-- it('should handle no scores', function()
|
||||
-- local lines_manager = pickers.line_manager(5, nil)
|
||||
|
||||
-- lines_manager:add_result(nil,
|
||||
-- end)
|
||||
end)
|
||||
|
||||
describe('ngrams', function()
|
||||
it('should capture intself in the ngram', function()
|
||||
local n = utils.new_ngram()
|
||||
|
||||
Reference in New Issue
Block a user