feat: allow caching and resuming picker (#1051)

* expose `cache_picker` in telescope.setup to configure caching, see `:h telescope.defaults.cache_picker`
* add builtin.resume and builtin.pickers picker
This commit is contained in:
fdschmidt93
2021-09-01 18:17:18 +02:00
committed by GitHub
parent 67bc1dcdd6
commit 5d37c3ea08
11 changed files with 444 additions and 31 deletions

View File

@@ -439,6 +439,8 @@ Built-in functions. Ready to be bound to any key you like. :smile:
| `builtin.highlights` | Lists all available highlights | | `builtin.highlights` | Lists all available highlights |
| `builtin.current_buffer_fuzzy_find` | Live fuzzy search inside of the currently open buffer | | `builtin.current_buffer_fuzzy_find` | Live fuzzy search inside of the currently open buffer |
| `builtin.current_buffer_tags` | Lists all of the tags for the currently open buffer, with a preview | | `builtin.current_buffer_tags` | Lists all of the tags for the currently open buffer, with a preview |
| `builtin.resume` | Lists the results incl. multi-selections of the previous picker |
| `builtin.pickers` | Lists the previous pickers incl. multi-selections (see `:h telescope.defaults.cache_picker`) |
### Neovim LSP Pickers ### Neovim LSP Pickers

View File

@@ -25,6 +25,28 @@ telescope.setup({opts}) *telescope.setup()*
Default: true Default: true
*telescope.defaults.cache_picker*
cache_picker: ~
This field handles the configuration for picker caching.
By default it is a table, with default values (more below).
To disable caching, set it to false.
Caching preserves all previous multi selections and results and
therefore may result in slowdown or increased RAM occupation
if too many pickers (`cache_picker.num_pickers`) or entries
('cache_picker.limit_entries`) are cached.
Fields:
- num_pickers: The number of pickers to be cached.
Set to -1 to preserve all pickers of your session.
If passed to a picker, the cached pickers with
indices larger than `cache_picker.num_pickers` will
be cleared.
Default: 1
- limit_entries: The amount of entries that will be written in the
Default: 1000
*telescope.defaults.default_mappings* *telescope.defaults.default_mappings*
default_mappings: ~ default_mappings: ~
Not recommended to use except for advanced users. Not recommended to use except for advanced users.
@@ -367,8 +389,8 @@ builtin.live_grep({opts}) *builtin.live_grep()*
{opts} (table) options to pass to the picker {opts} (table) options to pass to the picker
Fields: ~ Fields: ~
{cwd} (string) directory path to search from (default {cwd} (string) root dir to search from (default is cwd,
is cwd, use utils.buffer_dir() to search use utils.buffer_dir() to search
relative to open buffer) relative to open buffer)
{grep_open_files} (boolean) if true, restrict search to open files {grep_open_files} (boolean) if true, restrict search to open files
only, mutually exclusive with only, mutually exclusive with
@@ -388,8 +410,8 @@ builtin.grep_string({opts}) *builtin.grep_string()*
{opts} (table) options to pass to the picker {opts} (table) options to pass to the picker
Fields: ~ Fields: ~
{cwd} (string) directory path to search from (default {cwd} (string) root dir to search from (default is cwd,
is cwd, use utils.buffer_dir() to search use utils.buffer_dir() to search
relative to open buffer) relative to open buffer)
{search} (string) the query to search {search} (string) the query to search
{search_dirs} (table) directory/directories to search in {search_dirs} (table) directory/directories to search in
@@ -408,9 +430,9 @@ builtin.find_files({opts}) *builtin.find_files()*
{opts} (table) options to pass to the picker {opts} (table) options to pass to the picker
Fields: ~ Fields: ~
{cwd} (string) directory path to search from (default is {cwd} (string) root dir to search from (default is cwd, use
cwd, use utils.buffer_dir() to search utils.buffer_dir() to search relative to
relative to open buffer) open buffer)
{find_command} (table) command line arguments for `find_files` to {find_command} (table) command line arguments for `find_files` to
use for the search, overrides default config use for the search, overrides default config
{follow} (boolean) if true, follows symlinks (i.e. uses `-L` {follow} (boolean) if true, follows symlinks (i.e. uses `-L`
@@ -446,8 +468,8 @@ builtin.file_browser({opts}) *builtin.file_browser()*
{opts} (table) options to pass to the picker {opts} (table) options to pass to the picker
Fields: ~ Fields: ~
{cwd} (string) directory path to browse (default is cwd, use {cwd} (string) root dir to browse from (default is cwd, use
utils.buffer_dir() to browse relative to open utils.buffer_dir() to search relative to open
buffer) buffer)
{depth} (number) file tree depth to display (default is 1) {depth} (number) file tree depth to display (default is 1)
{dir_icon} (string) change the icon for a directory. default:  {dir_icon} (string) change the icon for a directory. default: 
@@ -679,6 +701,35 @@ builtin.search_history({opts}) *builtin.search_history()*
{opts} (table) options to pass to the picker {opts} (table) options to pass to the picker
builtin.resume({opts}) *builtin.resume()*
Opens the previous picker in the identical state (incl. multi selections)
- Notes:
- Requires `cache_picker` in setup or when having invoked pickers, see
|telescope.defaults.cache_picker|
Parameters: ~
{opts} (table) options to pass to the picker
Fields: ~
{cache_index} (number) what picker to resume, where 1 denotes most
recent (default 1)
builtin.pickers({opts}) *builtin.pickers()*
Opens a picker over previously cached pickers in there preserved states
(incl. multi selections)
- Default keymaps:
- `<C-x>`: delete the selected cached picker
- Notes:
- Requires `cache_picker` in setup or when having invoked pickers, see
|telescope.defaults.cache_picker|
Parameters: ~
{opts} (table) options to pass to the picker
builtin.vim_options({opts}) *builtin.vim_options()* builtin.vim_options({opts}) *builtin.vim_options()*
Lists vim options, allows you to edit the current value on `<cr>` Lists vim options, allows you to edit the current value on `<cr>`
@@ -1582,6 +1633,16 @@ actions.cycle_previewers_prev({prompt_bufnr})*actions.cycle_previewers_prev()*
{prompt_bufnr} (number) The prompt bufnr {prompt_bufnr} (number) The prompt bufnr
actions.remove_selected_picker({prompt_bufnr})*actions.remove_selected_picker()*
Removes the selected picker in |builtin.pickers|.
This action is not mapped by default and only intended for
|builtin.pickers|.
Parameters: ~
{prompt_bufnr} (number) The prompt bufnr
================================================================================ ================================================================================
*telescope.actions.state* *telescope.actions.state*

View File

@@ -832,6 +832,21 @@ actions.cycle_previewers_prev = function(prompt_bufnr)
actions.get_current_picker(prompt_bufnr):cycle_previewers(-1) actions.get_current_picker(prompt_bufnr):cycle_previewers(-1)
end end
--- Removes the selected picker in |builtin.pickers|.<br>
--- This action is not mapped by default and only intended for |builtin.pickers|.
---@param prompt_bufnr number: The prompt bufnr
actions.remove_selected_picker = function(prompt_bufnr)
local current_picker = action_state.get_current_picker(prompt_bufnr)
local selection_index = current_picker:get_index(current_picker:get_selection_row())
local cached_pickers = state.get_global_key "cached_pickers"
current_picker:delete_selection(function()
table.remove(cached_pickers, selection_index)
end)
if #cached_pickers == 0 then
actions.close(prompt_bufnr)
end
end
-- ================================================== -- ==================================================
-- Transforms modules and sets the corect metatables. -- Transforms modules and sets the corect metatables.
-- ================================================== -- ==================================================

View File

@@ -215,4 +215,41 @@ function LinkedList:ipairs()
end end
end end
function LinkedList:truncate(max_results)
if max_results >= self.size then
return
end
local current_node
if max_results < self.size - max_results then
local index = 1
current_node = self.head
while index < max_results do
local node = current_node
if not node.next then
break
end
current_node = current_node.next
index = index + 1
end
self.size = max_results
else
current_node = self.tail
while self.size > max_results do
if current_node.prev == nil then
break
end
current_node = current_node.prev
self.size = self.size - 1
end
end
self.tail = current_node
self.tail.next = nil
if max_results < self.track_at then
self.track_at = max_results
self.tracked = current_node.item
self._tracked_node = current_node
end
end
return LinkedList return LinkedList

View File

@@ -68,7 +68,7 @@ local builtin = {}
--- Search for a string and get results live as you type (respecting .gitignore) --- Search for a string and get results live as you type (respecting .gitignore)
---@param opts table: options to pass to the picker ---@param opts table: options to pass to the picker
---@field cwd string: directory path to search from (default is cwd, use utils.buffer_dir() to search relative to open buffer) ---@field cwd string: root dir to search from (default is cwd, use utils.buffer_dir() to search relative to open buffer)
---@field grep_open_files boolean: if true, restrict search to open files only, mutually exclusive with `search_dirs` ---@field grep_open_files boolean: if true, restrict search to open files only, mutually exclusive with `search_dirs`
---@field search_dirs table: directory/directories to search in, mutually exclusive with `grep_open_files` ---@field search_dirs table: directory/directories to search in, mutually exclusive with `grep_open_files`
---@field additional_args function: function(opts) which returns a table of additional arguments to be passed on ---@field additional_args function: function(opts) which returns a table of additional arguments to be passed on
@@ -76,7 +76,7 @@ builtin.live_grep = require("telescope.builtin.files").live_grep
--- Searches for the string under your cursor in your current working directory --- Searches for the string under your cursor in your current working directory
---@param opts table: options to pass to the picker ---@param opts table: options to pass to the picker
---@field cwd string: directory path to search from (default is cwd, use utils.buffer_dir() to search relative to open buffer) ---@field cwd string: root dir to search from (default is cwd, use utils.buffer_dir() to search relative to open buffer)
---@field search string: the query to search ---@field search string: the query to search
---@field search_dirs table: directory/directories to search in ---@field search_dirs table: directory/directories to search in
---@field use_regex boolean: if true, special characters won't be escaped, allows for using regex (default is false) ---@field use_regex boolean: if true, special characters won't be escaped, allows for using regex (default is false)
@@ -85,7 +85,7 @@ builtin.grep_string = require("telescope.builtin.files").grep_string
--- Search for files (respecting .gitignore) --- Search for files (respecting .gitignore)
---@param opts table: options to pass to the picker ---@param opts table: options to pass to the picker
---@field cwd string: directory path to search from (default is cwd, use utils.buffer_dir() to search relative to open buffer) ---@field cwd string: root dir to search from (default is cwd, use utils.buffer_dir() to search relative to open buffer)
---@field find_command table: command line arguments for `find_files` to use for the search, overrides default config ---@field find_command table: command line arguments for `find_files` to use for the search, overrides default config
---@field follow boolean: if true, follows symlinks (i.e. uses `-L` flag for the `find` command) ---@field follow boolean: if true, follows symlinks (i.e. uses `-L` flag for the `find` command)
---@field hidden boolean: determines whether to show hidden files or not (default is false) ---@field hidden boolean: determines whether to show hidden files or not (default is false)
@@ -105,7 +105,7 @@ builtin.fd = builtin.find_files
--- create the file `init.lua` inside of `lua/telescope` and will create the necessary folders (similar to how --- create the file `init.lua` inside of `lua/telescope` and will create the necessary folders (similar to how
--- `mkdir -p` would work) if they do not already exist --- `mkdir -p` would work) if they do not already exist
---@param opts table: options to pass to the picker ---@param opts table: options to pass to the picker
---@field cwd string: directory path to browse (default is cwd, use utils.buffer_dir() to browse relative to open buffer) ---@field cwd string: root dir to browse from (default is cwd, use utils.buffer_dir() to search relative to open buffer)
---@field depth number: file tree depth to display (default is 1) ---@field depth number: file tree depth to display (default is 1)
---@field dir_icon string: change the icon for a directory. default:  ---@field dir_icon string: change the icon for a directory. default: 
---@field hidden boolean: determines whether to show hidden files or not (default is false) ---@field hidden boolean: determines whether to show hidden files or not (default is false)
@@ -243,6 +243,21 @@ builtin.command_history = require("telescope.builtin.internal").command_history
---@param opts table: options to pass to the picker ---@param opts table: options to pass to the picker
builtin.search_history = require("telescope.builtin.internal").search_history builtin.search_history = require("telescope.builtin.internal").search_history
--- Opens the previous picker in the identical state (incl. multi selections)
--- - Notes:
--- - Requires `cache_picker` in setup or when having invoked pickers, see |telescope.defaults.cache_picker|
---@param opts table: options to pass to the picker
---@field cache_index number: what picker to resume, where 1 denotes most recent (default 1)
builtin.resume = require("telescope.builtin.internal").resume
--- Opens a picker over previously cached pickers in there preserved states (incl. multi selections)
--- - Default keymaps:
--- - `<C-x>`: delete the selected cached picker
--- - Notes:
--- - Requires `cache_picker` in setup or when having invoked pickers, see |telescope.defaults.cache_picker|
---@param opts table: options to pass to the picker
builtin.pickers = require("telescope.builtin.internal").pickers
--- Lists vim options, allows you to edit the current value on `<cr>` --- Lists vim options, allows you to edit the current value on `<cr>`
---@param opts table: options to pass to the picker ---@param opts table: options to pass to the picker
builtin.vim_options = require("telescope.builtin.internal").vim_options builtin.vim_options = require("telescope.builtin.internal").vim_options

View File

@@ -6,7 +6,9 @@ local make_entry = require "telescope.make_entry"
local Path = require "plenary.path" local Path = require "plenary.path"
local pickers = require "telescope.pickers" local pickers = require "telescope.pickers"
local previewers = require "telescope.previewers" local previewers = require "telescope.previewers"
local p_window = require "telescope.pickers.window"
local sorters = require "telescope.sorters" local sorters = require "telescope.sorters"
local state = require "telescope.state"
local utils = require "telescope.utils" local utils = require "telescope.utils"
local conf = require("telescope.config").values local conf = require("telescope.config").values
@@ -71,6 +73,80 @@ internal.builtin = function(opts)
}):find() }):find()
end end
internal.resume = function(opts)
opts = opts or {}
opts.cache_index = vim.F.if_nil(opts.cache_index, 1)
local cached_pickers = state.get_global_key "cached_pickers"
if cached_pickers == nil or vim.tbl_isempty(cached_pickers) then
print "No picker(s) cached."
return
end
local picker = cached_pickers[opts.cache_index]
if picker == nil then
print("Index too large as there are only %s pickers cached", #cached_pickers)
return
end
-- reset layout strategy and get_window_options if default as only one is valid
-- and otherwise unclear which was actually set
if picker.layout_strategy == conf.layout_strategy then
picker.layout_strategy = nil
end
if picker.get_window_options == p_window.get_window_options then
picker.get_window_options = nil
end
picker.cache_picker.index = opts.cache_index
-- avoid partial `opts.cache_picker` at picker creation
if opts.cache_picker ~= false then
picker.cache_picker = vim.tbl_extend("keep", opts.cache_picker or {}, picker.cache_picker)
else
picker.cache_picker.disabled = true
end
opts.cache_picker = nil
pickers.new(opts, picker):find()
end
internal.pickers = function(opts)
local cached_pickers = state.get_global_key "cached_pickers"
if cached_pickers == nil or vim.tbl_isempty(cached_pickers) then
print "No picker(s) cached."
return
end
opts = opts or {}
-- clear cache picker for immediate pickers.new and pass option to resumed picker
if opts.cache_picker ~= nil then
opts._cache_picker = opts.cache_picker
opts.cache_picker = nil
end
pickers.new(opts, {
prompt_title = "Pickers",
finder = finders.new_table {
results = cached_pickers,
entry_maker = make_entry.gen_from_picker(opts),
},
previewer = previewers.pickers.new(opts),
sorter = conf.generic_sorter(opts),
cache_picker = false,
attach_mappings = function(_, map)
actions.select_default:replace(function(prompt_bufnr)
local current_picker = action_state.get_current_picker(prompt_bufnr)
local selection_index = current_picker:get_index(current_picker:get_selection_row())
actions._close(prompt_bufnr, cached_pickers[selection_index].initial_mode == "insert")
opts.cache_picker = opts._cache_picker
opts["cache_index"] = selection_index
internal.resume(opts)
end)
map("i", "<C-x>", actions.remove_selected_picker)
map("n", "<C-x>", actions.remove_selected_picker)
return true
end,
}):find()
end
internal.planets = function(opts) internal.planets = function(opts)
local show_pluto = opts.show_pluto or false local show_pluto = opts.show_pluto or false

View File

@@ -46,11 +46,22 @@ local smarter_depth_2_extend = function(priority, base)
return result return result
end end
local resolve_table_opts = function(priority, base)
if priority == false or (priority == nil and base == false) then
return false
end
if priority == nil and type(base) == "table" then
return base
end
return smarter_depth_2_extend(priority, base)
end
-- TODO: Add other major configuration points here. -- TODO: Add other major configuration points here.
-- selection_strategy -- selection_strategy
local config = {} local config = {}
config.smarter_depth_2_extend = smarter_depth_2_extend config.smarter_depth_2_extend = smarter_depth_2_extend
config.resolve_table_opts = resolve_table_opts
config.values = _TelescopeConfigurationValues config.values = _TelescopeConfigurationValues
config.descriptions = {} config.descriptions = {}
@@ -286,6 +297,33 @@ local telescope_defaults = {
]], ]],
}, },
cache_picker = {
{
num_pickers = 1,
limit_entries = 1000,
},
[[
This field handles the configuration for picker caching.
By default it is a table, with default values (more below).
To disable caching, set it to false.
Caching preserves all previous multi selections and results and
therefore may result in slowdown or increased RAM occupation
if too many pickers (`cache_picker.num_pickers`) or entries
('cache_picker.limit_entries`) are cached.
Fields:
- num_pickers: The number of pickers to be cached.
Set to -1 to preserve all pickers of your session.
If passed to a picker, the cached pickers with
indices larger than `cache_picker.num_pickers` will
be cleared.
Default: 1
- limit_entries: The amount of entries that will be written in the
Default: 1000
]],
},
-- Builtin configuration -- Builtin configuration
-- List that will be executed. -- List that will be executed.
@@ -416,7 +454,7 @@ function config.set_defaults(user_defaults, tele_defaults)
vim.tbl_deep_extend("keep", if_nil(config.values[name], {}), if_nil(default_val, {})) vim.tbl_deep_extend("keep", if_nil(config.values[name], {}), if_nil(default_val, {}))
) )
end end
if name == "history" then if name == "history" or name == "cache_picker" then
if user_defaults[name] == false or config.values[name] == false then if user_defaults[name] == false or config.values[name] == false then
return false return false
end end

View File

@@ -662,6 +662,32 @@ function make_entry.gen_from_highlights()
end end
end end
function make_entry.gen_from_picker(opts)
local displayer = entry_display.create {
separator = " ",
items = {
{ width = 30 },
{ remaining = true },
},
}
local make_display = function(entry)
return displayer {
entry.value.prompt_title,
entry.value.default_text,
}
end
return function(entry)
return {
value = entry,
text = entry.prompt_title,
ordinal = string.format("%s %s", entry.prompt_title, utils.get_default(entry.default_text, "")),
display = make_display,
}
end
end
function make_entry.gen_from_buffer_lines(opts) function make_entry.gen_from_buffer_lines(opts)
local displayer = entry_display.create { local displayer = entry_display.create {
separator = "", separator = "",

View File

@@ -85,7 +85,11 @@ function Picker:new(opts)
_find_id = 0, _find_id = 0,
_completion_callbacks = {}, _completion_callbacks = {},
_multi = MultiSelect:new(), manager = (type(opts.manager) == "table" and getmetatable(opts.manger) == getmetatable(EntryManager))
and opts.manager,
_multi = (type(opts._multi) == "table" and getmetatable(opts._multi) == getmetatable(MultiSelect:new()))
and opts._multi
or MultiSelect:new(),
track = get_default(opts.track, false), track = get_default(opts.track, false),
stats = {}, stats = {},
@@ -104,6 +108,8 @@ function Picker:new(opts)
border = get_default(opts.border, config.values.border), border = get_default(opts.border, config.values.border),
borderchars = get_default(opts.borderchars, config.values.borderchars), borderchars = get_default(opts.borderchars, config.values.borderchars),
}, },
cache_picker = config.resolve_table_opts(opts.cache_picker, vim.deepcopy(config.values.cache_picker)),
}, self) }, self)
obj.get_window_options = opts.get_window_options or p_window.get_window_options obj.get_window_options = opts.get_window_options or p_window.get_window_options
@@ -332,6 +338,7 @@ function Picker:find()
if prompt_border_win then if prompt_border_win then
vim.api.nvim_win_set_option(prompt_border_win, "winhl", "Normal:TelescopePromptBorder") vim.api.nvim_win_set_option(prompt_border_win, "winhl", "Normal:TelescopePromptBorder")
end end
self.prompt_bufnr = prompt_bufnr
-- Prompt prefix -- Prompt prefix
local prompt_prefix = self.prompt_prefix local prompt_prefix = self.prompt_prefix
@@ -416,23 +423,47 @@ function Picker:find()
self.finder = new_finder self.finder = new_finder
end end
self.sorter:_start(prompt) -- 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 self.cache_picker == false or not (self.cache_picker.is_cached == true) then
self.sorter:_start(prompt)
self.manager = EntryManager:new(self.max_results, self.entry_adder, self.stats)
local process_result = self:get_result_processor(find_id, prompt, debounced_status) 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 process_complete = self:get_result_completor(self.results_bufnr, find_id, prompt, status_updater)
local ok, msg = pcall(function() local ok, msg = pcall(function()
self.finder(prompt, process_result, process_complete) self.finder(prompt, process_result, process_complete)
end) end)
if not ok then if not ok then
log.warn("Finder failed with msg: ", msg) log.warn("Finder failed with msg: ", msg)
end end
local diff_time = (vim.loop.hrtime() - start_time) / 1e6 local diff_time = (vim.loop.hrtime() - start_time) / 1e6
if self.debounce and diff_time < self.debounce then if self.debounce and diff_time < self.debounce then
async.util.sleep(self.debounce - diff_time) async.util.sleep(self.debounce - diff_time)
end
else
-- resume previous picker
local index = 1
for entry in self.manager:iter() do
self:entry_adder(index, entry, _, true)
index = index + 1
end
self.cache_picker.is_cached = false
-- if text changed, required to set anew to restart finder; otherwise hl and selection
if self.cache_picker.cached_prompt ~= self.default_text then
self:reset_prompt()
self:set_prompt(self.default_text)
else
-- scheduling required to apply highlighting and selection appropriately
await_schedule(function()
self:highlight_displayed_rows(self.results_bufnr, self.cache_picker.cached_prompt)
if self.cache_picker.selection_row ~= nil then
self:set_selection(self.cache_picker.selection_row)
end
end)
end
end end
end end
end) end)
@@ -444,7 +475,6 @@ function Picker:find()
self._result_completed = false self._result_completed = false
status_updater { completed = false } status_updater { completed = false }
tx.send(...) tx.send(...)
end, end,
on_detach = function() on_detach = function()
@@ -463,8 +493,6 @@ function Picker:find()
vim.cmd(on_buf_leave) vim.cmd(on_buf_leave)
vim.cmd [[augroup END]] vim.cmd [[augroup END]]
self.prompt_bufnr = prompt_bufnr
local preview_border = preview_opts and preview_opts.border local preview_border = preview_opts and preview_opts.border
self.preview_border = preview_border self.preview_border = preview_border
local preview_border_win = (preview_border and preview_border.win_id) and preview_border.win_id local preview_border_win = (preview_border and preview_border.win_id) and preview_border.win_id
@@ -1124,6 +1152,41 @@ function pickers.on_close_prompt(prompt_bufnr)
local status = state.get_status(prompt_bufnr) local status = state.get_status(prompt_bufnr)
local picker = status.picker local picker = status.picker
if type(picker.cache_picker) == "table" then
local cached_pickers = state.get_global_key "cached_pickers" or {}
if type(picker.cache_picker.index) == "number" then
if not vim.tbl_isempty(cached_pickers) then
table.remove(cached_pickers, picker.cache_picker.index)
end
end
-- if picker was disabled post-hoc (e.g. `cache_picker = false` conclude after deletion)
if picker.cache_picker.disabled ~= true then
if picker.cache_picker.limit_entries > 0 then
-- edge case: starting in normal mode and not having run a search means having no manager instantiated
if picker.manager then
picker.manager.linked_states:truncate(picker.cache_picker.limit_entries)
else
picker.manager = EntryManager:new(picker.max_results, picker.entry_adder, picker.stats)
end
end
picker.default_text = picker:_get_prompt()
picker.cache_picker.selection_row = picker._selection_row
picker.cache_picker.cached_prompt = picker:_get_prompt()
picker.cache_picker.is_cached = true
table.insert(cached_pickers, 1, picker)
-- release pickers
if picker.cache_picker.num_pickers > 0 then
while #cached_pickers > picker.cache_picker.num_pickers do
table.remove(cached_pickers, #cached_pickers)
end
end
state.set_global_key("cached_pickers", cached_pickers)
end
end
if picker.sorter then if picker.sorter then
picker.sorter:_destroy() picker.sorter:_destroy()
end end

View File

@@ -247,6 +247,8 @@ previewers.new_buffer_previewer = function(opts)
buf_delete(bufnr) buf_delete(bufnr)
end end
end end
-- enable resuming picker with existing previewer to avoid lookup of deleted bufs
bufname_table = {}
end end
function opts.preview_fn(self, entry, status) function opts.preview_fn(self, entry, status)
@@ -853,6 +855,83 @@ previewers.highlights = defaulter(function(_)
} }
end, {}) end, {})
previewers.pickers = defaulter(function(_)
local ns_telescope_multiselection = vim.api.nvim_create_namespace "telescope_mulitselection"
local get_row = function(picker, preview_height, index)
if picker.sorting_strategy == "ascending" then
return index - 1
else
return preview_height - index
end
end
return previewers.new_buffer_previewer {
dyn_title = function(_, entry)
if entry.value.default_text and entry.value.default_text ~= "" then
return string.format("%s ─ %s", entry.value.prompt_title, entry.value.default_text)
end
return entry.value.prompt_title
end,
get_buffer_by_name = function(_, entry)
return tostring(entry.value.prompt_bufnr)
end,
teardown = function(self)
if self.state and self.state.last_set_bufnr and vim.api.nvim_buf_is_valid(self.state.last_set_bufnr) then
vim.api.nvim_buf_clear_namespace(self.state.last_set_bufnr, ns_telescope_multiselection, 0, -1)
end
end,
define_preview = function(self, entry, status)
putils.with_preview_window(status, nil, function()
local ns_telescope_entry = vim.api.nvim_create_namespace "telescope_entry"
local preview_height = vim.api.nvim_win_get_height(status.preview_win)
if self.state.bufname then
return
end
local picker = entry.value
-- prefill buffer to be able to set lines individually
local placeholder = utils.repeated_table(preview_height, "")
vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, placeholder)
for index = 1, math.min(preview_height, picker.manager:num_results()) do
local row = get_row(picker, preview_height, index)
local e = picker.manager:get_entry(index)
local display, display_highlight = e:display()
vim.api.nvim_buf_set_lines(self.state.bufnr, row, row + 1, false, { display })
if display_highlight ~= nil then
for _, hl_block in ipairs(display_highlight) do
vim.api.nvim_buf_add_highlight(
self.state.bufnr,
ns_telescope_entry,
hl_block[2],
row,
hl_block[1][1],
hl_block[1][2]
)
end
end
if picker._multi:is_selected(e) then
vim.api.nvim_buf_add_highlight(
self.state.bufnr,
ns_telescope_multiselection,
"TelescopeMultiSelection",
row,
0,
-1
)
end
end
end)
end,
}
end, {})
previewers.display_content = defaulter(function(_) previewers.display_content = defaulter(function(_)
return previewers.new_buffer_previewer { return previewers.new_buffer_previewer {
define_preview = function(self, entry, status) define_preview = function(self, entry, status)

View File

@@ -306,6 +306,7 @@ previewers.man = buffer_previewer.man
previewers.autocommands = buffer_previewer.autocommands previewers.autocommands = buffer_previewer.autocommands
previewers.highlights = buffer_previewer.highlights previewers.highlights = buffer_previewer.highlights
previewers.buffers = buffer_previewer.buffers previewers.buffers = buffer_previewer.buffers
previewers.pickers = buffer_previewer.pickers
--- A deprecated way of displaying content more easily. Was written at a time, --- A deprecated way of displaying content more easily. Was written at a time,
--- where the buffer_previewer interface wasn't present. Nowadays it's easier --- where the buffer_previewer interface wasn't present. Nowadays it's easier