From 5d37c3ea08f40d8c9d3a9ebcc72bd641d366c110 Mon Sep 17 00:00:00 2001 From: fdschmidt93 <39233597+fdschmidt93@users.noreply.github.com> Date: Wed, 1 Sep 2021 18:17:18 +0200 Subject: [PATCH] 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 --- README.md | 2 + doc/telescope.txt | 79 +++++++++++++-- lua/telescope/actions/init.lua | 15 +++ lua/telescope/algos/linked_list.lua | 37 +++++++ lua/telescope/builtin/init.lua | 23 ++++- lua/telescope/builtin/internal.lua | 76 +++++++++++++++ lua/telescope/config.lua | 40 +++++++- lua/telescope/make_entry.lua | 26 +++++ lua/telescope/pickers.lua | 97 +++++++++++++++---- lua/telescope/previewers/buffer_previewer.lua | 79 +++++++++++++++ lua/telescope/previewers/init.lua | 1 + 11 files changed, 444 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 222b820..a1df186 100644 --- a/README.md +++ b/README.md @@ -439,6 +439,8 @@ Built-in functions. Ready to be bound to any key you like. :smile: | `builtin.highlights` | Lists all available highlights | | `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.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 diff --git a/doc/telescope.txt b/doc/telescope.txt index 8fedd6c..fc36ca5 100644 --- a/doc/telescope.txt +++ b/doc/telescope.txt @@ -25,6 +25,28 @@ telescope.setup({opts}) *telescope.setup()* 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* default_mappings: ~ 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 Fields: ~ - {cwd} (string) directory path to search from (default - is cwd, use utils.buffer_dir() to search + {cwd} (string) root dir to search from (default is cwd, + use utils.buffer_dir() to search relative to open buffer) {grep_open_files} (boolean) if true, restrict search to open files only, mutually exclusive with @@ -388,8 +410,8 @@ builtin.grep_string({opts}) *builtin.grep_string()* {opts} (table) options to pass to the picker Fields: ~ - {cwd} (string) directory path to search from (default - is cwd, use utils.buffer_dir() to search + {cwd} (string) root dir to search from (default is cwd, + use utils.buffer_dir() to search relative to open buffer) {search} (string) the query to search {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 Fields: ~ - {cwd} (string) directory path to search from (default is - cwd, use utils.buffer_dir() to search - relative to open buffer) + {cwd} (string) root dir to search from (default is cwd, use + utils.buffer_dir() to search relative to + open buffer) {find_command} (table) command line arguments for `find_files` to use for the search, overrides default config {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 Fields: ~ - {cwd} (string) directory path to browse (default is cwd, use - utils.buffer_dir() to browse relative to open + {cwd} (string) root dir to browse from (default is cwd, use + utils.buffer_dir() to search relative to open buffer) {depth} (number) file tree depth to display (default is 1) {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 +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: + - ``: 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()* Lists vim options, allows you to edit the current value on `` @@ -1582,6 +1633,16 @@ actions.cycle_previewers_prev({prompt_bufnr})*actions.cycle_previewers_prev()* {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* diff --git a/lua/telescope/actions/init.lua b/lua/telescope/actions/init.lua index cda5f1d..aa930dc 100644 --- a/lua/telescope/actions/init.lua +++ b/lua/telescope/actions/init.lua @@ -832,6 +832,21 @@ actions.cycle_previewers_prev = function(prompt_bufnr) actions.get_current_picker(prompt_bufnr):cycle_previewers(-1) end +--- Removes the selected picker in |builtin.pickers|.
+--- 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. -- ================================================== diff --git a/lua/telescope/algos/linked_list.lua b/lua/telescope/algos/linked_list.lua index 6015e1e..2da6a6e 100644 --- a/lua/telescope/algos/linked_list.lua +++ b/lua/telescope/algos/linked_list.lua @@ -215,4 +215,41 @@ function LinkedList:ipairs() 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 diff --git a/lua/telescope/builtin/init.lua b/lua/telescope/builtin/init.lua index ffc217e..6cc24b4 100644 --- a/lua/telescope/builtin/init.lua +++ b/lua/telescope/builtin/init.lua @@ -68,7 +68,7 @@ local builtin = {} --- Search for a string and get results live as you type (respecting .gitignore) ---@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 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 @@ -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 ---@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_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) @@ -85,7 +85,7 @@ builtin.grep_string = require("telescope.builtin.files").grep_string --- Search for files (respecting .gitignore) ---@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 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) @@ -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 --- `mkdir -p` would work) if they do not already exist ---@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 dir_icon string: change the icon for a directory. default:  ---@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 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: +--- - ``: 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 `` ---@param opts table: options to pass to the picker builtin.vim_options = require("telescope.builtin.internal").vim_options diff --git a/lua/telescope/builtin/internal.lua b/lua/telescope/builtin/internal.lua index b71811e..cbacf97 100644 --- a/lua/telescope/builtin/internal.lua +++ b/lua/telescope/builtin/internal.lua @@ -6,7 +6,9 @@ local make_entry = require "telescope.make_entry" local Path = require "plenary.path" local pickers = require "telescope.pickers" local previewers = require "telescope.previewers" +local p_window = require "telescope.pickers.window" local sorters = require "telescope.sorters" +local state = require "telescope.state" local utils = require "telescope.utils" local conf = require("telescope.config").values @@ -71,6 +73,80 @@ internal.builtin = function(opts) }):find() 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", "", actions.remove_selected_picker) + map("n", "", actions.remove_selected_picker) + return true + end, + }):find() +end + internal.planets = function(opts) local show_pluto = opts.show_pluto or false diff --git a/lua/telescope/config.lua b/lua/telescope/config.lua index a4899af..d58b94e 100644 --- a/lua/telescope/config.lua +++ b/lua/telescope/config.lua @@ -46,11 +46,22 @@ local smarter_depth_2_extend = function(priority, base) return result 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. -- selection_strategy local config = {} config.smarter_depth_2_extend = smarter_depth_2_extend +config.resolve_table_opts = resolve_table_opts config.values = _TelescopeConfigurationValues 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 -- 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, {})) ) end - if name == "history" then + if name == "history" or name == "cache_picker" then if user_defaults[name] == false or config.values[name] == false then return false end diff --git a/lua/telescope/make_entry.lua b/lua/telescope/make_entry.lua index e2c6d45..14d5ecb 100644 --- a/lua/telescope/make_entry.lua +++ b/lua/telescope/make_entry.lua @@ -662,6 +662,32 @@ function make_entry.gen_from_highlights() 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) local displayer = entry_display.create { separator = " │ ", diff --git a/lua/telescope/pickers.lua b/lua/telescope/pickers.lua index 9e5f251..42e37d9 100644 --- a/lua/telescope/pickers.lua +++ b/lua/telescope/pickers.lua @@ -85,7 +85,11 @@ function Picker:new(opts) _find_id = 0, _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), stats = {}, @@ -104,6 +108,8 @@ function Picker:new(opts) border = get_default(opts.border, config.values.border), borderchars = get_default(opts.borderchars, config.values.borderchars), }, + + cache_picker = config.resolve_table_opts(opts.cache_picker, vim.deepcopy(config.values.cache_picker)), }, self) 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 vim.api.nvim_win_set_option(prompt_border_win, "winhl", "Normal:TelescopePromptBorder") end + self.prompt_bufnr = prompt_bufnr -- Prompt prefix local prompt_prefix = self.prompt_prefix @@ -416,23 +423,47 @@ function Picker:find() self.finder = new_finder end - self.sorter:_start(prompt) - self.manager = EntryManager:new(self.max_results, self.entry_adder, self.stats) + -- TODO: Entry manager should have a "bulk" setter. This can prevent a lot of redraws from display + 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_complete = self:get_result_completor(self.results_bufnr, find_id, prompt, status_updater) + 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, process_complete) - end) + local ok, msg = pcall(function() + self.finder(prompt, process_result, process_complete) + end) - if not ok then - log.warn("Finder failed with msg: ", msg) - end + if not ok then + 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) + 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 + 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) @@ -444,7 +475,6 @@ function Picker:find() self._result_completed = false status_updater { completed = false } - tx.send(...) end, on_detach = function() @@ -463,8 +493,6 @@ function Picker:find() vim.cmd(on_buf_leave) vim.cmd [[augroup END]] - self.prompt_bufnr = prompt_bufnr - local preview_border = preview_opts and preview_opts.border self.preview_border = preview_border 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 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 picker.sorter:_destroy() end diff --git a/lua/telescope/previewers/buffer_previewer.lua b/lua/telescope/previewers/buffer_previewer.lua index f6c4a78..59630b8 100644 --- a/lua/telescope/previewers/buffer_previewer.lua +++ b/lua/telescope/previewers/buffer_previewer.lua @@ -247,6 +247,8 @@ previewers.new_buffer_previewer = function(opts) buf_delete(bufnr) end end + -- enable resuming picker with existing previewer to avoid lookup of deleted bufs + bufname_table = {} end function opts.preview_fn(self, entry, status) @@ -853,6 +855,83 @@ previewers.highlights = defaulter(function(_) } 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(_) return previewers.new_buffer_previewer { define_preview = function(self, entry, status) diff --git a/lua/telescope/previewers/init.lua b/lua/telescope/previewers/init.lua index 1d7d63e..b749056 100644 --- a/lua/telescope/previewers/init.lua +++ b/lua/telescope/previewers/init.lua @@ -306,6 +306,7 @@ previewers.man = buffer_previewer.man previewers.autocommands = buffer_previewer.autocommands previewers.highlights = buffer_previewer.highlights previewers.buffers = buffer_previewer.buffers +previewers.pickers = buffer_previewer.pickers --- 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