feat: add hide / unhide preview (#1305)
* feat: add hide / unhide preview or results and prompt * fix edit actions while only preview window is active * add option to start telescope without previewer -> "disable_previewer_at_startup" * remove hide / unhide prompt and resutls, improve hide / unhide preview * fix tests - check if popup window should be created with borders - popup.create does not support setting borderhighlight and border=false * allow toggle preview even if preview is set to false * reuse recalculate_layout in hide / unhide preview * add docs to toggle preview * check if preview window is valid window * remove unnecessary changes * cleanup, remove unnecessary changes * close all previewers, refactor toggle preview code [docgen] Update doc/telescope.txt skip-checks: true
This commit is contained in:
@@ -395,6 +395,9 @@ telescope.setup({opts}) *telescope.setup()*
|
|||||||
Default: true
|
Default: true
|
||||||
- msg_bg_fillchar: Character to fill background of unpreviewable buffers with
|
- msg_bg_fillchar: Character to fill background of unpreviewable buffers with
|
||||||
Default: "╱"
|
Default: "╱"
|
||||||
|
- hide_on_startup: Hide previewer when picker starts. Previewer can be toggled
|
||||||
|
with actions.toggle_preview.
|
||||||
|
Default: false
|
||||||
|
|
||||||
|
|
||||||
*telescope.defaults.vimgrep_arguments*
|
*telescope.defaults.vimgrep_arguments*
|
||||||
@@ -1909,6 +1912,15 @@ actions.toggle_all({prompt_bufnr}) *actions.toggle_all()*
|
|||||||
{prompt_bufnr} (number) The prompt bufnr
|
{prompt_bufnr} (number) The prompt bufnr
|
||||||
|
|
||||||
|
|
||||||
|
actions.toggle_preview({prompt_bufnr}) *actions.toggle_preview()*
|
||||||
|
Toggle preview window.
|
||||||
|
- Note: preview window can be toggled even if preview is set to false.
|
||||||
|
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{prompt_bufnr} (number) The prompt bufnr
|
||||||
|
|
||||||
|
|
||||||
actions.git_create_branch({prompt_bufnr}) *actions.git_create_branch()*
|
actions.git_create_branch({prompt_bufnr}) *actions.git_create_branch()*
|
||||||
Create and checkout a new git branch if it doesn't already exist
|
Create and checkout a new git branch if it doesn't already exist
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,13 @@ function actions.toggle_all(prompt_bufnr)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Toggle preview window.
|
||||||
|
--- - Note: preview window can be toggled even if preview is set to false.
|
||||||
|
---@param prompt_bufnr number: The prompt bufnr
|
||||||
|
function actions.toggle_preview(prompt_bufnr)
|
||||||
|
action_state.get_current_picker(prompt_bufnr):toggle_preview()
|
||||||
|
end
|
||||||
|
|
||||||
function actions.preview_scrolling_up(prompt_bufnr)
|
function actions.preview_scrolling_up(prompt_bufnr)
|
||||||
action_set.scroll_previewer(prompt_bufnr, -1)
|
action_set.scroll_previewer(prompt_bufnr, -1)
|
||||||
end
|
end
|
||||||
@@ -240,23 +247,14 @@ end
|
|||||||
actions._close = function(prompt_bufnr, keepinsert)
|
actions._close = function(prompt_bufnr, keepinsert)
|
||||||
action_state.get_current_history():reset()
|
action_state.get_current_history():reset()
|
||||||
local picker = action_state.get_current_picker(prompt_bufnr)
|
local picker = action_state.get_current_picker(prompt_bufnr)
|
||||||
local prompt_win = state.get_status(prompt_bufnr).prompt_win
|
|
||||||
local original_win_id = picker.original_win_id
|
local original_win_id = picker.original_win_id
|
||||||
|
|
||||||
if picker.previewer then
|
|
||||||
for _, v in ipairs(picker.all_previewers) do
|
|
||||||
v:teardown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
actions.close_pum(prompt_bufnr)
|
actions.close_pum(prompt_bufnr)
|
||||||
if not keepinsert then
|
if not keepinsert then
|
||||||
vim.cmd [[stopinsert]]
|
vim.cmd [[stopinsert]]
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.api.nvim_win_close(prompt_win, true)
|
require("telescope.pickers").on_close_prompt(prompt_bufnr)
|
||||||
|
|
||||||
pcall(vim.cmd, string.format([[silent bdelete! %s]], prompt_bufnr))
|
|
||||||
pcall(a.nvim_set_current_win, original_win_id)
|
pcall(a.nvim_set_current_win, original_win_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -431,6 +431,7 @@ append(
|
|||||||
timeout = 250,
|
timeout = 250,
|
||||||
treesitter = true,
|
treesitter = true,
|
||||||
msg_bg_fillchar = "╱",
|
msg_bg_fillchar = "╱",
|
||||||
|
hide_on_startup = false,
|
||||||
},
|
},
|
||||||
[[
|
[[
|
||||||
This field handles the global configuration for previewers.
|
This field handles the global configuration for previewers.
|
||||||
@@ -511,6 +512,9 @@ append(
|
|||||||
Default: true
|
Default: true
|
||||||
- msg_bg_fillchar: Character to fill background of unpreviewable buffers with
|
- msg_bg_fillchar: Character to fill background of unpreviewable buffers with
|
||||||
Default: "╱"
|
Default: "╱"
|
||||||
|
- hide_on_startup: Hide previewer when picker starts. Previewer can be toggled
|
||||||
|
with actions.toggle_preview.
|
||||||
|
Default: false
|
||||||
]]
|
]]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,14 @@ function Picker:new(opts)
|
|||||||
obj.previewer = false
|
obj.previewer = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local __hide_previewer = opts.__hide_previewer
|
||||||
|
if __hide_previewer then
|
||||||
|
obj.hidden_previewer = obj.previewer
|
||||||
|
obj.previewer = nil
|
||||||
|
else
|
||||||
|
obj.hidden_previewer = nil
|
||||||
|
end
|
||||||
|
|
||||||
-- TODO: It's annoying that this is create and everything else is "new"
|
-- TODO: It's annoying that this is create and everything else is "new"
|
||||||
obj.scroller = p_scroller.create(obj.scroll_strategy, obj.sorting_strategy)
|
obj.scroller = p_scroller.create(obj.scroll_strategy, obj.sorting_strategy)
|
||||||
|
|
||||||
@@ -297,6 +305,7 @@ function Picker:find()
|
|||||||
-- 1. Prompt window
|
-- 1. Prompt window
|
||||||
-- 2. Options window
|
-- 2. Options window
|
||||||
-- 3. Preview window
|
-- 3. Preview window
|
||||||
|
|
||||||
local line_count = vim.o.lines - vim.o.cmdheight
|
local line_count = vim.o.lines - vim.o.cmdheight
|
||||||
if vim.o.laststatus ~= 0 then
|
if vim.o.laststatus ~= 0 then
|
||||||
line_count = line_count - 1
|
line_count = line_count - 1
|
||||||
@@ -315,12 +324,11 @@ function Picker:find()
|
|||||||
popup_opts.prompt.titlehighlight = "TelescopePromptTitle"
|
popup_opts.prompt.titlehighlight = "TelescopePromptTitle"
|
||||||
if popup_opts.preview then
|
if popup_opts.preview then
|
||||||
popup_opts.preview.minheight = popup_opts.preview.height
|
popup_opts.preview.minheight = popup_opts.preview.height
|
||||||
popup_opts.preview.highlight = "TelescopeNormal"
|
popup_opts.preview.highlight = "TelescopePreviewNormal"
|
||||||
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
|
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
|
||||||
popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
|
popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- local results_win, results_opts = popup.create("", popup_opts.results)
|
|
||||||
local results_win, results_opts, results_border_win = self:_create_window("", popup_opts.results, true)
|
local results_win, results_opts, results_border_win = self:_create_window("", popup_opts.results, true)
|
||||||
local results_bufnr = a.nvim_win_get_buf(results_win)
|
local results_bufnr = a.nvim_win_get_buf(results_win)
|
||||||
|
|
||||||
@@ -457,12 +465,14 @@ function Picker:find()
|
|||||||
|
|
||||||
-- TODO: Use WinLeave as well?
|
-- TODO: Use WinLeave as well?
|
||||||
local on_buf_leave = string.format(
|
local on_buf_leave = string.format(
|
||||||
[[ autocmd BufLeave <buffer> ++nested ++once :silent lua require('telescope.pickers').on_close_prompt(%s)]],
|
[[ autocmd BufLeave <buffer=%s> ++nested ++once :silent lua require('telescope.pickers').on_close_prompt(%s)]],
|
||||||
|
prompt_bufnr,
|
||||||
prompt_bufnr
|
prompt_bufnr
|
||||||
)
|
)
|
||||||
|
|
||||||
local on_vim_resize = string.format(
|
local on_vim_resize = string.format(
|
||||||
[[ autocmd VimResized <buffer> ++nested :lua require('telescope.pickers').on_resize_window(%s)]],
|
[[ autocmd VimResized <buffer=%s> ++nested :lua require('telescope.pickers').on_resize_window(%s)]],
|
||||||
|
prompt_bufnr,
|
||||||
prompt_bufnr
|
prompt_bufnr
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -527,11 +537,16 @@ function Picker:recalculate_layout()
|
|||||||
if preview_win ~= nil then
|
if preview_win ~= nil then
|
||||||
popup.move(preview_win, popup_opts.preview)
|
popup.move(preview_win, popup_opts.preview)
|
||||||
else
|
else
|
||||||
popup_opts.preview.highlight = "TelescopeNormal"
|
popup_opts.preview.highlight = "TelescopePreviewNormal"
|
||||||
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
|
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
|
||||||
popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
|
popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
|
||||||
preview_win, preview_opts, preview_border_win = self:_create_window("", popup_opts.preview)
|
local preview_bufnr = vim.api.nvim_buf_is_valid(status.preview_bufnr) and status.preview_bufnr or ""
|
||||||
|
preview_win, preview_opts, preview_border_win = self:_create_window(preview_bufnr, popup_opts.preview)
|
||||||
|
if preview_bufnr == "" then
|
||||||
|
preview_bufnr = a.nvim_win_get_buf(preview_win)
|
||||||
|
end
|
||||||
status.preview_win = preview_win
|
status.preview_win = preview_win
|
||||||
|
status.preview_bufnr = preview_bufnr
|
||||||
status.preview_border_win = preview_border_win
|
status.preview_border_win = preview_border_win
|
||||||
state.set_status(prompt_win, status)
|
state.set_status(prompt_win, status)
|
||||||
self.preview_win = preview_win
|
self.preview_win = preview_win
|
||||||
@@ -539,10 +554,8 @@ function Picker:recalculate_layout()
|
|||||||
self.preview_border = preview_opts and preview_opts.border
|
self.preview_border = preview_opts and preview_opts.border
|
||||||
end
|
end
|
||||||
elseif preview_win ~= nil then
|
elseif preview_win ~= nil then
|
||||||
vim.api.nvim_win_close(preview_win, false)
|
utils.win_delete("preview_win", preview_win, true)
|
||||||
if status.preview_border_win then
|
utils.win_delete("preview_win", status.preview_border_win, true)
|
||||||
vim.api.nvim_win_close(status.preview_border_win, false)
|
|
||||||
end
|
|
||||||
status.preview_win = nil
|
status.preview_win = nil
|
||||||
status.preview_border_win = nil
|
status.preview_border_win = nil
|
||||||
state.set_status(prompt_win, status)
|
state.set_status(prompt_win, status)
|
||||||
@@ -559,9 +572,39 @@ function Picker:recalculate_layout()
|
|||||||
-- self.max_results = popup_opts.results.height
|
-- self.max_results = popup_opts.results.height
|
||||||
end
|
end
|
||||||
|
|
||||||
function Picker:hide_preview()
|
local update_scroll = function(win, oldinfo, oldcursor, strategy, max_results)
|
||||||
-- 1. Hide the window (and border)
|
if strategy == "ascending" then
|
||||||
-- 2. Resize prompt & results windows accordingly
|
vim.api.nvim_win_set_cursor(win, { max_results, 0 })
|
||||||
|
vim.api.nvim_win_set_cursor(win, { oldinfo.topline, 0 })
|
||||||
|
vim.api.nvim_win_set_cursor(win, oldcursor)
|
||||||
|
elseif strategy == "descending" then
|
||||||
|
vim.api.nvim_win_set_cursor(win, { 1, 0 })
|
||||||
|
vim.api.nvim_win_set_cursor(win, { oldinfo.botline, 0 })
|
||||||
|
vim.api.nvim_win_set_cursor(win, oldcursor)
|
||||||
|
else
|
||||||
|
error(debug.traceback("Unknown sorting strategy: " .. (strategy or "")))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Picker:toggle_preview()
|
||||||
|
local status = state.get_status(self.prompt_bufnr)
|
||||||
|
|
||||||
|
if self.previewer and status.preview_win then
|
||||||
|
self.hidden_previewer = self.previewer
|
||||||
|
self.previewer = nil
|
||||||
|
elseif self.hidden_previewer and not status.preview_win then
|
||||||
|
self.previewer = self.hidden_previewer
|
||||||
|
self.hidden_previewer = nil
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local oldinfo = vim.fn.getwininfo(status.results_win)[1]
|
||||||
|
local oldcursor = vim.api.nvim_win_get_cursor(status.results_win)
|
||||||
|
|
||||||
|
self:recalculate_layout()
|
||||||
|
self:refresh_previewer()
|
||||||
|
update_scroll(status.results_win, oldinfo, oldcursor, self.sorting_strategy, self.max_results)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Picker:toggle_padding()
|
function Picker:toggle_padding()
|
||||||
@@ -638,6 +681,8 @@ function Picker:set_prompt(str)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Picker.close_windows(status)
|
function Picker.close_windows(status)
|
||||||
|
-- make sure we don't have BufLeave autocmd.
|
||||||
|
vim.cmd(string.format([[ autocmd! PickerInsert BufLeave <buffer=%s> ]], status.prompt_bufnr))
|
||||||
local prompt_win = status.prompt_win
|
local prompt_win = status.prompt_win
|
||||||
local results_win = status.results_win
|
local results_win = status.results_win
|
||||||
local preview_win = status.preview_win
|
local preview_win = status.preview_win
|
||||||
@@ -646,42 +691,22 @@ function Picker.close_windows(status)
|
|||||||
local results_border_win = status.results_border_win
|
local results_border_win = status.results_border_win
|
||||||
local preview_border_win = status.preview_border_win
|
local preview_border_win = status.preview_border_win
|
||||||
|
|
||||||
local function del_win(name, win_id, force, bdelete)
|
utils.win_delete("prompt_win", prompt_win, true, true)
|
||||||
if win_id == nil or not vim.api.nvim_win_is_valid(win_id) then
|
utils.win_delete("results_win", results_win, true, true)
|
||||||
return
|
utils.win_delete("preview_win", preview_win, true, true)
|
||||||
end
|
|
||||||
|
|
||||||
local bufnr = vim.api.nvim_win_get_buf(win_id)
|
utils.win_delete("prompt_border_win", prompt_border_win, true, true)
|
||||||
if bdelete and vim.api.nvim_buf_is_valid(bufnr) and not vim.api.nvim_buf_get_option(bufnr, "buflisted") then
|
utils.win_delete("results_border_win", results_border_win, true, true)
|
||||||
vim.cmd(string.format("silent! bdelete! %s", bufnr))
|
utils.win_delete("preview_border_win", preview_border_win, true, true)
|
||||||
end
|
|
||||||
|
|
||||||
if not vim.api.nvim_win_is_valid(win_id) then
|
-- Buffers should be deleted but it may be also the case that buffer was swapped in window
|
||||||
return
|
-- so make sure that buffers created in Picker are deleted.
|
||||||
end
|
utils.buf_delete(status.prompt_bufnr)
|
||||||
|
utils.buf_delete(status.results_bufnr)
|
||||||
if not pcall(vim.api.nvim_win_close, win_id, force) then
|
utils.buf_delete(status.preview_bufnr)
|
||||||
log.trace("Unable to close window: ", name, "/", win_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
del_win("prompt_win", prompt_win, true)
|
|
||||||
del_win("results_win", results_win, true, true)
|
|
||||||
del_win("preview_win", preview_win, true, true)
|
|
||||||
|
|
||||||
del_win("prompt_border_win", prompt_border_win, true, true)
|
|
||||||
del_win("results_border_win", results_border_win, true, true)
|
|
||||||
del_win("preview_border_win", preview_border_win, true, true)
|
|
||||||
|
|
||||||
-- vim.cmd(string.format("bdelete! %s", status.prompt_bufnr))
|
-- vim.cmd(string.format("bdelete! %s", status.prompt_bufnr))
|
||||||
|
|
||||||
-- Major hack?? Why do I have to od this.
|
|
||||||
-- Probably because we're currently IN the buffer.
|
|
||||||
-- Should wait to do this until after we're done.
|
|
||||||
vim.defer_fn(function()
|
|
||||||
del_win("prompt_win", prompt_win, true)
|
|
||||||
end, 10)
|
|
||||||
|
|
||||||
state.clear_status(status.prompt_bufnr)
|
state.clear_status(status.prompt_bufnr)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -907,7 +932,11 @@ end
|
|||||||
|
|
||||||
function Picker:refresh_previewer()
|
function Picker:refresh_previewer()
|
||||||
local status = state.get_status(self.prompt_bufnr)
|
local status = state.get_status(self.prompt_bufnr)
|
||||||
if status.preview_win and self.previewer then
|
if not self._selection_entry then
|
||||||
|
-- if selection_entry is nil there is nothing to be previewed
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if self.previewer and status.preview_win and a.nvim_win_is_valid(status.preview_win) then
|
||||||
self:_increment "previewed"
|
self:_increment "previewed"
|
||||||
|
|
||||||
self.previewer:preview(self._selection_entry, status)
|
self.previewer:preview(self._selection_entry, status)
|
||||||
@@ -938,8 +967,12 @@ function Picker:cycle_previewers(next)
|
|||||||
self.current_previewer_index = size
|
self.current_previewer_index = size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.previewer then
|
||||||
self.previewer = self.all_previewers[self.current_previewer_index]
|
self.previewer = self.all_previewers[self.current_previewer_index]
|
||||||
self:refresh_previewer()
|
self:refresh_previewer()
|
||||||
|
elseif self.hidden_previewer then
|
||||||
|
self.hidden_previewer = self.all_previewers[self.current_previewer_index]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Picker:entry_adder(index, entry, _, insert)
|
function Picker:entry_adder(index, entry, _, insert)
|
||||||
@@ -1207,6 +1240,13 @@ pickers.new = function(opts, defaults)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if result["previewer"] == false then
|
||||||
|
result["previewer"] = defaults["previewer"]
|
||||||
|
result["__hide_previewer"] = true
|
||||||
|
elseif type(opts["preview"]) == "table" and opts["preview"]["hide_on_startup"] then
|
||||||
|
result["__hide_previewer"] = true
|
||||||
|
end
|
||||||
|
|
||||||
return Picker:new(result)
|
return Picker:new(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1253,8 +1293,10 @@ function pickers.on_close_prompt(prompt_bufnr)
|
|||||||
picker.sorter:_destroy()
|
picker.sorter:_destroy()
|
||||||
end
|
end
|
||||||
|
|
||||||
if picker.previewer then
|
if picker.all_previewers then
|
||||||
picker.previewer:teardown()
|
for _, v in ipairs(picker.all_previewers) do
|
||||||
|
v:teardown()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if picker.finder then
|
if picker.finder then
|
||||||
@@ -1264,20 +1306,6 @@ function pickers.on_close_prompt(prompt_bufnr)
|
|||||||
picker.close_windows(status)
|
picker.close_windows(status)
|
||||||
end
|
end
|
||||||
|
|
||||||
local update_scroll = function(win, oldinfo, oldcursor, strategy, max_results)
|
|
||||||
if strategy == "ascending" then
|
|
||||||
vim.api.nvim_win_set_cursor(win, { max_results, 0 })
|
|
||||||
vim.api.nvim_win_set_cursor(win, { oldinfo.topline, 0 })
|
|
||||||
vim.api.nvim_win_set_cursor(win, oldcursor)
|
|
||||||
elseif strategy == "descending" then
|
|
||||||
vim.api.nvim_win_set_cursor(win, { 1, 0 })
|
|
||||||
vim.api.nvim_win_set_cursor(win, { oldinfo.botline, 0 })
|
|
||||||
vim.api.nvim_win_set_cursor(win, oldcursor)
|
|
||||||
else
|
|
||||||
error(debug.traceback("Unknown sorting strategy: " .. (strategy or "")))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function pickers.on_resize_window(prompt_bufnr)
|
function pickers.on_resize_window(prompt_bufnr)
|
||||||
local status = state.get_status(prompt_bufnr)
|
local status = state.get_status(prompt_bufnr)
|
||||||
local picker = status.picker
|
local picker = status.picker
|
||||||
|
|||||||
@@ -438,6 +438,25 @@ function utils.buf_delete(bufnr)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function utils.win_delete(name, win_id, force, bdelete)
|
||||||
|
if win_id == nil or not vim.api.nvim_win_is_valid(win_id) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local bufnr = vim.api.nvim_win_get_buf(win_id)
|
||||||
|
if bdelete then
|
||||||
|
utils.buf_delete(bufnr)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not vim.api.nvim_win_is_valid(win_id) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not pcall(vim.api.nvim_win_close, win_id, force) then
|
||||||
|
log.trace("Unable to close window: ", name, "/", win_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function utils.max_split(s, pattern, maxsplit)
|
function utils.max_split(s, pattern, maxsplit)
|
||||||
pattern = pattern or " "
|
pattern = pattern or " "
|
||||||
maxsplit = maxsplit or -1
|
maxsplit = maxsplit or -1
|
||||||
|
|||||||
Reference in New Issue
Block a user