From 79dc995f820150d5de880c08e814af327ff7e965 Mon Sep 17 00:00:00 2001 From: fdschmidt93 <39233597+fdschmidt93@users.noreply.github.com> Date: Mon, 23 Aug 2021 15:27:11 +0200 Subject: [PATCH] fix: (terminal) buffer previewer (#1120) Use existing buffers for buffer previewer to allow previewing special buffer types --- lua/telescope/actions/init.lua | 7 + lua/telescope/builtin/internal.lua | 10 +- lua/telescope/previewers/buffer_previewer.lua | 136 ++++++++++++++---- lua/telescope/previewers/init.lua | 1 + lua/telescope/previewers/previewer.lua | 2 +- lua/telescope/previewers/term_previewer.lua | 3 - 6 files changed, 129 insertions(+), 30 deletions(-) diff --git a/lua/telescope/actions/init.lua b/lua/telescope/actions/init.lua index 7f82823..cda5f1d 100644 --- a/lua/telescope/actions/init.lua +++ b/lua/telescope/actions/init.lua @@ -807,6 +807,13 @@ end actions.delete_buffer = function(prompt_bufnr) local current_picker = action_state.get_current_picker(prompt_bufnr) current_picker:delete_selection(function(selection) + -- avoid preview win from closing by creating tmp buffer + local preview_win = state.get_status(prompt_bufnr).preview_win + if preview_win ~= nil and vim.api.nvim_win_is_valid(preview_win) then + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(buf, "bufhidden", "wipe") + vim.api.nvim_win_set_buf(preview_win, buf) + end vim.api.nvim_buf_delete(selection.bufnr, { force = true }) end) end diff --git a/lua/telescope/builtin/internal.lua b/lua/telescope/builtin/internal.lua index 226373b..4b2747b 100644 --- a/lua/telescope/builtin/internal.lua +++ b/lua/telescope/builtin/internal.lua @@ -655,9 +655,17 @@ internal.buffers = function(opts) results = buffers, entry_maker = opts.entry_maker or make_entry.gen_from_buffer(opts), }, - previewer = conf.grep_previewer(opts), + previewer = previewers.buffers.new(opts), sorter = conf.generic_sorter(opts), default_selection_index = default_selection_idx, + attach_mappings = function(_, _) + action_set.select:enhance { + post = function() + local entry = action_state.get_selected_entry() + vim.api.nvim_win_set_cursor(0, { entry.lnum, entry.col or 0 }) + end, + } + end, }):find() end diff --git a/lua/telescope/previewers/buffer_previewer.lua b/lua/telescope/previewers/buffer_previewer.lua index 2408366..3ba7bac 100644 --- a/lua/telescope/previewers/buffer_previewer.lua +++ b/lua/telescope/previewers/buffer_previewer.lua @@ -81,6 +81,19 @@ local search_teardown = function(self) end end +local scroll_fn = function(self, direction) + if not self.state then + return + end + + local input = direction > 0 and [[]] or [[]] + local count = math.abs(direction) + + vim.api.nvim_win_call(self.state.winid, function() + vim.cmd([[normal! ]] .. count .. input) + end) +end + previewers.file_maker = function(filepath, bufnr, opts) opts = opts or {} if opts.use_ft_detect == nil then @@ -282,18 +295,7 @@ previewers.new_buffer_previewer = function(opts) end if not opts.scroll_fn then - function opts.scroll_fn(self, direction) - if not self.state then - return - end - - local input = direction > 0 and [[]] or [[]] - local count = math.abs(direction) - - vim.api.nvim_buf_call(self.state.bufnr, function() - vim.cmd([[normal! ]] .. count .. input) - end) - end + opts.scroll_fn = scroll_fn end return Previewer:new(opts) @@ -370,19 +372,12 @@ previewers.vimgrep = defaulter(function(opts) pcall(vim.api.nvim_buf_clear_namespace, self.state.last_set_bufnr, ns_previewer, 0, -1) end - -- Workaround for unnamed buffer when using builtin.buffer - if entry.bufnr and (p == "[No Name]" or vim.api.nvim_buf_get_option(entry.bufnr, "buftype") ~= "") then - local lines = vim.api.nvim_buf_get_lines(entry.bufnr, 0, -1, false) - vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines) - jump_to_line(self, self.state.bufnr, entry.lnum) - else - conf.buffer_previewer_maker(p, self.state.bufnr, { - bufname = self.state.bufname, - callback = function(bufnr) - jump_to_line(self, bufnr, entry.lnum) - end, - }) - end + conf.buffer_previewer_maker(p, self.state.bufnr, { + bufname = self.state.bufname, + callback = function(bufnr) + jump_to_line(self, bufnr, entry.lnum) + end, + }) end, } end, {}) @@ -872,4 +867,95 @@ previewers.display_content = defaulter(function(_) } end, {}) +previewers.buffers = defaulter(function(opts) + opts = opts or {} + local cwd = opts.cwd or vim.loop.cwd() + local previewer_active = true -- decouple provider from preview_win + return Previewer:new { + title = function() + return "Buffers" + end, + setup = function(_, status) + local win_id = status.picker.original_win_id + -- required because of see `:h local-options` as + -- buffers not yet attached to a current window take the options from the `minimal` popup ... + local state = { + ["previewed_buffers"] = {}, + ["winid"] = status.preview_win, + ["win_options"] = { + ["colorcolumn"] = vim.api.nvim_win_get_option(win_id, "colorcolumn"), + ["cursorline"] = vim.api.nvim_win_get_option(win_id, "cursorline"), + ["foldlevel"] = vim.api.nvim_win_get_option(win_id, "foldlevel"), + ["list"] = vim.api.nvim_win_get_option(win_id, "list"), + ["number"] = vim.api.nvim_win_get_option(win_id, "number"), + ["relativenumber"] = vim.api.nvim_win_get_option(win_id, "relativenumber"), + ["signcolumn"] = vim.api.nvim_win_get_option(win_id, "signcolumn"), + ["spell"] = vim.api.nvim_win_get_option(win_id, "spell"), + ["winhl"] = vim.api.nvim_win_get_option(win_id, "winhl"), + ["wrap"] = vim.api.nvim_win_get_option(win_id, "wrap"), + }, + } + -- TODO clear explicitly once API should become available + -- decoration provider is hierachical on_start -> win + vim.api.nvim_set_decoration_provider(ns_previewer, { + on_start = function() + -- defacto disable provider if status.preview_win does not exist anymore + return previewer_active + end, + on_win = function(_, winid, bufnr, _) + if winid ~= status.preview_win then + return false -- skip setting extmark for any window other than status.preview_win + end + local lnum, _ = unpack(vim.api.nvim_win_get_cursor(winid)) + local line = vim.api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, false)[1] + -- only set if winid and rows are matching + pcall(vim.api.nvim_buf_set_extmark, bufnr, ns_previewer, lnum - 1, 0, { + end_col = #line, + virt_text_pos = "overlay", + hl_group = "TelescopePreviewLine", + ephemeral = true, + priority = 101, -- 1 higher than treesitter + }) + end, + }) + return state + end, + teardown = function(self) + -- reapply proper buffer-window options.. + for opt, value in pairs(self.state.win_options) do + vim.api.nvim_win_set_option(self.state.winid, opt, value) + end + -- TODO precautious clearing of extmark though likely no effect due to ephemeral + -- clear extmarks for previewed buffers + for buf, _ in pairs(self.state.previewed_buffers) do + if vim.api.nvim_buf_is_valid(buf) then + vim.api.nvim_buf_clear_namespace(buf, ns_previewer, 0, -1) + end + end + previewer_active = false + end, + dyn_title = function(_, entry) + return Path:new(from_entry.path(entry, true)):normalize(cwd) + end, + preview_fn = function(self, entry, status) + if vim.api.nvim_buf_is_valid(entry.bufnr) then + vim.api.nvim_win_set_buf(status.preview_win, entry.bufnr) + vim.api.nvim_win_set_option(status.preview_win, "winhl", "Normal:TelescopePreviewNormal") + vim.api.nvim_win_set_option(status.preview_win, "signcolumn", "no") + vim.api.nvim_win_set_option(status.preview_win, "foldlevel", 100) + vim.api.nvim_win_set_option(status.preview_win, "wrap", false) + self.state.bufnr = entry.bufnr + if not entry.col then + local _, col = unpack(vim.api.nvim_win_get_cursor(status.preview_win)) + entry.col = col + 1 + end + if self.state.previewed_buffers[entry.bufnr] ~= true then + self.state.previewed_buffers[entry.bufnr] = true + end + end + end, + scroll_fn = scroll_fn, + } +end, {}) + return previewers diff --git a/lua/telescope/previewers/init.lua b/lua/telescope/previewers/init.lua index 849e2c1..1d7d63e 100644 --- a/lua/telescope/previewers/init.lua +++ b/lua/telescope/previewers/init.lua @@ -305,6 +305,7 @@ previewers.help = buffer_previewer.help previewers.man = buffer_previewer.man previewers.autocommands = buffer_previewer.autocommands previewers.highlights = buffer_previewer.highlights +previewers.buffers = buffer_previewer.buffers --- 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 diff --git a/lua/telescope/previewers/previewer.lua b/lua/telescope/previewers/previewer.lua index dffa5de..d6eb9f1 100644 --- a/lua/telescope/previewers/previewer.lua +++ b/lua/telescope/previewers/previewer.lua @@ -23,7 +23,7 @@ function Previewer:preview(entry, status) if not self.state then if self._setup_func then - self.state = self:_setup_func() + self.state = self:_setup_func(status) else self.state = {} end diff --git a/lua/telescope/previewers/term_previewer.lua b/lua/telescope/previewers/term_previewer.lua index 8d4219c..375143d 100644 --- a/lua/telescope/previewers/term_previewer.lua +++ b/lua/telescope/previewers/term_previewer.lua @@ -294,9 +294,6 @@ previewers.vimgrep = defaulter(function(opts) if p == nil or p == "" then return end - if entry.bufnr and (p == "[No Name]" or vim.api.nvim_buf_get_option(entry.bufnr, "buftype") ~= "") then - return - end local lnum = entry.lnum or 0