summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua')
-rw-r--r--lua/telescope/builtin/files.lua14
-rw-r--r--lua/telescope/builtin/internal.lua2
-rw-r--r--lua/telescope/entry_manager.lua10
-rw-r--r--lua/telescope/finders.lua187
-rw-r--r--lua/telescope/finders/async_job_finder.lua73
-rw-r--r--lua/telescope/finders/async_oneshot_finder.lua81
-rw-r--r--lua/telescope/finders/async_static_finder.lua41
-rw-r--r--lua/telescope/log.lua3
-rw-r--r--lua/telescope/pickers.lua261
-rw-r--r--lua/telescope/pickers/layout_strategies.lua40
-rw-r--r--lua/telescope/pickers/window.lua17
-rw-r--r--lua/telescope/sorters.lua29
-rw-r--r--lua/tests/automated/telescope_spec.lua7
13 files changed, 412 insertions, 353 deletions
diff --git a/lua/telescope/builtin/files.lua b/lua/telescope/builtin/files.lua
index 24d02a0..23ceaa7 100644
--- a/lua/telescope/builtin/files.lua
+++ b/lua/telescope/builtin/files.lua
@@ -211,16 +211,16 @@ end
files.file_browser = function(opts)
opts = opts or {}
+ opts.depth = opts.depth or 1
opts.cwd = opts.cwd and vim.fn.expand(opts.cwd) or vim.loop.cwd()
-
- local gen_new_finder = function(path)
+ opts.new_finder = opts.new_finder or function(path)
opts.cwd = path
local data = {}
scan.scan_dir(path, {
hidden = opts.hidden or false,
add_dirs = true,
- depth = 1,
+ depth = opts.depth,
on_insert = function(entry, typ)
table.insert(data, typ == 'directory' and (entry .. os_sep) or entry)
end
@@ -242,8 +242,8 @@ files.file_browser = function(opts)
end
pickers.new(opts, {
- prompt_title = 'Find Files',
- finder = gen_new_finder(opts.cwd),
+ prompt_title = 'File Browser',
+ finder = opts.new_finder(opts.cwd),
previewer = conf.file_previewer(opts),
sorter = conf.file_sorter(opts),
attach_mappings = function(prompt_bufnr, map)
@@ -253,7 +253,7 @@ files.file_browser = function(opts)
local new_cwd = vim.fn.expand(action_state.get_selected_entry().path:sub(1, -2))
local current_picker = action_state.get_current_picker(prompt_bufnr)
current_picker.cwd = new_cwd
- current_picker:refresh(gen_new_finder(new_cwd), { reset_prompt = true })
+ current_picker:refresh(opts.new_finder(new_cwd), { reset_prompt = true })
end)
local create_new_file = function()
@@ -276,7 +276,7 @@ files.file_browser = function(opts)
Path:new(fpath:sub(1, -2)):mkdir({ parents = true })
local new_cwd = vim.fn.expand(fpath)
current_picker.cwd = new_cwd
- current_picker:refresh(gen_new_finder(new_cwd), { reset_prompt = true })
+ current_picker:refresh(opts.new_finder(new_cwd), { reset_prompt = true })
end
end
diff --git a/lua/telescope/builtin/internal.lua b/lua/telescope/builtin/internal.lua
index 7d9d750..7d2d716 100644
--- a/lua/telescope/builtin/internal.lua
+++ b/lua/telescope/builtin/internal.lua
@@ -815,8 +815,6 @@ internal.autocommands = function(opts)
inner_loop(line)
end
- -- print(vim.inspect(autocmd_table))
-
pickers.new(opts,{
prompt_title = 'autocommands',
finder = finders.new_table {
diff --git a/lua/telescope/entry_manager.lua b/lua/telescope/entry_manager.lua
index c7350cb..f32d29f 100644
--- a/lua/telescope/entry_manager.lua
+++ b/lua/telescope/entry_manager.lua
@@ -26,7 +26,7 @@ if past loop of must have scores,
local EntryManager = {}
EntryManager.__index = EntryManager
-function EntryManager:new(max_results, set_entry, info, id)
+function EntryManager:new(max_results, set_entry, info)
log.trace("Creating entry_manager...")
info = info or {}
@@ -40,7 +40,6 @@ function EntryManager:new(max_results, set_entry, info, id)
set_entry = set_entry or function() end
return setmetatable({
- id = id,
linked_states = LinkedList:new { track_at = max_results },
info = info,
max_results = max_results,
@@ -128,13 +127,6 @@ function EntryManager:_append_container(picker, new_container, should_update)
end
function EntryManager:add_entry(picker, score, entry)
- if picker and picker.id then
- if picker.request_number ~= self.id then
- error("ADDING ENTRY TOO LATE!")
- return
- end
- end
-
score = score or 0
local max_res = self.max_results
diff --git a/lua/telescope/finders.lua b/lua/telescope/finders.lua
index cf616b0..d2acd05 100644
--- a/lua/telescope/finders.lua
+++ b/lua/telescope/finders.lua
@@ -3,6 +3,10 @@ local Job = require('plenary.job')
local make_entry = require('telescope.make_entry')
local log = require('telescope.log')
+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 finders = {}
local _callable_obj = function()
@@ -104,179 +108,24 @@ function JobFinder:_find(prompt, process_result, process_complete)
self.job:start()
end
-local OneshotJobFinder = _callable_obj()
-
-function OneshotJobFinder:new(opts)
- opts = opts or {}
-
- assert(not opts.results, "`results` should be used with finder.new_table")
- assert(not opts.static, "`static` should be used with finder.new_oneshot_job")
-
- local obj = setmetatable({
- fn_command = opts.fn_command,
- entry_maker = opts.entry_maker or make_entry.from_string,
-
- cwd = opts.cwd,
- writer = opts.writer,
-
- maximum_results = opts.maximum_results,
-
- _started = false,
- }, self)
-
- obj._find = coroutine.wrap(function(finder, _, process_result, process_complete)
- local num_execution = 1
- local num_results = 0
-
- local results = setmetatable({}, {
- __newindex = function(t, k, v)
- rawset(t, k, v)
- process_result(v)
- end
- })
-
- local job_opts = finder:fn_command(_)
- if not job_opts then
- error(debug.traceback("expected `job_opts` from fn_command"))
- end
-
- local writer = nil
- 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 on_output = function(_, line)
- -- This will call the metamethod, process_result
- num_results = num_results + 1
- results[num_results] = finder.entry_maker(line)
- end
-
- local completed = false
- local job = Job:new {
- command = job_opts.command,
- args = job_opts.args,
- cwd = job_opts.cwd or finder.cwd,
-
- maximum_results = finder.maximum_results,
-
- writer = writer,
-
- enable_recording = false,
-
- on_stdout = on_output,
- on_stderr = on_output,
-
- on_exit = function()
- process_complete()
- completed = true
- end,
- }
-
- job:start()
-
- while true do
- finder, _, process_result, process_complete = coroutine.yield()
- num_execution = num_execution + 1
-
- local current_count = num_results
- for index = 1, current_count do
- process_result(results[index])
- end
-
- if completed then
- process_complete()
- end
- end
- end)
-
- return obj
-end
-
-function OneshotJobFinder:old_find(_, process_result, process_complete)
- local first_run = false
-
- if not self._started then
- first_run = true
-
- self._started = true
-
- end
-
- -- First time we get called, start on up that job.
- -- Every time after that, just use the results LUL
- if not first_run then
- return
- end
-end
-
-
-
---[[ =============================================================
-Static Finders
-
-A static finder has results that never change.
-They are passed in directly as a result.
--- ============================================================= ]]
-local StaticFinder = _callable_obj()
-
-function StaticFinder:new(opts)
- assert(opts, "Options are required. See documentation for usage")
-
- local input_results
- if vim.tbl_islist(opts) then
- input_results = opts
- else
- input_results = opts.results
- end
-
- local entry_maker = opts.entry_maker or make_entry.gen_from_string()
-
- assert(input_results)
- assert(input_results, "Results are required for static finder")
- assert(type(input_results) == 'table', "self.results must be a table")
-
- local results = {}
- for k, v in ipairs(input_results) do
- local entry = entry_maker(v)
-
- if entry then
- entry.index = k
- table.insert(results, entry)
- end
- end
-
- return setmetatable({ results = results }, self)
-end
-
-function StaticFinder:_find(_, process_result, process_complete)
- for _, v in ipairs(self.results) do
- process_result(v)
- end
-
- process_complete()
-end
-
-
--- local
-
-
--- Return a new Finder
--
-- Use at your own risk.
-- This opts dictionary is likely to change, but you are welcome to use it right now.
-- I will try not to change it needlessly, but I will change it sometimes and I won't feel bad.
finders._new = function(opts)
- if opts.results then
- print("finder.new is deprecated with `results`. You should use `finder.new_table`")
- return StaticFinder:new(opts)
- end
-
+ assert(not opts.results, "finder.new is deprecated with `results`. You should use `finder.new_table`")
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,
+ -- }
+
return JobFinder:new {
fn_command = function(_, prompt)
local command_list = command_generator(prompt)
@@ -298,18 +147,20 @@ finders.new_job = function(command_generator, entry_maker, maximum_results, cwd)
}
end
----@param command_list string[] Command list to execute.
----@param opts table
+--- 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
finders.new_oneshot_job = function(command_list, opts)
opts = opts or {}
- command_list = vim.deepcopy(command_list)
+ assert(not opts.results, "`results` should be used with finder.new_table")
+ command_list = vim.deepcopy(command_list)
local command = table.remove(command_list, 1)
- return OneshotJobFinder:new {
+ return async_oneshot_finder {
entry_maker = opts.entry_maker or make_entry.gen_from_string(),
cwd = opts.cwd,
@@ -331,7 +182,7 @@ end
-- results table, the results to run on
-- entry_maker function, the function to convert results to entries.
finders.new_table = function(t)
- return StaticFinder:new(t)
+ return async_static_finder(t)
end
return finders
diff --git a/lua/telescope/finders/async_job_finder.lua b/lua/telescope/finders/async_job_finder.lua
new file mode 100644
index 0000000..ee1b2c7
--- /dev/null
+++ b/lua/telescope/finders/async_job_finder.lua
@@ -0,0 +1,73 @@
+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 make_entry = require('telescope.make_entry')
+
+return function(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)
+ if command_list == nil then
+ return nil
+ end
+
+ local command = table.remove(command_list, 1)
+
+ return {
+ command = command,
+ args = command_list,
+ }
+ 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 return 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)
+ 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
diff --git a/lua/telescope/finders/async_oneshot_finder.lua b/lua/telescope/finders/async_oneshot_finder.lua
new file mode 100644
index 0000000..2345096
--- /dev/null
+++ b/lua/telescope/finders/async_oneshot_finder.lua
@@ -0,0 +1,81 @@
+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 make_entry = require('telescope.make_entry')
+
+local Job = require('plenary.job')
+
+return function(opts)
+ opts = opts or {}
+
+ local entry_maker = opts.entry_maker or make_entry.from_string
+ local cwd = opts.cwd
+ local fn_command = assert(opts.fn_command, "Must pass `fn_command`")
+
+ local results = {}
+ local num_results = 0
+
+ local job_started = false
+ local job_completed = false
+ return setmetatable({
+ close = function() results = {}; job_started = false end,
+ results = results,
+ }, {
+ __call = void(async(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
+
+ local job = Job:new {
+ command = job_opts.command,
+ args = job_opts.args,
+ cwd = job_opts.cwd or cwd,
+ maximum_results = opts.maximum_results,
+ writer = writer,
+ enable_recording = false,
+
+ 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,
+ }
+
+ job:start()
+ job_started = true
+ end
+
+ local current_count = num_results
+ for index = 1, current_count do
+ 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
diff --git a/lua/telescope/finders/async_static_finder.lua b/lua/telescope/finders/async_static_finder.lua
new file mode 100644
index 0000000..0756551
--- /dev/null
+++ b/lua/telescope/finders/async_static_finder.lua
@@ -0,0 +1,41 @@
+local async_lib = require('plenary.async_lib')
+local async = async_lib.async
+local await = async_lib.await
+local void = async_lib.void
+
+local make_entry = require('telescope.make_entry')
+
+return function(opts)
+ local input_results
+ if vim.tbl_islist(opts) then input_results = opts
+ else input_results = opts.results end
+
+ local entry_maker = opts.entry_maker or make_entry.gen_from_string()
+
+ local results = {}
+ for k, v in ipairs(input_results) do
+ local entry = entry_maker(v)
+
+ if entry then
+ entry.index = k
+ table.insert(results, entry)
+ end
+ end
+
+ return setmetatable({
+ results = results,
+ close = function() end,
+ }, {
+ __call = void(async(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())
+ end
+ end
+
+ process_complete()
+ end)),
+ })
+end
diff --git a/lua/telescope/log.lua b/lua/telescope/log.lua
index 9beabb1..c93472b 100644
--- a/lua/telescope/log.lua
+++ b/lua/telescope/log.lua
@@ -1,5 +1,6 @@
+local user = vim.loop.os_getenv("USER")
return require('plenary.log').new {
plugin = 'telescope',
- level = (vim.loop.os_getenv("USER") == 'tj' and 'debug') or 'warn',
+ level = ((user == 'tj' or user == 'tjdevries') and 'debug') or 'warn',
}
diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua
index 5ba0ca0..7e658c3 100644
--- a/lua/telescope/pickers.lua
+++ b/lua/telescope/pickers.lua
@@ -1,22 +1,28 @@
local a = vim.api
local popup = require('popup')
+local async_lib = require('plenary.async_lib')
+local async_util = async_lib.util
+
+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')
local debounce = require('telescope.debounce')
-local resolve = require('telescope.config.resolve')
local log = require('telescope.log')
local mappings = require('telescope.mappings')
local state = require('telescope.state')
local utils = require('telescope.utils')
-local layout_strategies = require('telescope.pickers.layout_strategies')
local entry_display = require('telescope.pickers.entry_display')
-local p_highlights = require('telescope.pickers.highlights')
+local p_highlighter = require('telescope.pickers.highlights')
local p_scroller = require('telescope.pickers.scroller')
+local p_window = require('telescope.pickers.window')
local EntryManager = require('telescope.entry_manager')
local MultiSelect = require('telescope.pickers.multi')
@@ -73,6 +79,7 @@ function Picker:new(opts)
cwd = opts.cwd,
+ _find_id = 0,
_completion_callbacks = {},
_multi = MultiSelect:new(),
@@ -85,7 +92,6 @@ function Picker:new(opts)
sorting_strategy = get_default(opts.sorting_strategy, config.values.sorting_strategy),
selection_strategy = get_default(opts.selection_strategy, config.values.selection_strategy),
- get_window_options = opts.get_window_options,
layout_strategy = layout_strategy,
layout_config = get_default(
opts.layout_config,
@@ -116,12 +122,15 @@ function Picker:new(opts)
preview_cutoff = get_default(opts.preview_cutoff, config.values.preview_cutoff),
}, self)
+ obj.get_window_options = opts.get_window_options or p_window.get_window_options
+
+ -- TODO: It's annoying that this is create and everything else is "new"
obj.scroller = p_scroller.create(
get_default(opts.scroll_strategy, config.values.scroll_strategy),
obj.sorting_strategy
)
- obj.highlighter = p_highlights.new(obj)
+ obj.highlighter = p_highlighter.new(obj)
if opts.on_complete then
for _, on_complete_item in ipairs(opts.on_complete) do
@@ -132,52 +141,8 @@ function Picker:new(opts)
return obj
end
-function Picker:_get_initial_window_options()
- local popup_border = resolve.win_option(self.window.border)
- local popup_borderchars = resolve.win_option(self.window.borderchars)
-
- local preview = {
- title = self.preview_title,
- border = popup_border.preview,
- borderchars = popup_borderchars.preview,
- enter = false,
- highlight = false
- }
-
- local results = {
- title = self.results_title,
- border = popup_border.results,
- borderchars = popup_borderchars.results,
- enter = false,
- }
-
- local prompt = {
- title = self.prompt_title,
- border = popup_border.prompt,
- borderchars = popup_borderchars.prompt,
- enter = true
- }
-
- return {
- preview = preview,
- results = results,
- prompt = prompt,
- }
-end
-
-function Picker:get_window_options(max_columns, max_lines)
- local layout_strategy = self.layout_strategy
- local getter = layout_strategies[layout_strategy]
-
- if not getter then
- error("Not a valid layout strategy: " .. layout_strategy)
- end
-
- return getter(self, max_columns, max_lines)
-end
-
--- Take a row and get an index.
---- @note: Rows are 0-indexed, and `index` is 1 indexed (table index)
+---@note: Rows are 0-indexed, and `index` is 1 indexed (table index)
---@param index number: The row being displayed
---@return number The row for the picker to display in
function Picker:get_row(index)
@@ -308,6 +273,13 @@ function Picker:can_select_row(row)
end
end
+function Picker:_next_find_id()
+ local find_id = self._find_id + 1
+ self._find_id = find_id
+
+ return find_id
+end
+
function Picker:find()
self:close_existing_pickers()
self:reset_selection()
@@ -317,7 +289,7 @@ function Picker:find()
self.original_win_id = a.nvim_get_current_win()
-- User autocmd run it before create Telescope window
- vim.cmd'do User TelescopeFindPre'
+ vim.cmd [[doautocmd User TelescopeFindPre]]
-- Create three windows:
-- 1. Prompt window
@@ -393,66 +365,70 @@ function Picker:find()
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
- self.request_number = 0
- local on_lines = function(_, _, _, first_line, last_line)
- self.request_number = self.request_number + 1
- self:_reset_track()
+ local tx, rx = channel.mpsc()
+ self.__on_lines = tx.send
- if not vim.api.nvim_buf_is_valid(prompt_bufnr) then
- log.debug("ON_LINES: Invalid prompt_bufnr", prompt_bufnr)
- return
- end
+ local main_loop = async(function()
+ while true do
+ await(async_lib.scheduler())
- if not first_line then first_line = 0 end
- if not last_line then last_line = 1 end
+ local _, _, _, first_line, last_line = await(rx.last())
+ self:_reset_track()
- if first_line > 0 or last_line > 1 then
- log.debug("ON_LINES: Bad range", first_line, last_line)
- return
- end
+ if not vim.api.nvim_buf_is_valid(prompt_bufnr) then
+ log.debug("ON_LINES: Invalid prompt_bufnr", prompt_bufnr)
+ return
+ end
- local original_prompt = self:_get_prompt()
- local on_input_result = self._on_input_filter_cb(original_prompt) or {}
+ if not first_line then first_line = 0 end
+ if not last_line then last_line = 1 end
- local prompt = on_input_result.prompt or original_prompt
- local finder = on_input_result.updated_finder
+ if first_line > 0 or last_line > 1 then
+ log.debug("ON_LINES: Bad range", first_line, last_line)
+ return
+ end
- if finder then
- self.finder:close()
- self.finder = finder
- end
+ local original_prompt = self:_get_prompt()
+ local on_input_result = self._on_input_filter_cb(original_prompt) or {}
- if self.sorter then
- self.sorter:_start(prompt)
- end
+ local prompt = on_input_result.prompt or original_prompt
+ local finder = on_input_result.updated_finder
- -- TODO: Entry manager should have a "bulk" setter. This can prevent a lot of redraws from display
- self.manager = EntryManager:new(self.max_results, self.entry_adder, self.stats, self.request_number)
+ if finder then
+ self.finder:close()
+ self.finder = finder
+ end
- local process_result = self:get_result_processor(prompt, debounced_status)
- local process_complete = self:get_result_completor(self.results_bufnr, prompt, status_updater)
+ if self.sorter then
+ self.sorter:_start(prompt)
+ end
- local ok, msg = pcall(function()
- self.finder(prompt, process_result, vim.schedule_wrap(process_complete))
- end)
+ -- TODO: Entry manager should have a "bulk" setter. This can prevent a lot of redraws from display
+ self.manager = EntryManager:new(self.max_results, self.entry_adder, self.stats)
- if not ok then
- log.warn("Failed with msg: ", msg)
- end
- end
+ 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)
- self.__on_lines = on_lines
+ local ok, msg = pcall(function()
+ self.finder(prompt, process_result, vim.schedule_wrap(process_complete))
+ end)
+
+ if not ok then
+ log.warn("Failed with msg: ", msg)
+ end
+ end
+ end)
- on_lines(nil, nil, nil, 0, 1)
+ -- on_lines(nil, nil, nil, 0, 1)
status_updater()
-- Register attach
vim.api.nvim_buf_attach(prompt_bufnr, false, {
- on_lines = on_lines,
+ on_lines = tx.send,
on_detach = function()
- on_lines = nil
-
-- TODO: Can we add a "cleanup" / "teardown" function that completely removes these.
self.finder = nil
self.previewer = nil
@@ -466,6 +442,8 @@ function Picker:find()
end,
})
+ async_lib.run(main_loop())
+
-- 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)]],
@@ -659,7 +637,8 @@ function Picker:refresh(finder, opts)
if opts.reset_prompt then self:reset_prompt() end
self.finder:close()
- self.finder = finder
+ if finder then self.finder = finder end
+
self.__on_lines(nil, nil, nil, 0, 1)
end
@@ -695,6 +674,8 @@ function Picker:set_selection(row)
local entry = self.manager:get_entry(self:get_index(row))
state.set_global_key("selected_entry", entry)
+ if not entry then return end
+
-- TODO: Probably should figure out what the rows are that made this happen...
-- Probably something with setting a row that's too high for this?
-- Not sure.
@@ -775,6 +756,8 @@ function Picker:refresh_previewer()
end
function Picker:entry_adder(index, entry, _, insert)
+ if not entry then return end
+
local row = self:get_row(index)
-- If it's less than 0, then we don't need to show it at all.
@@ -799,18 +782,14 @@ function Picker:entry_adder(index, entry, _, insert)
-- TODO: Don't need to schedule this if we schedule the adder.
local offset = insert and 0 or 1
- local scheduled_request = self.request_number
vim.schedule(function()
if not vim.api.nvim_buf_is_valid(self.results_bufnr) then
log.debug("ON_ENTRY: Invalid buffer")
return
end
- if self.request_number ~= scheduled_request then
- log.trace("Cancelling request number:", self.request_number, " // ", scheduled_request)
- return
- end
-
+ -- TODO: Does this every get called?
+ -- local line_count = vim.api.nvim_win_get_height(self.results_win)
local line_count = vim.api.nvim_buf_line_count(self.results_bufnr)
if row > line_count then
return
@@ -850,11 +829,6 @@ function Picker:_reset_track()
self.stats.filtered = 0
self.stats.highlights = 0
-
- self.stats._sort_time = 0
- self.stats._add_time = 0
- self.stats._highlight_time = 0
- self.stats._start = vim.loop.hrtime()
end
function Picker:_track(key, func, ...)
@@ -914,8 +888,7 @@ function Picker:get_status_updater(prompt_win, prompt_bufnr)
return
end
- local expected_prompt_len = #self.prompt_prefix + 1
- local prompt_len = #current_prompt < expected_prompt_len and expected_prompt_len or #current_prompt
+ local prompt_len = #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)
@@ -927,68 +900,61 @@ function Picker:get_status_updater(prompt_win, prompt_bufnr)
{}
)
+ -- TODO: Wait for bfredl
+ -- vim.api.nvim_buf_set_extmark(prompt_bufnr, ns_telescope_prompt, 0, 0, {
+ -- end_line = 0,
+ -- -- end_col = start_column + #text,
+ -- virt_text = { { text, "NonText", } },
+ -- virt_text_pos = "eol",
+ -- })
+
self:_increment("status")
end
end
-function Picker:get_result_processor(prompt, status_updater)
- return function(entry)
- if self.closed or self:is_done() then return 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()
+ end
- self:_increment("processed")
+ local cb_filter = function(_)
+ self:_increment("filtered")
+ end
- if not entry then
- log.debug("No entry...")
- return
+ return function(entry)
+ if find_id ~= self._find_id
+ or self.closed
+ or self:is_done() then
+ return true
end
- -- TODO: Should we even have valid?
- if entry.valid == false then
+ self:_increment("processed")
+
+ if not entry or entry.valid == false then
return
end
+ -- TODO: Probably should asyncify this / cache this / do something because this probably takes
+ -- a ton of time on large results.
log.trace("Processing result... ", entry)
-
for _, v in ipairs(self.file_ignore_patterns or {}) do
local file = type(entry.value) == 'string' and entry.value or entry.filename
if file then
if string.find(file, v) then
- log.debug("SKIPPING", entry.value, "because", v)
+ log.trace("SKIPPING", entry.value, "because", v)
self:_decrement("processed")
return
end
end
end
- local sort_ok
- local sort_score = 0
- if self.sorter then
- sort_ok, sort_score = self:_track("_sort_time", pcall, self.sorter.score, self.sorter, prompt, entry)
-
- if not sort_ok then
- log.warn("Sorting failed with:", prompt, entry, sort_score)
- return
- end
-
- if entry.ignore_count ~= nil and entry.ignore_count == true then
- self:_decrement("processed")
- end
-
- if sort_score == -1 then
- self:_increment("filtered")
- log.trace("Filtering out result: ", entry)
- return
- end
- end
-
- self:_track("_add_time", self.manager.add_entry, self.manager, self, sort_score, entry)
-
- status_updater()
+ self.sorter:score(prompt, entry, cb_add, cb_filter)
end
end
-function Picker:get_result_completor(results_bufnr, prompt, status_updater)
+function Picker:get_result_completor(results_bufnr, find_id, prompt, status_updater)
return function()
if self.closed == true or self:is_done() then return end
@@ -1030,17 +996,6 @@ function Picker:get_result_completor(results_bufnr, prompt, status_updater)
self:clear_extra_rows(results_bufnr)
self:highlight_displayed_rows(results_bufnr, prompt)
- -- TODO: Cleanup.
- self.stats._done = vim.loop.hrtime()
- self.stats.time = (self.stats._done - self.stats._start) / 1e9
-
- local function do_times(key)
- self.stats[key] = self.stats["_" .. key] / 1e9
- end
-
- do_times("sort_time")
- do_times("add_time")
- do_times("highlight_time")
self:_on_complete()
diff --git a/lua/telescope/pickers/layout_strategies.lua b/lua/telescope/pickers/layout_strategies.lua
index b8d9aea..b4c9fda 100644
--- a/lua/telescope/pickers/layout_strategies.lua
+++ b/lua/telescope/pickers/layout_strategies.lua
@@ -61,6 +61,40 @@
local config = require('telescope.config')
local resolve = require("telescope.config.resolve")
+local function get_initial_window_options(picker)
+ local popup_border = resolve.win_option(picker.window.border)
+ local popup_borderchars = resolve.win_option(picker.window.borderchars)
+
+ local preview = {
+ title = picker.preview_title,
+ border = popup_border.preview,
+ borderchars = popup_borderchars.preview,
+ enter = false,
+ highlight = false
+ }
+
+ local results = {
+ title = picker.results_title,
+ border = popup_border.results,
+ borderchars = popup_borderchars.results,
+ enter = false,
+ }
+
+ local prompt = {
+ title = picker.prompt_title,
+ border = popup_border.prompt,
+ borderchars = popup_borderchars.prompt,
+ enter = true
+ }
+
+ return {
+ preview = preview,
+ results = results,
+ prompt = prompt,
+ }
+end
+
+
-- Check if there are any borders. Right now it's a little raw as
-- there are a few things that contribute to the border
local is_borderless = function(opts)
@@ -105,7 +139,7 @@ layout_strategies.horizontal = function(self, max_columns, max_lines)
scroll_speed = "The speed when scrolling through the previewer",
})
- local initial_options = self:_get_initial_window_options()
+ local initial_options = get_initial_window_options(self)
local preview = initial_options.preview
local results = initial_options.results
local prompt = initial_options.prompt
@@ -203,7 +237,7 @@ end
--- +--------------+
--- </pre>
layout_strategies.center = function(self, columns, lines)
- local initial_options = self:_get_initial_window_options()
+ local initial_options = get_initial_window_options(self)
local preview = initial_options.preview
local results = initial_options.results
local prompt = initial_options.prompt
@@ -273,7 +307,7 @@ layout_strategies.vertical = function(self, max_columns, max_lines)
scroll_speed = "The speed when scrolling through the previewer",
})
- local initial_options = self:_get_initial_window_options()
+ local initial_options = get_initial_window_options(self)
local preview = initial_options.preview
local results = initial_options.results
local prompt = initial_options.prompt
diff --git a/lua/telescope/pickers/window.lua b/lua/telescope/pickers/window.lua
new file mode 100644
index 0000000..76c1fe0
--- /dev/null
+++ b/lua/telescope/pickers/window.lua
@@ -0,0 +1,17 @@
+local p_layouts = require('telescope.pickers.layout_strategies')
+
+local p_window = {}
+
+function p_window.get_window_options(picker, max_columns, max_lines)
+ local layout_strategy = picker.layout_strategy
+ local getter = p_layouts[layout_strategy]
+
+ if not getter then
+ error("Not a valid layout strategy: " .. layout_strategy)
+ end
+
+ return getter(picker, max_columns, max_lines)
+end
+
+
+return p_window
diff --git a/lua/telescope/sorters.lua b/lua/telescope/sorters.lua
index 5ac7086..4147f59 100644
--- a/lua/telescope/sorters.lua
+++ b/lua/telescope/sorters.lua
@@ -32,12 +32,17 @@ 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.
---- @field scoring_function function Function that has the interface:
--- (sorter, prompt, line): number
+---@field scoring_function function: Function that has the interface: (sorter, prompt, line): number
+---@field tags table: Unique tags collected at filtering for tag completion
+---@field filter_function function: Function that can filter results
+---@field highlighter function: Highlights results to display them pretty
+---@field discard boolean: Whether this is a discardable style sorter or not.
+---@field score function: Override the score function if desired.
function Sorter:new(opts)
opts = opts or {}
return setmetatable({
+ score = opts.score,
state = {},
tags = opts.tags,
filter_function = opts.filter_function,
@@ -77,13 +82,12 @@ end
-- TODO: Consider doing something that makes it so we can skip the filter checks
-- if we're not discarding. Also, that means we don't have to check otherwise as well :)
-function Sorter:score(prompt, entry)
- if not entry or not entry.ordinal then return -1 end
+function Sorter:score(prompt, entry, cb_add, cb_filter)
+ if not entry or not entry.ordinal then return end
local ordinal = entry.ordinal
-
if self:_was_discarded(prompt, ordinal) then
- return FILTERED
+ return cb_filter(entry)
end
local filter_score
@@ -92,14 +96,21 @@ function Sorter:score(prompt, entry)
filter_score, prompt = self:filter_function(prompt, entry)
end
- local score = (filter_score == FILTERED and FILTERED or
- self:scoring_function(prompt or "", ordinal, entry))
+ if filter_score == FILTERED then
+ return cb_filter(entry)
+ end
+ local score = self:scoring_function(prompt or "", ordinal, entry)
if score == FILTERED then
self:_mark_discarded(prompt, ordinal)
+ return cb_filter(entry)
end
- return score
+ if cb_add then
+ return cb_add(score, entry)
+ else
+ return score
+ end
end
function Sorter:_was_discarded(prompt, ordinal)
diff --git a/lua/tests/automated/telescope_spec.lua b/lua/tests/automated/telescope_spec.lua
index 0f7bc85..6ad09d7 100644
--- a/lua/tests/automated/telescope_spec.lua
+++ b/lua/tests/automated/telescope_spec.lua
@@ -100,7 +100,12 @@ describe('telescope', function()
describe('fzy', function()
local sorter = require'telescope.sorters'.get_fzy_sorter()
local function score(prompt, line)
- return sorter:score(prompt, {ordinal = line})
+ return sorter:score(
+ prompt,
+ {ordinal = line},
+ function(val) return val end,
+ function() return -1 end
+ )
end
describe("matches", function()