feat: recalculate picker layout on VimResized (#959)

* WIP: recalculate picker layout on `VimResized`

* refactor: `popup.resize` -> `popup.move`

* fix: scroll to the correct place after resize

* fix: update positioning in results buffer

* fix: completely redraw results buffer on resize

* fix: handle preview enable/disable

* fix: work with scrolling

* docs: add plan for `toggle_padding`

* refactor: factor out creation of picker windows

* refactor: pass highlights directly to popup_create

* refactor: remove lines update and factor out scroll repositioning

Co-authored-by: Github Actions <actions@github>
This commit is contained in:
Luke Kershaw
2021-10-20 11:06:10 +01:00
committed by GitHub
parent 9cad3a4a5d
commit adfbd616c6
2 changed files with 142 additions and 45 deletions

View File

@@ -774,7 +774,7 @@ builtin.treesitter() *builtin.treesitter()*
hl_group hl_group
builtin.current_buffer_fuzzy_find({opts})*builtin.current_buffer_fuzzy_find()* builtin.current_buffer_fuzzy_find({opts}) *builtin.current_buffer_fuzzy_find()*
Live fuzzy search inside of the currently open buffer Live fuzzy search inside of the currently open buffer
@@ -1390,7 +1390,7 @@ builtin.lsp_workspace_symbols({opts}) *builtin.lsp_workspace_symbols()*
with hl_group with hl_group
builtin.lsp_dynamic_workspace_symbols({opts})*builtin.lsp_dynamic_workspace_symbols()* builtin.lsp_dynamic_workspace_symbols({opts}) *builtin.lsp_dynamic_workspace_symbols()*
Dynamically lists LSP for all workspace symbols Dynamically lists LSP for all workspace symbols
- Default keymaps: - Default keymaps:
- `<C-l>`: show autocompletion menu to prefilter your query by type of - `<C-l>`: show autocompletion menu to prefilter your query by type of
@@ -1439,7 +1439,7 @@ builtin.lsp_document_diagnostics({opts}) *builtin.lsp_document_diagnostics()*
in Results in Results
builtin.lsp_workspace_diagnostics({opts})*builtin.lsp_workspace_diagnostics()* builtin.lsp_workspace_diagnostics({opts}) *builtin.lsp_workspace_diagnostics()*
Lists LSP diagnostics for the current workspace if supported, otherwise Lists LSP diagnostics for the current workspace if supported, otherwise
searches in all open buffers searches in all open buffers
- Fields: - Fields:
@@ -1782,7 +1782,7 @@ actions.move_selection_next({prompt_bufnr}) *actions.move_selection_next()*
{prompt_bufnr} (number) The prompt bufnr {prompt_bufnr} (number) The prompt bufnr
actions.move_selection_previous({prompt_bufnr})*actions.move_selection_previous()* actions.move_selection_previous({prompt_bufnr}) *actions.move_selection_previous()*
Move the selection to the previous entry Move the selection to the previous entry
@@ -1798,7 +1798,7 @@ actions.move_selection_worse({prompt_bufnr}) *actions.move_selection_worse()*
{prompt_bufnr} (number) The prompt bufnr {prompt_bufnr} (number) The prompt bufnr
actions.move_selection_better({prompt_bufnr})*actions.move_selection_better()* actions.move_selection_better({prompt_bufnr}) *actions.move_selection_better()*
Move the selection to the entry that has a better score Move the selection to the entry that has a better score
@@ -2067,7 +2067,7 @@ actions.delete_buffer({prompt_bufnr}) *actions.delete_buffer()*
{prompt_bufnr} (number) The prompt bufnr {prompt_bufnr} (number) The prompt bufnr
actions.cycle_previewers_next({prompt_bufnr})*actions.cycle_previewers_next()* actions.cycle_previewers_next({prompt_bufnr}) *actions.cycle_previewers_next()*
Cycle to the next previewer if there is one available. Cycle to the next previewer if there is one available.
This action is not mapped on default. This action is not mapped on default.
@@ -2076,7 +2076,7 @@ actions.cycle_previewers_next({prompt_bufnr})*actions.cycle_previewers_next()*
{prompt_bufnr} (number) The prompt bufnr {prompt_bufnr} (number) The prompt bufnr
actions.cycle_previewers_prev({prompt_bufnr})*actions.cycle_previewers_prev()* actions.cycle_previewers_prev({prompt_bufnr}) *actions.cycle_previewers_prev()*
Cycle to the previous previewer if there is one available. Cycle to the previous previewer if there is one available.
This action is not mapped on default. This action is not mapped on default.
@@ -2085,7 +2085,7 @@ 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()* actions.remove_selected_picker({prompt_bufnr}) *actions.remove_selected_picker()*
Removes the selected picker in |builtin.pickers|. Removes the selected picker in |builtin.pickers|.
This action is not mapped by default and only intended for This action is not mapped by default and only intended for
|builtin.pickers|. |builtin.pickers|.
@@ -2125,7 +2125,7 @@ action_state.get_current_line() *action_state.get_current_line()*
action_state.get_current_picker({prompt_bufnr})*action_state.get_current_picker()* action_state.get_current_picker({prompt_bufnr}) *action_state.get_current_picker()*
Gets the current picker Gets the current picker
@@ -2145,7 +2145,7 @@ vertical split, etc. Instead of making users have to overwrite EACH of those
every time they want to change this behavior, they can instead replace the every time they want to change this behavior, they can instead replace the
`set` itself and then it will work great and they're done. `set` itself and then it will work great and they're done.
action_set.shift_selection({prompt_bufnr}, {change})*action_set.shift_selection()* action_set.shift_selection({prompt_bufnr}, {change}) *action_set.shift_selection()*
Move the current selection of a picker {change} rows. Handles not Move the current selection of a picker {change} rows. Handles not
overflowing / underflowing the list. overflowing / underflowing the list.
@@ -2176,7 +2176,7 @@ action_set.edit({prompt_bufnr}, {command}) *action_set.edit()*
{command} (string) The command to use to open the file. {command} (string) The command to use to open the file.
action_set.scroll_previewer({prompt_bufnr}, {direction})*action_set.scroll_previewer()* action_set.scroll_previewer({prompt_bufnr}, {direction}) *action_set.scroll_previewer()*
Scrolls the previewer up or down Scrolls the previewer up or down
@@ -2255,7 +2255,7 @@ utils.map_selections({prompt_bufnr}, {f}) *utils.map_selections()*
that takes (selection) as a viable argument that takes (selection) as a viable argument
utils.get_registered_mappings({prompt_bufnr})*utils.get_registered_mappings()* utils.get_registered_mappings({prompt_bufnr}) *utils.get_registered_mappings()*
Utility to collect mappings of prompt buffer in array of `{mode, keybind, Utility to collect mappings of prompt buffer in array of `{mode, keybind,
name}`. name}`.
@@ -2571,7 +2571,7 @@ previewers.new_buffer_previewer() *previewers.new_buffer_previewer()*
previewers.buffer_previewer_maker({filepath}, {bufnr}, {opts})*previewers.buffer_previewer_maker()* previewers.buffer_previewer_maker({filepath}, {bufnr}, {opts}) *previewers.buffer_previewer_maker()*
A universal way of reading a file into a buffer previewer. It handles async A universal way of reading a file into a buffer previewer. It handles async
reading, cache, highlighting, displaying directories and provides a reading, cache, highlighting, displaying directories and provides a
callback which can be used, to jump to a line in the buffer. callback which can be used, to jump to a line in the buffer.
@@ -2627,7 +2627,7 @@ previewers.git_stash_diff() *previewers.git_stash_diff()*
previewers.git_commit_diff_to_parent()*previewers.git_commit_diff_to_parent()* previewers.git_commit_diff_to_parent() *previewers.git_commit_diff_to_parent()*
A previewer that shows a diff of a commit to a parent commit. A previewer that shows a diff of a commit to a parent commit.
The run command is `git --no-pager diff SHA^! -- $CURRENT_FILE` The run command is `git --no-pager diff SHA^! -- $CURRENT_FILE`
@@ -2735,7 +2735,7 @@ histories.History:reset() *histories.History:reset()*
histories.History:append({line}, {picker}, {no_reset})*histories.History:append()* histories.History:append({line}, {picker}, {no_reset}) *histories.History:append()*
Append a new line to the history Append a new line to the history

View File

@@ -266,6 +266,18 @@ function Picker:_next_find_id()
return find_id return find_id
end end
function Picker:_create_window(bufnr, popup_opts, nowrap)
local what = bufnr or ""
local win, opts = popup.create(what, popup_opts)
a.nvim_win_set_option(win, "winblend", self.window.winblend)
if nowrap then
a.nvim_win_set_option(win, "wrap", false)
end
local border_win = opts and opts.border and opts.border.win_id
return win, opts, border_win
end
function Picker:find() function Picker:find()
self:close_existing_pickers() self:close_existing_pickers()
self:reset_selection() self:reset_selection()
@@ -288,48 +300,35 @@ function Picker:find()
-- `popup.nvim` massaging so people don't have to remember minheight shenanigans -- `popup.nvim` massaging so people don't have to remember minheight shenanigans
popup_opts.results.minheight = popup_opts.results.height popup_opts.results.minheight = popup_opts.results.height
popup_opts.results.highlight = "TelescopeNormal"
popup_opts.results.borderhighlight = "TelescopeResultsBorder"
popup_opts.prompt.minheight = popup_opts.prompt.height popup_opts.prompt.minheight = popup_opts.prompt.height
popup_opts.prompt.highlight = "TelescopeNormal"
popup_opts.prompt.borderhighlight = "TelescopePromptBorder"
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.borderhighlight = "TelescopePreviewBorder"
end end
local results_win, results_opts = popup.create("", popup_opts.results) -- local results_win, results_opts = popup.create("", popup_opts.results)
local results_win, _, 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)
self.results_bufnr = results_bufnr self.results_bufnr = results_bufnr
self.results_win = results_win self.results_win = results_win
-- TODO: Should probably always show all the line for results win, so should implement a resize for the windows local preview_win, preview_opts, preview_bufnr, preview_border_win
a.nvim_win_set_option(results_win, "wrap", false)
a.nvim_win_set_option(results_win, "winhl", "Normal:TelescopeNormal")
a.nvim_win_set_option(results_win, "winblend", self.window.winblend)
local results_border_win = results_opts.border and results_opts.border.win_id
if results_border_win then
vim.api.nvim_win_set_option(results_border_win, "winhl", "Normal:TelescopeResultsBorder")
end
local preview_win, preview_opts, preview_bufnr
if popup_opts.preview then if popup_opts.preview then
preview_win, preview_opts = popup.create("", popup_opts.preview) preview_win, preview_opts, preview_border_win = self:_create_window("", popup_opts.preview)
preview_bufnr = a.nvim_win_get_buf(preview_win) preview_bufnr = a.nvim_win_get_buf(preview_win)
a.nvim_win_set_option(preview_win, "winhl", "Normal:TelescopePreviewNormal")
a.nvim_win_set_option(preview_win, "winblend", self.window.winblend)
local preview_border_win = preview_opts and preview_opts.border and preview_opts.border.win_id
if preview_border_win then
vim.api.nvim_win_set_option(preview_border_win, "winhl", "Normal:TelescopePreviewBorder")
end
end end
-- This is needed for updating the title
local preview_border = preview_opts and preview_opts.border
self.preview_border = preview_border
-- TODO: We need to center this and make it prettier... local prompt_win, _, prompt_border_win = self:_create_window("", popup_opts.prompt)
local prompt_win, prompt_opts = popup.create("", popup_opts.prompt)
local prompt_bufnr = a.nvim_win_get_buf(prompt_win) local prompt_bufnr = a.nvim_win_get_buf(prompt_win)
a.nvim_win_set_option(prompt_win, "winhl", "Normal:TelescopeNormal")
a.nvim_win_set_option(prompt_win, "winblend", self.window.winblend)
local prompt_border_win = prompt_opts.border and prompt_opts.border.win_id
if prompt_border_win then
vim.api.nvim_win_set_option(prompt_border_win, "winhl", "Normal:TelescopePromptBorder")
end
self.prompt_bufnr = prompt_bufnr self.prompt_bufnr = prompt_bufnr
-- Prompt prefix -- Prompt prefix
@@ -448,14 +447,18 @@ function Picker:find()
prompt_bufnr prompt_bufnr
) )
local on_vim_resize = string.format(
[[ autocmd VimResized <buffer> ++nested :lua require('telescope.pickers').on_resize_window(%s)]],
prompt_bufnr
)
vim.cmd [[augroup PickerInsert]] vim.cmd [[augroup PickerInsert]]
vim.cmd [[ au!]] vim.cmd [[ au!]]
vim.cmd(on_buf_leave) vim.cmd(on_buf_leave)
vim.cmd(on_vim_resize)
vim.cmd [[augroup END]] vim.cmd [[augroup END]]
local preview_border = preview_opts and preview_opts.border self.prompt_bufnr = prompt_bufnr
self.preview_border = preview_border
local preview_border_win = (preview_border and preview_border.win_id) and preview_border.win_id
state.set_status( state.set_status(
prompt_bufnr, prompt_bufnr,
@@ -483,11 +486,78 @@ function Picker:find()
main_loop() main_loop()
end end
function Picker:recalculate_layout()
local line_count = vim.o.lines - vim.o.cmdheight
if vim.o.laststatus ~= 0 then
line_count = line_count - 1
end
local popup_opts = self:get_window_options(vim.o.columns, line_count)
-- `popup.nvim` massaging so people don't have to remember minheight shenanigans
popup_opts.results.minheight = popup_opts.results.height
popup_opts.prompt.minheight = popup_opts.prompt.height
if popup_opts.preview then
popup_opts.preview.minheight = popup_opts.preview.height
end
local status = state.get_status(self.prompt_bufnr)
local prompt_win = status.prompt_win
local results_win = status.results_win
local preview_win = status.preview_win
popup.move(results_win, popup_opts.results)
local preview_opts, preview_border_win
if popup_opts.preview then
if preview_win ~= nil then
popup.move(preview_win, popup_opts.preview)
else
popup_opts.preview.highlight = "TelescopeNormal"
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
preview_win, preview_opts, preview_border_win = self:_create_window("", popup_opts.preview)
status.preview_win = preview_win
status.preview_border_win = preview_border_win
state.set_status(prompt_win, status)
self.preview_win = preview_win
self.preview_border_win = preview_border_win
self.preview_border = preview_opts and preview_opts.border
end
elseif preview_win ~= nil then
vim.api.nvim_win_close(preview_win, false)
if status.preview_border_win then
vim.api.nvim_win_close(status.preview_border_win, false)
end
status.preview_win = nil
status.preview_border_win = nil
state.set_status(prompt_win, status)
self.preview_win = nil
self.preview_border_win = nil
self.preview_border = nil
end
popup.move(prompt_win, popup_opts.prompt)
-- Temporarily disabled: Draw the screen ASAP. This makes things feel speedier.
-- vim.cmd [[redraw]]
-- self.max_results = popup_opts.results.height
end
function Picker:hide_preview() function Picker:hide_preview()
-- 1. Hide the window (and border) -- 1. Hide the window (and border)
-- 2. Resize prompt & results windows accordingly -- 2. Resize prompt & results windows accordingly
end end
function Picker:toggle_padding()
-- if padding ~= 0
-- 1. Save `height` and `width` of picker
-- 2. Set both to `{padding = 0}`
-- else
-- 1. Lookup previous `height` and `width` of picker
-- 2. Set both to previous values
end
-- TODO: update multi-select with the correct tag name when available -- TODO: update multi-select with the correct tag name when available
--- A simple interface to remove an entry from the results window without --- A simple interface to remove an entry from the results window without
--- closing telescope. This either deletes the current selection or all the --- closing telescope. This either deletes the current selection or all the
@@ -1172,6 +1242,33 @@ 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)
local status = state.get_status(prompt_bufnr)
local picker = status.picker
local oldinfo = vim.fn.getwininfo(status.results_win)[1]
local oldcursor = vim.api.nvim_win_get_cursor(status.results_win)
picker:recalculate_layout()
picker:refresh_previewer()
-- update scrolled position
update_scroll(status.results_win, oldinfo, oldcursor, picker.sorting_strategy, picker.max_results)
end
--- Get the prompt text without the prompt prefix. --- Get the prompt text without the prompt prefix.
function Picker:_get_prompt() function Picker:_get_prompt()
return vim.api.nvim_buf_get_lines(self.prompt_bufnr, 0, 1, false)[1]:sub(#self.prompt_prefix + 1) return vim.api.nvim_buf_get_lines(self.prompt_bufnr, 0, 1, false)[1]:sub(#self.prompt_prefix + 1)