feat: quickfix (#293)
* feat: quickfix (not implemented) * [WIP]: Wed 09 Dec 2020 11:11:30 PM EST * somewhat working linked list impl * getting closer * might be working * might be working for real * works and implemented basic example * dont forget to close prompt * fix descending and add more tests * test fixes * fix test * more logging * Fix some more tests * Fix logging messing up tests * fix: lint * fix: multi select stuffs
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
local assert = require('luassert')
|
||||
local builtin = require('telescope.builtin')
|
||||
local log = require('telescope.log')
|
||||
|
||||
local Job = require("plenary.job")
|
||||
local Path = require("plenary.path")
|
||||
|
||||
local tester = {}
|
||||
|
||||
tester.debug = false
|
||||
|
||||
local replace_terms = function(input)
|
||||
return vim.api.nvim_replace_termcodes(input, true, false, true)
|
||||
end
|
||||
@@ -15,7 +19,53 @@ local nvim_feed = function(text, feed_opts)
|
||||
vim.api.nvim_feedkeys(text, feed_opts, true)
|
||||
end
|
||||
|
||||
tester.picker_feed = function(input, test_cases, debug)
|
||||
local writer = function(val)
|
||||
if type(val) == "table" then
|
||||
val = vim.fn.json_encode(val) .. "\n"
|
||||
end
|
||||
|
||||
if tester.debug then
|
||||
print(val)
|
||||
else
|
||||
io.stderr:write(val)
|
||||
end
|
||||
end
|
||||
|
||||
local execute_test_case = function(location, key, spec)
|
||||
local ok, actual = pcall(spec[2])
|
||||
|
||||
if not ok then
|
||||
writer {
|
||||
location = 'Error: ' .. location,
|
||||
case = key,
|
||||
expected = 'To succeed and return: ' .. tostring(spec[1]),
|
||||
actual = actual,
|
||||
|
||||
_type = spec._type,
|
||||
}
|
||||
else
|
||||
writer {
|
||||
location = location,
|
||||
case = key,
|
||||
expected = spec[1],
|
||||
actual = actual,
|
||||
|
||||
_type = spec._type,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local end_test_cases = function()
|
||||
vim.cmd [[qa!]]
|
||||
end
|
||||
|
||||
local invalid_test_case = function(k)
|
||||
writer { case = k, expected = '<a valid key>', actual = k }
|
||||
|
||||
end_test_cases()
|
||||
end
|
||||
|
||||
tester.picker_feed = function(input, test_cases)
|
||||
input = replace_terms(input)
|
||||
|
||||
return coroutine.wrap(function()
|
||||
@@ -28,75 +78,66 @@ tester.picker_feed = function(input, test_cases, debug)
|
||||
if string.match(char, "%g") then
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
if tester.debug then
|
||||
vim.wait(200)
|
||||
end
|
||||
end
|
||||
|
||||
vim.wait(10, function() end)
|
||||
vim.wait(10)
|
||||
|
||||
local timer = vim.loop.new_timer()
|
||||
timer:start(20, 0, vim.schedule_wrap(function()
|
||||
if test_cases.post_close then
|
||||
for k, v in ipairs(test_cases.post_close) do
|
||||
io.stderr:write(vim.fn.json_encode({ case = k, expected = v[1], actual = v[2]() }))
|
||||
io.stderr:write("\n")
|
||||
if tester.debug then
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
vim.defer_fn(function()
|
||||
if test_cases.post_typed then
|
||||
for k, v in ipairs(test_cases.post_typed) do
|
||||
execute_test_case('post_typed', k, v)
|
||||
end
|
||||
end
|
||||
|
||||
if debug then
|
||||
nvim_feed(replace_terms("<CR>"), "")
|
||||
end, 20)
|
||||
|
||||
vim.defer_fn(function()
|
||||
if test_cases.post_close then
|
||||
for k, v in ipairs(test_cases.post_close) do
|
||||
execute_test_case('post_close', k, v)
|
||||
end
|
||||
end
|
||||
|
||||
if tester.debug then
|
||||
return
|
||||
end
|
||||
|
||||
vim.defer_fn(function()
|
||||
vim.cmd [[qa!]]
|
||||
end, 10)
|
||||
end))
|
||||
vim.defer_fn(end_test_cases, 20)
|
||||
end, 40)
|
||||
|
||||
if not debug then
|
||||
vim.schedule(function()
|
||||
if test_cases.post_typed then
|
||||
for k, v in ipairs(test_cases.post_typed) do
|
||||
io.stderr:write(vim.fn.json_encode({ case = k, expected = v[1], actual = v[2]() }))
|
||||
io.stderr:write("\n")
|
||||
end
|
||||
end
|
||||
|
||||
nvim_feed(replace_terms("<CR>"), "")
|
||||
end)
|
||||
end
|
||||
coroutine.yield()
|
||||
end)
|
||||
end
|
||||
|
||||
-- local test_cases = {
|
||||
-- post_typed = {
|
||||
-- },
|
||||
-- post_close = {
|
||||
-- { "README.md", function() return "README.md" end },
|
||||
-- },
|
||||
-- }
|
||||
|
||||
local _VALID_KEYS = {
|
||||
post_typed = true,
|
||||
post_close = true,
|
||||
}
|
||||
|
||||
tester.builtin_picker = function(key, input, test_cases, opts)
|
||||
tester.builtin_picker = function(builtin_key, input, test_cases, opts)
|
||||
opts = opts or {}
|
||||
local debug = opts.debug or false
|
||||
tester.debug = opts.debug or false
|
||||
|
||||
for k, _ in pairs(test_cases) do
|
||||
if not _VALID_KEYS[k] then
|
||||
-- TODO: Make an error type for the json protocol.
|
||||
io.stderr:write(vim.fn.json_encode({ case = k, expected = '<a valid key>', actual = k }))
|
||||
io.stderr:write("\n")
|
||||
vim.cmd [[qa!]]
|
||||
return invalid_test_case(k)
|
||||
end
|
||||
end
|
||||
|
||||
opts.on_complete = {
|
||||
tester.picker_feed(input, test_cases, debug)
|
||||
tester.picker_feed(input, test_cases),
|
||||
}
|
||||
|
||||
builtin[key](opts)
|
||||
builtin[builtin_key](opts)
|
||||
end
|
||||
|
||||
local get_results_from_file = function(file)
|
||||
@@ -107,11 +148,14 @@ local get_results_from_file = function(file)
|
||||
'-u',
|
||||
'scripts/minimal_init.vim',
|
||||
'-c',
|
||||
'luafile ' .. file
|
||||
string.format(
|
||||
[[lua require("telescope.pickers._test")._execute("%s")]],
|
||||
file
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
j:sync()
|
||||
j:sync(1000)
|
||||
|
||||
local results = j:stderr_result()
|
||||
local result_table = {}
|
||||
@@ -122,10 +166,27 @@ local get_results_from_file = function(file)
|
||||
return result_table
|
||||
end
|
||||
|
||||
|
||||
local asserters = {
|
||||
_default = assert.are.same,
|
||||
|
||||
are = assert.are.same,
|
||||
are_not = assert.are_not.same,
|
||||
}
|
||||
|
||||
|
||||
local check_results = function(results)
|
||||
-- TODO: We should get all the test cases here that fail, not just the first one.
|
||||
for _, v in ipairs(results) do
|
||||
assert.are.same(v.expected, v.actual)
|
||||
local assertion = asserters[v._type or 'default']
|
||||
|
||||
assertion(
|
||||
v.expected,
|
||||
v.actual,
|
||||
string.format("Test Case: %s // %s",
|
||||
v.location,
|
||||
v.case)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -144,14 +205,52 @@ tester.run_string = function(contents)
|
||||
vim.fn.delete(tempname)
|
||||
|
||||
check_results(result_table)
|
||||
-- assert.are.same(result_table.expected, result_table.actual)
|
||||
end
|
||||
|
||||
tester.run_file = function(filename)
|
||||
local file = './lua/tests/pickers/' .. filename .. '.lua'
|
||||
|
||||
if not Path:new(file):exists() then
|
||||
assert.are.same("<An existing file>", file)
|
||||
end
|
||||
|
||||
local result_table = get_results_from_file(file)
|
||||
assert.are.same(result_table.expected, result_table.actual)
|
||||
|
||||
check_results(result_table)
|
||||
end
|
||||
|
||||
tester.not_ = function(val)
|
||||
val._type = 'are_not'
|
||||
return val
|
||||
end
|
||||
|
||||
tester._execute = function(filename)
|
||||
-- Important so that the outputs don't get mixed
|
||||
log.use_console = false
|
||||
|
||||
vim.cmd(string.format("luafile %s", filename))
|
||||
|
||||
local f = loadfile(filename)
|
||||
if not f then
|
||||
writer {
|
||||
location = 'Error: ' .. filename,
|
||||
case = filename,
|
||||
expected = 'To succeed',
|
||||
actual = nil,
|
||||
}
|
||||
end
|
||||
|
||||
local ok, msg = pcall(f)
|
||||
if not ok then
|
||||
writer {
|
||||
location = "Error: " .. msg,
|
||||
case = msg,
|
||||
expected = msg,
|
||||
}
|
||||
end
|
||||
|
||||
end_test_cases()
|
||||
end
|
||||
|
||||
|
||||
return tester
|
||||
|
||||
@@ -22,9 +22,15 @@ test_helpers.get_results = function()
|
||||
return vim.api.nvim_buf_get_lines(test_helpers.get_results_bufnr(), 0, -1, false)
|
||||
end
|
||||
|
||||
test_helpers.get_last_result = function()
|
||||
test_helpers.get_best_result = function()
|
||||
local results = test_helpers.get_results()
|
||||
return results[#results]
|
||||
local picker = test_helpers.get_picker ()
|
||||
|
||||
if picker.sorting_strategy == 'ascending' then
|
||||
return results[1]
|
||||
else
|
||||
return results[#results]
|
||||
end
|
||||
end
|
||||
|
||||
test_helpers.get_selection = function()
|
||||
@@ -41,7 +47,7 @@ test_helpers.make_globals = function()
|
||||
GetPrompt = test_helpers.get_prompt -- luacheck: globals GetPrompt
|
||||
|
||||
GetResults = test_helpers.get_results -- luacheck: globals GetResults
|
||||
GetLastResult = test_helpers.get_last_result -- luacheck: globals GetLastResult
|
||||
GetBestResult = test_helpers.get_best_result -- luacheck: globals GetBestResult
|
||||
|
||||
GetSelection = test_helpers.get_selection -- luacheck: globals GetSelection
|
||||
GetSelectionValue = test_helpers.get_selection_value -- luacheck: globals GetSelectionValue
|
||||
|
||||
@@ -3,6 +3,7 @@ local a = vim.api
|
||||
local highlights = {}
|
||||
|
||||
local ns_telescope_selection = a.nvim_create_namespace('telescope_selection')
|
||||
local ns_telescope_multiselection = a.nvim_create_namespace('telescope_mulitselection')
|
||||
local ns_telescope_entry = a.nvim_create_namespace('telescope_entry')
|
||||
|
||||
local Highlighter = {}
|
||||
@@ -75,6 +76,28 @@ function Highlighter:hi_selection(row, caret)
|
||||
)
|
||||
end
|
||||
|
||||
function Highlighter:hi_multiselect(row, entry)
|
||||
local results_bufnr = assert(self.picker.results_bufnr, "Must have a results bufnr")
|
||||
|
||||
if self.picker.multi_select[entry] then
|
||||
vim.api.nvim_buf_add_highlight(
|
||||
results_bufnr,
|
||||
ns_telescope_multiselection,
|
||||
"TelescopeMultiSelection",
|
||||
row,
|
||||
0,
|
||||
-1
|
||||
)
|
||||
else
|
||||
vim.api.nvim_buf_clear_namespace(
|
||||
results_bufnr,
|
||||
ns_telescope_multiselection,
|
||||
row,
|
||||
row + 1
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
highlights.new = function(...)
|
||||
return Highlighter:new(...)
|
||||
end
|
||||
|
||||
@@ -1,56 +1,75 @@
|
||||
local scroller = {}
|
||||
|
||||
local calc_count_fn = function(sorting_strategy)
|
||||
if sorting_strategy == 'ascending' then
|
||||
return function(a, b) return math.min(a, b) end
|
||||
else
|
||||
return function(a, b, row)
|
||||
if a == b or not row then
|
||||
return math.max(a, b)
|
||||
else
|
||||
local x = a - b
|
||||
if row < x then
|
||||
return math.max(a, b) - 1, true
|
||||
elseif row == a then
|
||||
return x, true
|
||||
else
|
||||
return math.max(a, b)
|
||||
end
|
||||
local range_calculators = {
|
||||
ascending = function(max_results, num_results)
|
||||
return 0, math.min(max_results, num_results)
|
||||
end,
|
||||
|
||||
descending = function(max_results, num_results)
|
||||
return math.max(max_results - num_results, 0), max_results
|
||||
end,
|
||||
}
|
||||
|
||||
local scroll_calculators = {
|
||||
cycle = function(range_fn)
|
||||
return function(max_results, num_results, row)
|
||||
local start, finish = range_fn(max_results, num_results)
|
||||
|
||||
if row >= finish then
|
||||
return start
|
||||
elseif row < start then
|
||||
return finish - 1
|
||||
end
|
||||
|
||||
return row
|
||||
end
|
||||
end,
|
||||
|
||||
limit = function(range_fn)
|
||||
return function(max_results, num_results, row)
|
||||
local start, finish = range_fn(max_results, num_results)
|
||||
|
||||
if row >= finish then
|
||||
return finish - 1
|
||||
elseif row < start then
|
||||
return start
|
||||
end
|
||||
|
||||
return row
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
scroller.create = function(scroll_strategy, sorting_strategy)
|
||||
local range_fn = range_calculators[sorting_strategy]
|
||||
if not range_fn then
|
||||
error(debug.traceback("Unknown sorting strategy: " .. sorting_strategy))
|
||||
end
|
||||
end
|
||||
|
||||
scroller.create = function(strategy, sorting_strategy)
|
||||
local calc_count = calc_count_fn(sorting_strategy)
|
||||
local scroll_fn = scroll_calculators[scroll_strategy]
|
||||
if not scroll_fn then
|
||||
error(debug.traceback("Unknown scroll strategy: " .. (scroll_strategy or '')))
|
||||
end
|
||||
|
||||
if strategy == 'cycle' then
|
||||
return function(max_results, num_results, row)
|
||||
local count, b = calc_count(max_results, num_results, row)
|
||||
if b then return count end
|
||||
local calculator = scroll_fn(range_fn)
|
||||
return function(max_results, num_results, row)
|
||||
local result = calculator(max_results, num_results, row)
|
||||
|
||||
if row >= count then
|
||||
return 0
|
||||
elseif row < 0 then
|
||||
return count - 1
|
||||
end
|
||||
|
||||
return row
|
||||
if result < 0 then
|
||||
error(string.format(
|
||||
"Must never return a negative row: { result = %s, args = { %s %s %s } }",
|
||||
result, max_results, num_results, row
|
||||
))
|
||||
end
|
||||
elseif strategy == 'limit' or strategy == nil then
|
||||
return function(max_results, num_results, row)
|
||||
local count = calc_count(max_results, num_results)
|
||||
|
||||
if row >= count then
|
||||
return count - 1
|
||||
elseif row < 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
return row
|
||||
if result >= max_results then
|
||||
error(string.format(
|
||||
"Must never exceed max results: { result = %s, args = { %s %s %s } }",
|
||||
result, max_results, num_results, row
|
||||
))
|
||||
end
|
||||
else
|
||||
error("Unsupported strategy: " .. strategy)
|
||||
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user