feat(performance): Major performance improvements using async v2 from @oberblastmeister (#987)

* start: Working w/ async jobs

* short circuit to using bad finder if you pass writer.
This commit is contained in:
TJ DeVries
2021-08-20 11:11:24 -04:00
committed by GitHub
parent d6d28dbe32
commit a97af306c4
56 changed files with 626 additions and 2493 deletions

296
lua/telescope/_.lua Normal file
View File

@@ -0,0 +1,296 @@
local uv = vim.loop
local Object = require "plenary.class"
local log = require "plenary.log"
local async = require "plenary.async"
local channel = require("plenary.async").control.channel
local M = {}
local AsyncJob = {}
AsyncJob.__index = AsyncJob
function AsyncJob.new(opts)
local self = setmetatable({}, AsyncJob)
self.command, self.uv_opts = M.convert_opts(opts)
self.stdin = opts.stdin or M.NullPipe()
self.stdout = opts.stdout or M.NullPipe()
self.stderr = opts.stderr or M.NullPipe()
if opts.cwd then
-- TODO: not vim.fn
self.uv_opts.cwd = vim.fn.expand(opts.cwd)
end
self.uv_opts.stdio = {
self.stdin.handle,
self.stdout.handle,
self.stderr.handle,
}
return self
end
function AsyncJob:_for_each_pipe(f, ...)
for _, pipe in ipairs { self.stdin, self.stdout, self.stderr } do
f(pipe, ...)
end
end
function AsyncJob:close(force)
if force == nil then
force = true
end
self:_for_each_pipe(function(p)
p:close(force)
end)
if not self.handle:is_closing() then
self.handle:close()
end
log.debug "[async_job] closed"
end
M.spawn = function(opts)
local self = AsyncJob.new(opts)
self.handle = uv.spawn(
self.command,
self.uv_opts,
async.void(function()
self:close(false)
end)
)
return self
end
---@class uv_pipe_t
--- A pipe handle from libuv
---@field read_start function: Start reading
---@field read_stop function: Stop reading
---@field close function: Close the handle
---@field is_closing function: Whether handle is currently closing
---@field is_active function: Whether the handle is currently reading
---@class BasePipe
---@field super Object: Always available
---@field handle uv_pipe_t: A pipe handle
---@field extend function: Extend
local BasePipe = Object:extend()
function BasePipe:new()
self.eof_tx, self.eof_rx = channel.oneshot()
end
function BasePipe:close(force)
if force == nil then
force = true
end
assert(self.handle, "Must have a pipe to close. Otherwise it's weird!")
if self.handle:is_closing() then
return
end
-- If we're not forcing the stop, allow waiting for eof
-- This ensures that we don't end up with weird race conditions
if not force then
self.eof_rx()
end
self.handle:read_stop()
if not self.handle:is_closing() then
self.handle:close()
end
self._closed = true
end
---@class LinesPipe : BasePipe
local LinesPipe = BasePipe:extend()
function LinesPipe:new()
LinesPipe.super.new(self)
self.handle = uv.new_pipe(false)
end
function LinesPipe:read()
local read_tx, read_rx = channel.oneshot()
self.handle:read_start(function(err, data)
assert(not err, err)
self.handle:read_stop()
read_tx(data)
if data == nil then
self.eof_tx()
end
end)
return read_rx()
end
function LinesPipe:iter(schedule)
if schedule == nil then
schedule = true
end
local text = nil
local index = nil
local get_next_text = function(previous)
index = nil
local read = self:read()
if previous == nil and read == nil then
return
end
return (previous or "") .. (read or "")
end
local next_value = nil
next_value = function()
if schedule then
async.util.scheduler()
end
if text == nil or (text == "" and index == nil) then
return nil
end
local start = index
index = string.find(text, "\n", index, true)
if index == nil then
text = get_next_text(string.sub(text, start or 1))
return next_value()
end
index = index + 1
return string.sub(text, start or 1, index - 2)
end
text = get_next_text()
return function()
return next_value()
end
end
---@class NullPipe : BasePipe
local NullPipe = BasePipe:extend()
function NullPipe:new()
NullPipe.super.new(self)
self.start = function() end
self.read_start = function() end
self.close = function() end
-- This always has eof tx done, so can just call it now
self.eof_tx()
end
---@class ChunkPipe : BasePipe
local ChunkPipe = BasePipe:extend()
function ChunkPipe:new()
ChunkPipe.super.new(self)
self.handle = uv.new_pipe(false)
end
function ChunkPipe:read()
local read_tx, read_rx = channel.oneshot()
self.handle:read_start(function(err, data)
assert(not err, err)
self.handle:read_stop()
read_tx(data)
if data == nil then
self.eof_tx()
end
end)
return read_rx()
end
function ChunkPipe:iter()
return function()
if self._closed then
return nil
end
return self:read()
end
end
---@class ErrorPipe : BasePipe
local ErrorPipe = BasePipe:extend()
function ErrorPipe:new()
ErrorPipe.super.new(self)
self.handle = uv.new_pipe(false)
end
function ErrorPipe:start()
self.handle:read_start(function(err, data)
if not err and not data then
return
end
self.handle:read_stop()
self.handle:close()
error(string.format("Err: %s, Data: '%s'", err, data))
end)
end
M.NullPipe = NullPipe
M.LinesPipe = LinesPipe
M.ChunkPipe = ChunkPipe
M.ErrorPipe = ErrorPipe
M.convert_opts = function(o)
if not o then
error(debug.traceback "Options are required for Job:new")
end
local command = o.command
if not command then
if o[1] then
command = o[1]
else
error(debug.traceback "'command' is required for Job:new")
end
elseif o[1] then
error(debug.traceback "Cannot pass both 'command' and array args")
end
local args = o.args
if not args then
if #o > 1 then
args = { select(2, unpack(o)) }
end
end
local ok, is_exe = pcall(vim.fn.executable, command)
if not o.skip_validation and ok and 1 ~= is_exe then
error(debug.traceback(command .. ": Executable not found"))
end
local obj = {}
obj.args = args
return command, obj
end
return M

View File

@@ -1,56 +0,0 @@
vim.deepcopy = (function()
local function _id(v)
return v
end
local deepcopy_funcs = {
table = function(orig)
local copy = {}
if vim._empty_dict_mt ~= nil and getmetatable(orig) == vim._empty_dict_mt then
copy = vim.empty_dict()
end
for k, v in pairs(orig) do
copy[vim.deepcopy(k)] = vim.deepcopy(v)
end
if getmetatable(orig) then
setmetatable(copy, getmetatable(orig))
end
return copy
end,
["function"] = _id or function(orig)
local ok, dumped = pcall(string.dump, orig)
if not ok then
error(debug.traceback(dumped))
end
local cloned = loadstring(dumped)
local i = 1
while true do
local name = debug.getupvalue(orig, i)
if not name then
break
end
debug.upvaluejoin(cloned, i, orig, i)
i = i + 1
end
return cloned
end,
number = _id,
string = _id,
["nil"] = _id,
boolean = _id,
}
return function(orig)
local f = deepcopy_funcs[type(orig)]
if f then
return f(orig)
else
error("Cannot deepcopy object of type " .. type(orig))
end
end
end)()

View File

@@ -582,12 +582,22 @@ actions.git_staging_toggle = function(prompt_bufnr)
end
local entry_to_qf = function(entry)
local text = entry.text
if not text then
if type(entry.value) == "table" then
text = entry.value.text
else
text = entry.value
end
end
return {
bufnr = entry.bufnr,
filename = from_entry.path(entry, false),
lnum = entry.lnum,
col = entry.col,
text = entry.text or entry.value.text or entry.value,
text = text,
}
end

View File

@@ -18,7 +18,7 @@ end
--- Gets the current line
function action_state.get_current_line()
return global_state.get_global_key "current_line"
return global_state.get_global_key "current_line" or ""
end
--- Gets the current picker

View File

@@ -5,6 +5,7 @@ local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local previewers = require "telescope.previewers"
local sorters = require "telescope.sorters"
local utils = require "telescope.utils"
local conf = require("telescope.config").values
local log = require "telescope.log"
@@ -80,8 +81,6 @@ files.live_grep = function(opts)
return nil
end
prompt = escape_chars(prompt)
local search_list = {}
if search_dirs then
@@ -103,7 +102,9 @@ files.live_grep = function(opts)
prompt_title = "Live Grep",
finder = live_grepper,
previewer = conf.grep_previewer(opts),
sorter = conf.generic_sorter(opts),
-- TODO: It would be cool to use `--json` output for this
-- and then we could get the highlight positions directly.
sorter = sorters.highlighter_only(opts),
}):find()
end

View File

@@ -1,16 +1,14 @@
local actions = require "telescope.actions"
local channel = require("plenary.async.control").channel
local action_state = require "telescope.actions.state"
local actions = require "telescope.actions"
local conf = require("telescope.config").values
local entry_display = require "telescope.pickers.entry_display"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local entry_display = require "telescope.pickers.entry_display"
local utils = require "telescope.utils"
local strings = require "plenary.strings"
local a = require "plenary.async_lib"
local async, await = a.async, a.await
local channel = a.util.channel
local conf = require("telescope.config").values
local utils = require "telescope.utils"
local lsp = {}
@@ -309,20 +307,21 @@ lsp.workspace_symbols = function(opts)
}):find()
end
-- TODO(MERGE)
local function get_workspace_symbols_requester(bufnr)
local cancel = function() end
return async(function(prompt)
return function(prompt)
local tx, rx = channel.oneshot()
cancel()
_, cancel = vim.lsp.buf_request(bufnr, "workspace/symbol", { query = prompt }, tx)
local err, _, results_lsp = await(rx())
local err, _, results_lsp = rx()
assert(not err, err)
local locations = vim.lsp.util.symbols_to_items(results_lsp or {}, bufnr) or {}
return locations
end)
end
end
lsp.dynamic_workspace_symbols = function(opts)
@@ -335,7 +334,7 @@ lsp.dynamic_workspace_symbols = function(opts)
fn = get_workspace_symbols_requester(curr_bufnr),
},
previewer = conf.qflist_previewer(opts),
sorter = conf.generic_sorter(),
sorter = conf.generic_sorter(opts),
}):find()
end

View File

@@ -219,13 +219,20 @@ local telescope_defaults = {
borderchars = { { "", "", "", "", "", "", "", "" } },
get_status_text = {
function(self)
function(self, opts)
local xx = (self.stats.processed or 0) - (self.stats.filtered or 0)
local yy = self.stats.processed or 0
if xx == 0 and yy == 0 then
return ""
end
-- local status_icon
-- if opts.completed then
-- status_icon = "✔️"
-- else
-- status_icon = "*"
-- end
return string.format("%s / %s", xx, yy)
end,
},

View File

@@ -155,7 +155,10 @@ function EntryManager:add_entry(picker, score, entry)
info.looped = info.looped + 1
if container[2] > score then
-- print("Inserting: ", picker, index, node, new_container)
return self:_insert_container_before(picker, index, node, new_container)
end
if score < 1 and container[2] == score and #entry.ordinal < #container[1].ordinal then
return self:_insert_container_before(picker, index, node, new_container)
end
@@ -174,11 +177,13 @@ function EntryManager:add_entry(picker, score, entry)
end
function EntryManager:iter()
return coroutine.wrap(function()
for val in self.linked_states:iter() do
coroutine.yield(val[1])
local iterator = self.linked_states:iter()
return function()
local val = iterator()
if val then
return val[1]
end
end)
end
end
return EntryManager

View File

@@ -2,12 +2,10 @@ local Job = require "plenary.job"
local make_entry = require "telescope.make_entry"
local log = require "telescope.log"
local a = require "plenary.async_lib"
local await = a.await
local async_static_finder = require "telescope.finders.async_static_finder"
local async_oneshot_finder = require "telescope.finders.async_oneshot_finder"
-- local async_job_finder = require('telescope.finders.async_job_finder')
local async_job_finder = require "telescope.finders.async_job_finder"
local finders = {}
@@ -103,7 +101,7 @@ function JobFinder:_find(prompt, process_result, process_complete)
enable_recording = false,
on_stdout = on_output,
on_stderr = on_output,
-- on_stderr = on_output,
on_exit = function()
process_complete()
@@ -131,17 +129,15 @@ function DynamicFinder:new(opts)
end
function DynamicFinder:_find(prompt, process_result, process_complete)
a.scope(function()
local results = await(self.fn(prompt))
local results = self.fn(prompt)
for _, result in ipairs(results) do
if process_result(self.entry_maker(result)) then
return
end
for _, result in ipairs(results) do
if process_result(self.entry_maker(result)) then
return
end
end
process_complete()
end)
process_complete()
end
--- Return a new Finder
@@ -154,31 +150,18 @@ finders._new = function(opts)
return JobFinder:new(opts)
end
finders.new_job = function(command_generator, entry_maker, maximum_results, cwd)
-- return async_job_finder {
-- command_generator = command_generator,
-- entry_maker = entry_maker,
-- maximum_results = maximum_results,
-- cwd = cwd,
-- }
finders.new_async_job = function(opts)
if opts.writer then
return finders._new(opts)
end
return JobFinder:new {
fn_command = function(_, prompt)
local command_list = command_generator(prompt)
if command_list == nil then
return nil
end
local command = table.remove(command_list, 1)
return {
command = command,
args = command_list,
}
end,
return async_job_finder(opts)
end
finders.new_job = function(command_generator, entry_maker, _, cwd)
return async_job_finder {
command_generator = command_generator,
entry_maker = entry_maker,
maximum_results = maximum_results,
cwd = cwd,
}
end
@@ -186,8 +169,8 @@ end
--- One shot job
---@param command_list string[]: Command list to execute.
---@param opts table: stuff
--- @key entry_maker function Optional: function(line: string) => table
--- @key cwd string
-- @key entry_maker function Optional: function(line: string) => table
-- @key cwd string
finders.new_oneshot_job = function(command_list, opts)
opts = opts or {}

View File

@@ -1,14 +1,11 @@
local log = require "telescope.log"
local Job = require "plenary.job"
local async_lib = require "plenary.async_lib"
local async = async_lib.async
-- local await = async_lib.await
local void = async_lib.void
local async_job = require "telescope._"
local LinesPipe = require("telescope._").LinesPipe
local make_entry = require "telescope.make_entry"
local log = require "telescope.log"
return function(opts)
log.trace("Creating async_job:", opts)
local entry_maker = opts.entry_maker or make_entry.gen_from_string()
local fn_command = function(prompt)
local command_list = opts.command_generator(prompt)
@@ -18,58 +15,61 @@ return function(opts)
local command = table.remove(command_list, 1)
return {
local res = {
command = command,
args = command_list,
}
return res
end
local job
return setmetatable({
close = function() end,
}, {
__call = void(async(function(prompt, process_result, process_complete)
print("are we callin anything?", job)
if job and not job.is_shutdown then
log.debug "Shutting down old job"
job:shutdown()
end
local job_opts = fn_command(prompt)
if not job_opts then
local callable = function(_, prompt, process_result, process_complete)
if job then
job:close(true)
end
local job_opts = fn_command(prompt)
if not job_opts then
return
end
local writer = nil
-- if job_opts.writer and Job.is_job(job_opts.writer) then
-- writer = job_opts.writer
if opts.writer then
error "async_job_finder.writer is not yet implemented"
writer = async_job.writer(opts.writer)
end
local stdout = LinesPipe()
job = async_job.spawn {
command = job_opts.command,
args = job_opts.args,
cwd = job_opts.cwd or opts.cwd,
writer = writer,
stdout = stdout,
}
for line in stdout:iter(true) do
if process_result(entry_maker(line)) then
return
end
end
local writer = nil
if job_opts.writer and Job.is_job(job_opts.writer) then
writer = job_opts.writer
elseif opts.writer then
writer = Job:new(job_opts.writer)
process_complete()
end
return setmetatable({
close = function()
if job then
job:close(true)
end
job = Job:new {
command = job_opts.command,
args = job_opts.args,
cwd = job_opts.cwd or opts.cwd,
maximum_results = opts.maximum_results,
writer = writer,
enable_recording = false,
on_stdout = vim.schedule_wrap(function(_, line)
if not line or line == "" then
return
end
-- TODO: shutdown job here.
process_result(entry_maker(line))
end),
on_exit = function()
process_complete()
end,
}
job:start()
end)),
end,
}, {
__call = callable,
})
end

View File

@@ -1,14 +1,9 @@
local async_lib = require "plenary.async_lib"
local async = async_lib.async
local await = async_lib.await
local void = async_lib.void
local AWAITABLE = 1000
local async = require "plenary.async"
local async_job = require "telescope._"
local LinesPipe = require("telescope._").LinesPipe
local make_entry = require "telescope.make_entry"
local Job = require "plenary.job"
return function(opts)
opts = opts or {}
@@ -21,64 +16,65 @@ return function(opts)
local job_started = false
local job_completed = false
local stdout = nil
return setmetatable({
close = function()
results = {}
job_started = false
end,
-- close = function() results = {}; job_started = false end,
close = function() end,
results = results,
}, {
__call = void(async(function(_, prompt, process_result, process_complete)
__call = function(_, prompt, process_result, process_complete)
if not job_started then
local job_opts = fn_command()
local writer
if job_opts.writer and Job.is_job(job_opts.writer) then
writer = job_opts.writer
elseif job_opts.writer then
writer = Job:new(job_opts.writer)
end
-- TODO: Handle writers.
-- local writer
-- if job_opts.writer and Job.is_job(job_opts.writer) then
-- writer = job_opts.writer
-- elseif job_opts.writer then
-- writer = Job:new(job_opts.writer)
-- end
local job = Job:new {
stdout = LinesPipe()
local _ = async_job.spawn {
command = job_opts.command,
args = job_opts.args,
cwd = job_opts.cwd or cwd,
maximum_results = opts.maximum_results,
writer = writer,
enable_recording = false,
cwd = cwd,
on_stdout = vim.schedule_wrap(function(_, line)
num_results = num_results + 1
local v = entry_maker(line)
results[num_results] = v
process_result(v)
end),
on_exit = function()
process_complete()
job_completed = true
end,
stdout = stdout,
}
job:start()
job_started = true
end
if not job_completed then
for line in stdout:iter(true) do
num_results = num_results + 1
local v = entry_maker(line)
results[num_results] = v
process_result(v)
end
process_complete()
job_completed = true
return
end
local current_count = num_results
for index = 1, current_count do
-- TODO: Figure out scheduling...
async.util.scheduler()
if process_result(results[index]) then
break
end
if index % AWAITABLE == 0 then
await(async_lib.scheduler())
end
end
if job_completed then
process_complete()
end
end)),
end,
})
end

View File

@@ -1,7 +1,4 @@
local async_lib = require "plenary.async_lib"
local async = async_lib.async
local await = async_lib.await
local void = async_lib.void
local scheduler = require("plenary.async").util.scheduler
local make_entry = require "telescope.make_entry"
@@ -29,18 +26,18 @@ return function(opts)
results = results,
close = function() end,
}, {
__call = void(async(function(_, _, process_result, process_complete)
__call = function(_, _, process_result, process_complete)
for i, v in ipairs(results) do
if process_result(v) then
break
end
if i % 1000 == 0 then
await(async_lib.scheduler())
scheduler()
end
end
process_complete()
end)),
end,
})
end

View File

@@ -1,5 +1,3 @@
require "telescope._compat"
local _extensions = require "telescope._extensions"
local telescope = {}

View File

@@ -1,103 +0,0 @@
local log = require "telescope.log"
local path = {}
path.separator = package.config:sub(1, 1)
path.home = vim.fn.expand "~"
path.make_relative = function(filepath, cwd)
if not cwd or not filepath then
return filepath
end
if filepath:sub(1, #cwd) == cwd then
local offset = 0
-- if cwd does ends in the os separator, we need to take it off
if cwd:sub(#cwd, #cwd) ~= path.separator then
offset = 1
end
filepath = filepath:sub(#cwd + 1 + offset, #filepath)
end
return filepath
end
path.shorten = (function()
if jit then
local ffi = require "ffi"
ffi.cdef [[
typedef unsigned char char_u;
char_u *shorten_dir(char_u *str);
]]
return function(filepath)
if not filepath then
return filepath
end
local c_str = ffi.new("char[?]", #filepath + 1)
ffi.copy(c_str, filepath)
return ffi.string(ffi.C.shorten_dir(c_str))
end
else
return function(filepath)
return filepath
end
end
end)()
path.normalize = function(filepath, cwd)
filepath = path.make_relative(filepath, cwd)
-- Substitute home directory w/ "~"
filepath = filepath:gsub("^" .. path.home, "~", 1)
-- Remove double path separators, it's annoying
filepath = filepath:gsub(path.separator .. path.separator, path.separator)
return filepath
end
path.read_file = function(filepath)
local fd = vim.loop.fs_open(filepath, "r", 438)
if fd == nil then
return ""
end
local stat = assert(vim.loop.fs_fstat(fd))
if stat.type ~= "file" then
return ""
end
local data = assert(vim.loop.fs_read(fd, stat.size, 0))
assert(vim.loop.fs_close(fd))
return data
end
path.read_file_async = function(filepath, callback)
vim.loop.fs_open(filepath, "r", 438, function(err_open, fd)
if err_open then
print("We tried to open this file but couldn't. We failed with following error message: " .. err_open)
return
end
vim.loop.fs_fstat(fd, function(err_fstat, stat)
assert(not err_fstat, err_fstat)
if stat.type ~= "file" then
return callback ""
end
vim.loop.fs_read(fd, stat.size, 0, function(err_read, data)
assert(not err_read, err_read)
vim.loop.fs_close(fd, function(err_close)
assert(not err_close, err_close)
return callback(data)
end)
end)
end)
end)
end
return setmetatable({}, {
__index = function(_, k)
log.error "telescope.path is deprecated. please use plenary.path instead"
return path[k]
end,
})

View File

@@ -1,15 +1,12 @@
require "telescope"
local a = vim.api
local async_lib = require "plenary.async_lib"
local async_util = async_lib.util
local async = require "plenary.async"
local await_schedule = async.util.scheduler
local channel = require("plenary.async.control").channel
local popup = require "plenary.popup"
local async = async_lib.async
local await = async_lib.await
local channel = async_util.channel
require "telescope"
local actions = require "telescope.actions"
local action_set = require "telescope.actions.set"
local config = require "telescope.config"
@@ -70,12 +67,13 @@ function Picker:new(opts)
selection_caret = get_default(opts.selection_caret, config.values.selection_caret),
entry_prefix = get_default(opts.entry_prefix, config.values.entry_prefix),
initial_mode = get_default(opts.initial_mode, config.values.initial_mode),
debounce = get_default(tonumber(opts.debounce), nil),
default_text = opts.default_text,
get_status_text = get_default(opts.get_status_text, config.values.get_status_text),
_on_input_filter_cb = opts.on_input_filter_cb or function() end,
finder = opts.finder,
finder = assert(opts.finder, "Finder is required."),
sorter = opts.sorter or require("telescope.sorters").empty(),
all_previewers = opts.previewer,
@@ -228,7 +226,7 @@ function Picker:highlight_displayed_rows(results_bufnr, prompt)
end
function Picker:highlight_one_row(results_bufnr, prompt, display, row)
local highlights = self:_track("_highlight_time", self.sorter.highlighter, self.sorter, prompt, display)
local highlights = self.sorter:highlighter(prompt, display)
if highlights then
for _, hl in ipairs(highlights) do
@@ -274,8 +272,6 @@ function Picker:find()
self:close_existing_pickers()
self:reset_selection()
assert(self.finder, "Finder is required to do picking")
self.original_win_id = a.nvim_get_current_win()
-- User autocmd run it before create Telescope window
@@ -346,26 +342,50 @@ function Picker:find()
self.prompt_prefix = prompt_prefix
self:_reset_prefix_color()
-- Temporarily disabled: Draw the screen ASAP. This makes things feel speedier.
-- vim.cmd [[redraw]]
-- First thing we want to do is set all the lines to blank.
self.max_results = popup_opts.results.height
-- TODO(scrolling): This may be a hack when we get a little further into implementing scrolling.
vim.api.nvim_buf_set_lines(results_bufnr, 0, self.max_results, false, utils.repeated_table(self.max_results, ""))
-- TODO(status): I would love to get the status text not moving back and forth. Perhaps it is just a problem with
-- virtual text & prompt buffers or something though. I can't figure out why it would redraw the way it does.
--
-- A "hacked" version of this would be to calculate where the area I want the status to go and put a new window there.
-- With this method, I do not need to worry about padding or antying, just make it take up X characters or something.
local status_updater = self:get_status_updater(prompt_win, prompt_bufnr)
local debounced_status = debounce.throttle_leading(status_updater, 50)
-- local debounced_status = status_updater
local tx, rx = channel.mpsc()
self.__on_lines = tx.send
local main_loop = async(function()
while true do
await(async_lib.scheduler())
local find_id = self:_next_find_id()
local main_loop = async.void(function()
self.sorter:_init()
-- Do filetype last, so that users can register at the last second.
pcall(a.nvim_buf_set_option, prompt_bufnr, "filetype", "TelescopePrompt")
pcall(a.nvim_buf_set_option, results_bufnr, "filetype", "TelescopeResults")
-- TODO(async): I wonder if this should actually happen _before_ we nvim_buf_attach.
-- This way the buffer would always start with what we think it should when we start the loop.
if self.default_text then
self:set_prompt(self.default_text)
end
if self.initial_mode == "insert" then
vim.cmd [[startinsert!]]
elseif self.initial_mode ~= "normal" then
error("Invalid setting for initial_mode: " .. self.initial_mode)
end
await_schedule()
while true do
-- Wait for the next input
rx.last()
local _, _, _, first_line, last_line = await(rx.last())
self:_reset_track()
if not vim.api.nvim_buf_is_valid(prompt_bufnr) then
@@ -373,74 +393,58 @@ function Picker:find()
return
end
if not first_line then
first_line = 0
end
if not last_line then
last_line = 1
local start_time = vim.loop.hrtime()
local prompt = self:_get_prompt()
local on_input_result = self._on_input_filter_cb(prompt) or {}
local new_prompt = on_input_result.prompt
if new_prompt then
prompt = new_prompt
end
if first_line > 0 or last_line > 1 then
log.debug("ON_LINES: Bad range", first_line, last_line, self:_get_prompt())
return
end
local original_prompt = self:_get_prompt()
local on_input_result = self._on_input_filter_cb(original_prompt) or {}
local prompt = on_input_result.prompt or original_prompt
local finder = on_input_result.updated_finder
if finder then
local new_finder = on_input_result.updated_finder
if new_finder then
self.finder:close()
self.finder = finder
self.finder = new_finder
end
if self.sorter then
self.sorter:_start(prompt)
end
-- TODO: Entry manager should have a "bulk" setter. This can prevent a lot of redraws from display
self.sorter:_start(prompt)
self.manager = EntryManager:new(self.max_results, self.entry_adder, self.stats)
local find_id = self:_next_find_id()
local process_result = self:get_result_processor(find_id, prompt, debounced_status)
local process_complete = self:get_result_completor(self.results_bufnr, find_id, prompt, status_updater)
local ok, msg = pcall(function()
self.finder(prompt, process_result, vim.schedule_wrap(process_complete))
self.finder(prompt, process_result, process_complete)
end)
if not ok then
log.warn("Failed with msg: ", msg)
log.warn("Finder failed with msg: ", msg)
end
local diff_time = (vim.loop.hrtime() - start_time) / 1e6
if self.debounce and diff_time < self.debounce then
async.util.sleep(self.debounce - diff_time)
end
end
end)
-- Register attach
vim.api.nvim_buf_attach(prompt_bufnr, false, {
on_lines = tx.send,
on_lines = function(...)
find_id = self:_next_find_id()
self._result_completed = false
status_updater { completed = false }
tx.send(...)
end,
on_detach = function()
-- TODO: Can we add a "cleanup" / "teardown" function that completely removes these.
self.finder = nil
self.previewer = nil
self.sorter = nil
self.manager = nil
self.closed = true
-- TODO: Should we actually do this?
collectgarbage()
collectgarbage()
self:_detach()
end,
})
if self.sorter then
self.sorter:_init()
end
async_lib.run(main_loop())
status_updater()
-- TODO: Use WinLeave as well?
local on_buf_leave = string.format(
[[ autocmd BufLeave <buffer> ++nested ++once :silent lua require('telescope.pickers').on_close_prompt(%s)]],
@@ -480,19 +484,8 @@ function Picker:find()
mappings.apply_keymap(prompt_bufnr, self.attach_mappings, config.values.mappings)
-- Do filetype last, so that users can register at the last second.
pcall(a.nvim_buf_set_option, prompt_bufnr, "filetype", "TelescopePrompt")
pcall(a.nvim_buf_set_option, results_bufnr, "filetype", "TelescopeResults")
if self.default_text then
self:set_prompt(self.default_text)
end
if self.initial_mode == "insert" then
vim.cmd [[startinsert!]]
elseif self.initial_mode ~= "normal" then
error("Invalid setting for initial_mode: " .. self.initial_mode)
end
tx.send()
main_loop()
end
function Picker:hide_preview()
@@ -791,9 +784,7 @@ function Picker:set_selection(row)
end
local caret = self.selection_caret
-- local display = string.format('%s %s', caret,
-- (a.nvim_buf_get_lines(results_bufnr, row, row + 1, false)[1] or ''):sub(3)
-- )
local display, display_highlights = entry_display.resolve(self, entry)
display = caret .. display
@@ -939,23 +930,6 @@ function Picker:_reset_track()
self.stats.highlights = 0
end
function Picker:_track(key, func, ...)
local start, final
if self.track then
start = vim.loop.hrtime()
end
-- Hack... we just do this so that we can track stuff that returns two values.
local res1, res2 = func(...)
if self.track then
final = vim.loop.hrtime()
self.stats[key] = final - start + self.stats[key]
end
return res1, res2
end
function Picker:_increment(key)
self.stats[key] = (self.stats[key] or 0) + 1
end
@@ -987,12 +961,12 @@ function Picker:close_existing_pickers()
end
function Picker:get_status_updater(prompt_win, prompt_bufnr)
return function()
local text = self:get_status_text()
return function(opts)
if self.closed or not vim.api.nvim_buf_is_valid(prompt_bufnr) then
return
end
local current_prompt = vim.api.nvim_buf_get_lines(prompt_bufnr, 0, 1, false)[1]
local current_prompt = self:_get_prompt()
if not current_prompt then
return
end
@@ -1001,10 +975,11 @@ function Picker:get_status_updater(prompt_win, prompt_bufnr)
return
end
local prompt_len = #current_prompt
local text = self:get_status_text(opts)
local prompt_len = #self.prompt_prefix + #current_prompt
local padding = string.rep(" ", vim.api.nvim_win_get_width(prompt_win) - prompt_len - #text - 3)
vim.api.nvim_buf_clear_namespace(prompt_bufnr, ns_telescope_prompt, 0, 1)
local padding = string.rep(" ", vim.api.nvim_win_get_width(prompt_win) - prompt_len - #text)
vim.api.nvim_buf_clear_namespace(prompt_bufnr, ns_telescope_prompt, 0, -1)
vim.api.nvim_buf_set_virtual_text(prompt_bufnr, ns_telescope_prompt, 0, { { padding .. text, "NonText" } }, {})
-- TODO: Wait for bfredl
@@ -1022,7 +997,7 @@ end
function Picker:get_result_processor(find_id, prompt, status_updater)
local cb_add = function(score, entry)
self.manager:add_entry(self, score, entry)
status_updater()
status_updater { completed = false }
end
local cb_filter = function(_)
@@ -1030,7 +1005,7 @@ function Picker:get_result_processor(find_id, prompt, status_updater)
end
return function(entry)
if find_id ~= self._find_id or self.closed or self:is_done() then
if find_id ~= self._find_id then
return true
end
@@ -1059,61 +1034,62 @@ function Picker:get_result_processor(find_id, prompt, status_updater)
end
function Picker:get_result_completor(results_bufnr, find_id, prompt, status_updater)
return function()
return vim.schedule_wrap(function()
if self.closed == true or self:is_done() then
return
end
local selection_strategy = self.selection_strategy or "reset"
self:_do_selection(prompt)
-- TODO: Either: always leave one result or make sure we actually clean up the results when nothing matches
if selection_strategy == "row" then
if self._selection_row == nil and self.default_selection_index ~= nil then
self:set_selection(self:get_row(self.default_selection_index))
else
self:set_selection(self:get_selection_row())
end
elseif selection_strategy == "follow" then
if self._selection_row == nil and self.default_selection_index ~= nil then
self:set_selection(self:get_row(self.default_selection_index))
else
local index = self.manager:find_entry(self:get_selection())
if index then
local follow_row = self:get_row(index)
self:set_selection(follow_row)
else
self:set_selection(self:get_reset_row())
end
end
elseif selection_strategy == "reset" then
if self.default_selection_index ~= nil then
self:set_selection(self:get_row(self.default_selection_index))
else
self:set_selection(self:get_reset_row())
end
elseif selection_strategy == "closest" then
if prompt == "" and self.default_selection_index ~= nil then
self:set_selection(self:get_row(self.default_selection_index))
else
self:set_selection(self:get_reset_row())
end
else
error("Unknown selection strategy: " .. selection_strategy)
end
local current_line = vim.api.nvim_get_current_line():sub(self.prompt_prefix:len() + 1)
state.set_global_key("current_line", current_line)
status_updater()
state.set_global_key("current_line", self:_get_prompt())
status_updater { completed = true }
self:clear_extra_rows(results_bufnr)
self:highlight_displayed_rows(results_bufnr, prompt)
if self.sorter then
self.sorter:_finish(prompt)
end
self.sorter:_finish(prompt)
self:_on_complete()
self._result_completed = true
end)
end
function Picker:_do_selection(prompt)
local selection_strategy = self.selection_strategy or "reset"
-- TODO: Either: always leave one result or make sure we actually clean up the results when nothing matches
if selection_strategy == "row" then
if self._selection_row == nil and self.default_selection_index ~= nil then
self:set_selection(self:get_row(self.default_selection_index))
else
self:set_selection(self:get_selection_row())
end
elseif selection_strategy == "follow" then
if self._selection_row == nil and self.default_selection_index ~= nil then
self:set_selection(self:get_row(self.default_selection_index))
else
local index = self.manager:find_entry(self:get_selection())
if index then
local follow_row = self:get_row(index)
self:set_selection(follow_row)
else
self:set_selection(self:get_reset_row())
end
end
elseif selection_strategy == "reset" then
if self.default_selection_index ~= nil then
self:set_selection(self:get_row(self.default_selection_index))
else
self:set_selection(self:get_reset_row())
end
elseif selection_strategy == "closest" then
if prompt == "" and self.default_selection_index ~= nil then
self:set_selection(self:get_row(self.default_selection_index))
else
self:set_selection(self:get_reset_row())
end
else
error("Unknown selection strategy: " .. selection_strategy)
end
end
@@ -1169,6 +1145,18 @@ function Picker:_reset_highlights()
self.highlighter:clear_display()
end
function Picker:_detach()
self.finder:close()
-- TODO: Can we add a "cleanup" / "teardown" function that completely removes these.
-- self.finder = nil
-- self.previewer = nil
-- self.sorter = nil
-- self.manager = nil
self.closed = true
end
pickers._Picker = Picker
return pickers

View File

@@ -89,7 +89,7 @@ function Highlighter:hi_multiselect(row, is_selected)
-- This is still kind of weird to me, since it seems like I'm erasing stuff
-- when i shouldn't... perhaps it's a bout the gravity of the extmark?
if #existing_marks > 0 then
log.trace("Clearning row: ", row)
log.trace("Clearning highlight multi select row: ", row)
vim.api.nvim_buf_clear_namespace(results_bufnr, ns_telescope_multiselection, row, row + 1)
end

View File

@@ -96,10 +96,10 @@ function Sorter:_start(prompt)
local len_previous = #previous
if #prompt < len_previous then
log.debug "Reset discard because shorter prompt"
log.trace "Reset discard because shorter prompt"
self._discard_state.filtered = {}
elseif string.sub(prompt, 1, len_previous) ~= previous then
log.debug "Reset discard no match"
log.trace "Reset discard no match"
self._discard_state.filtered = {}
end
@@ -167,11 +167,10 @@ end
sorters.Sorter = Sorter
TelescopeCachedTails = TelescopeCachedTails or nil
if not TelescopeCachedTails then
local make_cached_tail = function()
local os_sep = util.get_separator()
local match_string = "[^" .. os_sep .. "]*$"
TelescopeCachedTails = setmetatable({}, {
return setmetatable({}, {
__index = function(t, k)
local tail = string.match(k, match_string)
@@ -181,8 +180,8 @@ if not TelescopeCachedTails then
})
end
TelescopeCachedUppers = TelescopeCachedUppers
or setmetatable({}, {
local make_cached_uppers = function()
return setmetatable({}, {
__index = function(t, k)
local obj = {}
for i = 1, #k do
@@ -196,8 +195,7 @@ TelescopeCachedUppers = TelescopeCachedUppers
return obj
end,
})
TelescopeCachedNgrams = TelescopeCachedNgrams or {}
end
-- TODO: Match on upper case words
-- TODO: Match on last match
@@ -206,9 +204,11 @@ sorters.get_fuzzy_file = function(opts)
local ngram_len = opts.ngram_len or 2
local cached_ngrams = {}
local function overlapping_ngrams(s, n)
if TelescopeCachedNgrams[s] and TelescopeCachedNgrams[s][n] then
return TelescopeCachedNgrams[s][n]
if cached_ngrams[s] and cached_ngrams[s][n] then
return cached_ngrams[s][n]
end
local R = {}
@@ -216,15 +216,18 @@ sorters.get_fuzzy_file = function(opts)
R[#R + 1] = s:sub(i, i + n - 1)
end
if not TelescopeCachedNgrams[s] then
TelescopeCachedNgrams[s] = {}
if not cached_ngrams[s] then
cached_ngrams[s] = {}
end
TelescopeCachedNgrams[s][n] = R
cached_ngrams[s][n] = R
return R
end
local cached_tails = make_cached_tail()
local cached_uppers = make_cached_uppers()
return Sorter:new {
scoring_function = function(_, prompt, line)
local N = #prompt
@@ -243,8 +246,8 @@ sorters.get_fuzzy_file = function(opts)
-- Contains the original string
local contains_string = line_lower:find(prompt_lower, 1, true)
local prompt_uppers = TelescopeCachedUppers[prompt]
local line_uppers = TelescopeCachedUppers[line]
local prompt_uppers = cached_uppers[prompt]
local line_uppers = cached_uppers[line]
local uppers_matching = 0
for k, _ in pairs(prompt_uppers) do
@@ -254,7 +257,7 @@ sorters.get_fuzzy_file = function(opts)
end
-- TODO: Consider case senstivity
local tail = TelescopeCachedTails[line_lower]
local tail = cached_tails[line_lower]
local contains_tail = tail:find(prompt, 1, true)
local consecutive_matches = 0
@@ -313,9 +316,10 @@ sorters.get_generic_fuzzy_sorter = function(opts)
local ngram_len = opts.ngram_len or 2
local cached_ngrams = {}
local function overlapping_ngrams(s, n)
if TelescopeCachedNgrams[s] and TelescopeCachedNgrams[s][n] then
return TelescopeCachedNgrams[s][n]
if cached_ngrams[s] and cached_ngrams[s][n] then
return cached_ngrams[s][n]
end
local R = {}
@@ -323,11 +327,11 @@ sorters.get_generic_fuzzy_sorter = function(opts)
R[#R + 1] = s:sub(i, i + n - 1)
end
if not TelescopeCachedNgrams[s] then
TelescopeCachedNgrams[s] = {}
if not cached_ngrams[s] then
cached_ngrams[s] = {}
end
TelescopeCachedNgrams[s][n] = R
cached_ngrams[s][n] = R
return R
end
@@ -462,6 +466,9 @@ sorters.get_fzy_sorter = function(opts)
}
end
-- TODO: Could probably do something nice where we check their conf
-- and choose their default for this.
-- But I think `fzy` is good default for now.
sorters.highlighter_only = function(opts)
opts = opts or {}
local fzy = opts.fzy_mod or require "telescope.algos.fzy"

View File

@@ -11,8 +11,13 @@ describe("telescope", function()
end)
describe("attach_mappings", function()
local new_picker = function(a, b)
a.finder = true
return picker.new(a, b)
end
it("should allow for passing in a function", function()
local p = picker.new({}, {
local p = new_picker({}, {
attach_mappings = function()
return 1
end,
@@ -22,7 +27,7 @@ describe("telescope", function()
it("should override an attach mappings passed in by opts", function()
local called_order = {}
local p = picker.new({
local p = new_picker({
attach_mappings = function()
table.insert(called_order, "opts")
end,

View File

@@ -1,22 +0,0 @@
--[[
vim.api.nvim_buf_set_lines(0, 4, -1, false, vim.tbl_keys(require('telescope.builtin')))
--]]
require("telescope.builtin").git_files()
RELOAD "telescope"
require("telescope.builtin").oldfiles()
require("telescope.builtin").grep_string()
require("telescope.builtin").lsp_document_symbols()
RELOAD "telescope"
require("telescope.builtin").lsp_workspace_symbols()
require("telescope.builtin").lsp_references()
require("telescope.builtin").builtin()
require("telescope.builtin").fd()
require("telescope.builtin").command_history()
require("telescope.builtin").search_history()
require("telescope.builtin").live_grep()
require("telescope.builtin").loclist()
-- TODO: make a function that puts stuff into quickfix.
-- that way we can test this better.
require("telescope.builtin").quickfix()

View File

@@ -1,80 +0,0 @@
RELOAD "telescope"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local previewers = require "telescope.previewers"
local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters"
local find_files = function(opts)
opts = opts or {}
opts.prompt_prefix = ""
local find_command = opts.find_command
if not find_command then
if 1 == vim.fn.executable "fd" then
find_command = { "fd", "--type", "f" }
elseif 1 == vim.fn.executable "fdfind" then
find_command = { "fdfind", "--type", "f" }
elseif 1 == vim.fn.executable "rg" then
find_command = { "rg", "--files" }
end
end
if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd)
end
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)
local p = pickers.new(opts, {
prompt = "Find Files",
finder = finders.new_oneshot_job(find_command, opts),
previewer = previewers.cat.new(opts),
sorter = sorters.get_fuzzy_file(),
track = true,
})
local count = 0
p:register_completion_callback(function(s)
print(
count,
vim.inspect(s.stats, {
process = function(item)
if type(item) == "string" and item:sub(1, 1) == "_" then
return nil
end
return item
end,
})
)
count = count + 1
end)
local feed = function(text, feed_opts)
feed_opts = feed_opts or "n"
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(text, true, false, true), feed_opts, true)
end
p:register_completion_callback(coroutine.wrap(function()
local input = "pickers.lua"
for i = 1, #input do
feed(input:sub(i, i))
coroutine.yield()
end
vim.wait(300, function() end)
feed("<CR>", "")
coroutine.yield()
print "STILL CALLED?"
end))
p:find()
end
find_files()

View File

@@ -1,105 +0,0 @@
require("plenary.reload").reload_module "plenary"
require("plenary.reload").reload_module "telescope"
--[[
Goals:
1. Easily test a sorter and finder to make sure we get all the results we need.
--]]
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters"
local EntryManager = require "telescope.entry_manager"
local find_and_sort_test = function(prompt, f, s)
local info = {}
local start = vim.loop.hrtime()
info.filtered = 0
info.added = 0
info.scoring_time = 0
info.set_entry = 0
local entry_manager = EntryManager:new(25, function()
info.set_entry = info.set_entry + 1
end, info)
local completed = false
local process_result = function(entry)
local score_start = vim.loop.hrtime()
local score = s:score(prompt, entry)
info.scoring_time = info.scoring_time + (vim.loop.hrtime() - score_start) / 1e9
-- Filter these out here.
if score == -1 then
info.filtered = info.filtered + 1
return
end
info.added = info.added + 1
entry_manager:add_entry(s:score(prompt, entry), entry)
end
local process_complete = function()
info.time = (vim.loop.hrtime() - start) / 1e9
info.total = info.filtered + info.added
completed = true
end
f(prompt, process_result, process_complete)
-- Wait until we're done to return
vim.wait(5000, function()
return completed
end, 10)
return entry_manager, info
end
local info_to_csv = function(info, filename)
local writer = io.open(filename, "a")
writer:write(string.format("%.8f", info.scoring_time) .. "\t")
writer:write(string.format("%.8f", info.time) .. "\t")
writer:write(info.looped .. "\t")
writer:write(info.filtered .. "\t")
writer:write(info.added .. "\t")
writer:write(info.inserted .. "\t")
writer:write(info.total .. "\t")
writer:write(info.set_entry .. "\t")
writer:write(string.format("%.0f", collectgarbage "count") .. "\t")
writer:write "\n"
writer:close()
end
local cwd = vim.fn.expand "~/build/neovim"
collectgarbage "collect"
for _ = 1, 1 do
-- local s = sorters.get_fuzzy_file()
local s = sorters.get_generic_fuzzy_sorter()
local finder = finders.new_oneshot_job({ "fdfind" }, {
cwd = cwd,
entry_maker = make_entry.gen_from_file { cwd = cwd },
-- disable_devicons = true,
-- maximum_results = 1000,
})
local res, info = find_and_sort_test("pickers.lua", finder, s)
-- print(vim.inspect(res:get_entry(1)))
-- print(vim.inspect(info))
info_to_csv(info, "/home/tj/tmp/profile.csv")
collectgarbage "collect"
end
-- No skip: 2,206,186
-- Ya skip: 2,133

View File

@@ -1,29 +0,0 @@
RELOAD "plenary"
RELOAD "telescope"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local previewers = require "telescope.previewers"
local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters"
local cwd = vim.fn.expand "~/build/neovim"
pickers.new({
prompt = "Large search",
finder = finders.new_oneshot_job({ "fdfind" }, {
cwd = cwd,
entry_maker = make_entry.gen_from_file { cwd = cwd },
-- disable_devicons = true,
-- maximum_results = 1000,
}),
sorter = sorters.get_fuzzy_file(),
previewer = previewers.cat.new { cwd = cwd },
}):find()
-- vim.wait(3000, function()
-- vim.cmd [[redraw!]]
-- return COMPLETED
-- end, 100)
-- vim.cmd [[bd!]]
-- vim.cmd [[stopinsert]]

View File

@@ -1,24 +0,0 @@
require("plenary.reload").reload_module "telescope"
local finders = require "telescope.finders"
local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters"
local previewers = require "telescope.previewers"
local make_entry = require "telescope.make_entry"
local my_list = {
"lua/telescope/WIP.lua",
"lua/telescope/actions.lua",
"lua/telescope/builtin.lua",
}
local opts = {}
pickers.new(opts, {
prompt = "Telescope Builtin",
finder = finders.new_table {
results = my_list,
},
sorter = sorters.get_generic_fuzzy_sorter(),
previewer = previewers.cat.new(opts),
}):find()

View File

@@ -1,70 +0,0 @@
-- TODO: Add a ladder test.
-- 1, 2, 4, 8, 16, 32 attempts
RELOAD "plenary"
-- RELOAD('telescope')
local profiler = require "plenary.profile.lua_profiler"
local Job = require "plenary.job"
BIG_LIST = nil
BIG_LIST = BIG_LIST or Job:new({ command = "fdfind", cwd = "~/build/" }):sync()
print(#BIG_LIST)
local do_profile = true
local sorter_to_test = require("telescope.sorters").get_fuzzy_file()
local strings_to_test = { "", "ev", "eval.c", "neovim/eval.c" }
if do_profile then
profiler.start()
end
local first_results = setmetatable({}, {
__index = function(t, k)
local obj = {}
rawset(t, k, obj)
return obj
end,
})
local second_results = {}
local do_iterations = function(num)
local start
for _, prompt in ipairs(strings_to_test) do
start = vim.fn.reltime()
for _ = 1, num do
for _, v in ipairs(BIG_LIST) do
sorter_to_test:score(prompt, v)
end
end
-- print("First Time: ", vim.fn.reltimestr(vim.fn.reltime(start)), num, prompt)
table.insert(first_results[prompt], vim.fn.reltimestr(vim.fn.reltime(start)))
start = vim.fn.reltime()
for _ = 1, num do
for _, v in ipairs(BIG_LIST) do
sorter_to_test:score(prompt, v)
end
end
-- print("Second Time: ", vim.fn.reltimestr(vim.fn.reltime(start)), num, prompt)
table.insert(second_results, vim.fn.reltimestr(vim.fn.reltime(start)))
end
end
do_iterations(1)
-- do_iterations(2)
-- do_iterations(4)
-- do_iterations(8)
-- do_iterations(16)
-- do_iterations(32)
print(vim.inspect(first_results))
if do_profile then
profiler.stop()
profiler.report "/home/tj/tmp/profiler_score.txt"
end

View File

@@ -1,50 +0,0 @@
-- local actions = require('telescope.actions')
-- local utils = require('telescope.utils')
require "telescope"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local previewers = require "telescope.previewers"
local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters"
local log = require "telescope.log"
local real_opts = setmetatable({}, { __mode = "v" })
local opts = setmetatable({}, {
__index = function(t, k)
log.debug("accessing:", k)
return real_opts[k]
end,
__newindex = function(t, k, v)
log.debug("setting:", k, v)
real_opts[k] = v
end,
})
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file()
if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd)
end
-- local get_finder_opts = function(opts)
-- local t = {}
-- t.entry_maker = table.pop(opts, 'entry_maker')
-- return t
-- end
-- local finder_opts = get_finder_opts(opts)
-- assert(not opts.entry_maker)
local picker_config = {
prompt = "Git File",
finder = finders.new_oneshot_job({ "git", "ls-files", "-o", "--exclude-standard", "-c" }, opts),
-- previewer = previewers.cat.new(opts),
-- sorter = sorters.get_fuzzy_file(opts),
-- sorter = sorters.get_fuzzy_file(),
}
log.debug "Done with config"
local x = pickers.new(picker_config)
x:find()
x = nil

View File

@@ -1,62 +0,0 @@
RELOAD "telescope"
local resolve = require "telescope.config.resolve"
local eq = function(a, b)
if a ~= b then
error(string.format("Expected a == b, got: %s and %s", vim.inspect(a), vim.inspect(b)))
end
end
local opt = nil
local height_config = 0.8
opt = resolve.win_option(height_config)
eq(height_config, opt.preview)
eq(height_config, opt.prompt)
eq(height_config, opt.results)
opt = resolve.win_option(nil, height_config)
eq(height_config, opt.preview)
eq(height_config, opt.prompt)
eq(height_config, opt.results)
local table_val = { "a" }
opt = resolve.win_option(nil, table_val)
eq(table_val, opt.preview)
eq(table_val, opt.prompt)
eq(table_val, opt.results)
local prompt_override = { "a", prompt = "b" }
opt = resolve.win_option(prompt_override)
eq("a", opt.preview)
eq("a", opt.results)
eq("b", opt.prompt)
local all_specified = { preview = "a", prompt = "b", results = "c" }
opt = resolve.win_option(all_specified)
eq("a", opt.preview)
eq("b", opt.prompt)
eq("c", opt.results)
local some_specified = { prompt = "b", results = "c" }
opt = resolve.win_option(some_specified, "a")
eq("a", opt.preview)
eq("b", opt.prompt)
eq("c", opt.results)
eq(10, resolve.resolve_height(0.1)(nil, 24, 100))
eq(2, resolve.resolve_width(0.1)(nil, 24, 100))
eq(10, resolve.resolve_width(10)(nil, 24, 100))
eq(24, resolve.resolve_width(50)(nil, 24, 100))
-- local true_table = {true}
-- opt = resolve.win_option(some_specified, 'a')
-- eq('a', opt.preview)
-- eq('b', opt.prompt)
-- eq('c', opt.results)
print "DONE!"

View File

@@ -1,70 +0,0 @@
RELOAD "telescope"
local actions = require "telescope.actions"
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local previewers = require "telescope.previewers"
local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters"
local utils = require "telescope.utils"
local slow_proc = function(opts)
opts = opts or {}
if opts.cwd then
opts.cwd = vim.fn.expand(opts.cwd)
end
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)
local p = pickers.new(opts, {
prompt = "Slow Proc",
finder = finders.new_oneshot_job({ "./scratch/slow_proc.sh" }, opts),
previewer = previewers.cat.new(opts),
sorter = sorters.get_fuzzy_file(),
track = true,
})
local count = 0
p:register_completion_callback(function(s)
print(
count,
vim.inspect(s.stats, {
process = function(item)
if type(item) == "string" and item:sub(1, 1) == "_" then
return nil
end
return item
end,
})
)
count = count + 1
end)
local feed = function(text)
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(text, true, false, true), "n", true)
end
if false then
p:register_completion_callback(coroutine.wrap(function()
local input = "pickers.lua"
for i = 1, #input do
feed(input:sub(i, i))
coroutine.yield()
end
vim.wait(300, function() end)
vim.cmd [[:q]]
vim.cmd [[:Messages]]
vim.cmd [[stopinsert]]
end))
end
p:find()
end
slow_proc()