feat(pickers): fully customizable layout (#2572)
This commit is contained in:
@@ -146,6 +146,13 @@ telescope.setup({opts}) *telescope.setup()*
|
|||||||
|
|
||||||
Default: 'horizontal'
|
Default: 'horizontal'
|
||||||
|
|
||||||
|
*telescope.defaults.create_layout*
|
||||||
|
create_layout: ~
|
||||||
|
Configure the layout of Telescope pickers.
|
||||||
|
See |telescope.pickers.layout| for details.
|
||||||
|
|
||||||
|
Default: 'nil'
|
||||||
|
|
||||||
*telescope.defaults.layout_config*
|
*telescope.defaults.layout_config*
|
||||||
layout_config: ~
|
layout_config: ~
|
||||||
Determines the default configuration values for layout strategies.
|
Determines the default configuration values for layout strategies.
|
||||||
@@ -1947,6 +1954,155 @@ ordered from the lowest priority to the highest priority.
|
|||||||
<
|
<
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
LAYOUT *telescope.pickers.layout*
|
||||||
|
|
||||||
|
The telescope pickers layout can be configured using the
|
||||||
|
|telescope.defaults.create_layout| option.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
- picker : A Picker object.
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
- layout : instance of `TelescopeLayout` class.
|
||||||
|
|
||||||
|
Example: ~
|
||||||
|
>
|
||||||
|
local Layout = require "telescope.pickers.layout"
|
||||||
|
|
||||||
|
require("telescope").setup {
|
||||||
|
create_layout = function(picker)
|
||||||
|
local function create_window(enter, width, height, row, col, title)
|
||||||
|
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||||
|
local winid = vim.api.nvim_open_win(bufnr, enter, {
|
||||||
|
style = "minimal",
|
||||||
|
relative = "editor",
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
row = row,
|
||||||
|
col = col,
|
||||||
|
border = "single",
|
||||||
|
title = title,
|
||||||
|
})
|
||||||
|
|
||||||
|
vim.wo[winid].winhighlight = "Normal:Normal"
|
||||||
|
|
||||||
|
return Layout.Window {
|
||||||
|
bufnr = bufnr,
|
||||||
|
winid = winid,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function destory_window(window)
|
||||||
|
if window then
|
||||||
|
if vim.api.nvim_win_is_valid(window.winid) then
|
||||||
|
vim.api.nvim_win_close(window.winid, true)
|
||||||
|
end
|
||||||
|
if vim.api.nvim_buf_is_valid(window.bufnr) then
|
||||||
|
vim.api.nvim_buf_delete(window.bufnr, { force = true })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local layout = Layout {
|
||||||
|
picker = picker,
|
||||||
|
mount = function(self)
|
||||||
|
self.results = create_window(false, 40, 20, 0, 0, "Results")
|
||||||
|
self.preview = create_window(false, 40, 23, 0, 42, "Preview")
|
||||||
|
self.prompt = create_window(true, 40, 1, 22, 0, "Prompt")
|
||||||
|
end,
|
||||||
|
unmount = function(self)
|
||||||
|
destory_window(self.results)
|
||||||
|
destory_window(self.preview)
|
||||||
|
destory_window(self.prompt)
|
||||||
|
end,
|
||||||
|
update = function(self) end,
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
<
|
||||||
|
|
||||||
|
TelescopeWindowBorder.config *TelescopeWindowBorder.config*
|
||||||
|
|
||||||
|
|
||||||
|
Fields: ~
|
||||||
|
{bufnr} (integer)
|
||||||
|
{winid} (integer|nil)
|
||||||
|
{change_title} (nil|function) (self: TelescopeWindowBorder, title:
|
||||||
|
string, pos?:
|
||||||
|
"NW"|"N"|"NE"|"SW"|"S"|"SE"):nil
|
||||||
|
|
||||||
|
|
||||||
|
TelescopeWindowBorder *TelescopeWindowBorder*
|
||||||
|
|
||||||
|
|
||||||
|
Fields: ~
|
||||||
|
{bufnr} (integer|nil)
|
||||||
|
{winid} (integer|nil)
|
||||||
|
|
||||||
|
|
||||||
|
TelescopeWindow.config *TelescopeWindow.config*
|
||||||
|
|
||||||
|
|
||||||
|
Fields: ~
|
||||||
|
{bufnr} (integer)
|
||||||
|
{winid} (integer|nil)
|
||||||
|
{border} (TelescopeWindowBorder.config|nil)
|
||||||
|
|
||||||
|
|
||||||
|
TelescopeWindow *TelescopeWindow*
|
||||||
|
|
||||||
|
|
||||||
|
Fields: ~
|
||||||
|
{border} (TelescopeWindowBorder)
|
||||||
|
{bufnr} (integer)
|
||||||
|
{winid} (integer)
|
||||||
|
|
||||||
|
|
||||||
|
TelescopeLayout.config *TelescopeLayout.config*
|
||||||
|
|
||||||
|
|
||||||
|
Fields: ~
|
||||||
|
{mount} (function) (self: TelescopeLayout):nil
|
||||||
|
{unmount} (function) (self: TelescopeLayout):nil
|
||||||
|
{update} (function) (self: TelescopeLayout):nil
|
||||||
|
{prompt} (TelescopeWindow|nil)
|
||||||
|
{results} (TelescopeWindow|nil)
|
||||||
|
{preview} (TelescopeWindow|nil)
|
||||||
|
|
||||||
|
|
||||||
|
TelescopeLayout *TelescopeLayout*
|
||||||
|
|
||||||
|
|
||||||
|
Fields: ~
|
||||||
|
{prompt} (TelescopeWindow)
|
||||||
|
{results} (TelescopeWindow)
|
||||||
|
{preview} (TelescopeWindow|nil)
|
||||||
|
|
||||||
|
|
||||||
|
Layout:mount() *telescope.pickers.layout:mount()*
|
||||||
|
Create the layout. This needs to ensure the required properties are
|
||||||
|
populated.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Layout:unmount() *telescope.pickers.layout:unmount()*
|
||||||
|
Destroy the layout. This is responsible for performing clean-up, for
|
||||||
|
example:
|
||||||
|
- deleting buffers
|
||||||
|
- closing windows
|
||||||
|
- clearing autocmds
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Layout:update() *telescope.pickers.layout:update()*
|
||||||
|
Refresh the layout. This is called when, for example, vim is resized.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
LAYOUT *telescope.layout*
|
LAYOUT *telescope.layout*
|
||||||
|
|
||||||
|
|||||||
@@ -75,12 +75,12 @@ action_generate.refine = function(prompt_bufnr, opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- title
|
-- title
|
||||||
if opts.prompt_title and current_picker.prompt_border then
|
if opts.prompt_title and current_picker.layout.prompt.border then
|
||||||
current_picker.prompt_border:change_title(opts.prompt_title)
|
current_picker.layout.prompt.border:change_title(opts.prompt_title)
|
||||||
end
|
end
|
||||||
|
|
||||||
if opts.results_title and current_picker.results_border then
|
if opts.results_title and current_picker.layout.results.border then
|
||||||
current_picker.results_border:change_title(opts.results_title)
|
current_picker.layout.results.border:change_title(opts.results_title)
|
||||||
end
|
end
|
||||||
|
|
||||||
local results = {}
|
local results = {}
|
||||||
|
|||||||
@@ -26,10 +26,11 @@ action_layout.toggle_preview = function(prompt_bufnr)
|
|||||||
local picker = action_state.get_current_picker(prompt_bufnr)
|
local picker = action_state.get_current_picker(prompt_bufnr)
|
||||||
local status = state.get_status(picker.prompt_bufnr)
|
local status = state.get_status(picker.prompt_bufnr)
|
||||||
|
|
||||||
if picker.previewer and status.preview_win then
|
local preview_winid = status.layout.preview and status.layout.preview.winid
|
||||||
|
if picker.previewer and preview_winid then
|
||||||
picker.hidden_previewer = picker.previewer
|
picker.hidden_previewer = picker.previewer
|
||||||
picker.previewer = nil
|
picker.previewer = nil
|
||||||
elseif picker.hidden_previewer and not status.preview_win then
|
elseif picker.hidden_previewer and not preview_winid then
|
||||||
picker.previewer = picker.hidden_previewer
|
picker.previewer = picker.hidden_previewer
|
||||||
picker.hidden_previewer = nil
|
picker.hidden_previewer = nil
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -230,12 +230,13 @@ action_set.scroll_previewer = function(prompt_bufnr, direction)
|
|||||||
local previewer = action_state.get_current_picker(prompt_bufnr).previewer
|
local previewer = action_state.get_current_picker(prompt_bufnr).previewer
|
||||||
local status = state.get_status(prompt_bufnr)
|
local status = state.get_status(prompt_bufnr)
|
||||||
|
|
||||||
|
local preview_winid = status.layout.preview and status.layout.preview.winid
|
||||||
-- Check if we actually have a previewer and a preview window
|
-- Check if we actually have a previewer and a preview window
|
||||||
if type(previewer) ~= "table" or previewer.scroll_fn == nil or status.preview_win == nil then
|
if type(previewer) ~= "table" or previewer.scroll_fn == nil or preview_winid == nil then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local default_speed = vim.api.nvim_win_get_height(status.preview_win) / 2
|
local default_speed = vim.api.nvim_win_get_height(status.layout.preview.winid) / 2
|
||||||
local speed = status.picker.layout_config.scroll_speed or default_speed
|
local speed = status.picker.layout_config.scroll_speed or default_speed
|
||||||
|
|
||||||
previewer:scroll_fn(math.floor(speed * direction))
|
previewer:scroll_fn(math.floor(speed * direction))
|
||||||
@@ -270,12 +271,12 @@ end
|
|||||||
-- Valid directions include: "1", "-1"
|
-- Valid directions include: "1", "-1"
|
||||||
action_set.scroll_results = function(prompt_bufnr, direction)
|
action_set.scroll_results = function(prompt_bufnr, direction)
|
||||||
local status = state.get_status(prompt_bufnr)
|
local status = state.get_status(prompt_bufnr)
|
||||||
local default_speed = vim.api.nvim_win_get_height(status.results_win) / 2
|
local default_speed = vim.api.nvim_win_get_height(status.layout.results.winid) / 2
|
||||||
local speed = status.picker.layout_config.scroll_speed or default_speed
|
local speed = status.picker.layout_config.scroll_speed or default_speed
|
||||||
|
|
||||||
local input = direction > 0 and [[]] or [[]]
|
local input = direction > 0 and [[]] or [[]]
|
||||||
|
|
||||||
vim.api.nvim_win_call(status.results_win, function()
|
vim.api.nvim_win_call(status.layout.results.winid, function()
|
||||||
vim.cmd([[normal! ]] .. math.floor(speed) .. input)
|
vim.cmd([[normal! ]] .. math.floor(speed) .. input)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
@@ -991,8 +991,10 @@ internal.colorscheme = function(opts)
|
|||||||
preview_fn = function(_, entry, status)
|
preview_fn = function(_, entry, status)
|
||||||
if not deleted then
|
if not deleted then
|
||||||
deleted = true
|
deleted = true
|
||||||
del_win(status.preview_win)
|
if status.layout.preview then
|
||||||
del_win(status.preview_border_win)
|
del_win(status.layout.preview.winid)
|
||||||
|
del_win(status.layout.preview.border.winid)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
vim.cmd("colorscheme " .. entry.value)
|
vim.cmd("colorscheme " .. entry.value)
|
||||||
end,
|
end,
|
||||||
|
|||||||
@@ -188,6 +188,16 @@ append(
|
|||||||
Default: 'horizontal']]
|
Default: 'horizontal']]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
append(
|
||||||
|
"create_layout",
|
||||||
|
nil,
|
||||||
|
[[
|
||||||
|
Configure the layout of Telescope pickers.
|
||||||
|
See |telescope.pickers.layout| for details.
|
||||||
|
|
||||||
|
Default: 'nil']]
|
||||||
|
)
|
||||||
|
|
||||||
append("layout_config", layout_config_defaults, layout_config_description)
|
append("layout_config", layout_config_defaults, layout_config_description)
|
||||||
|
|
||||||
append(
|
append(
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ local entry_display = require "telescope.pickers.entry_display"
|
|||||||
local p_highlighter = require "telescope.pickers.highlights"
|
local p_highlighter = require "telescope.pickers.highlights"
|
||||||
local p_scroller = require "telescope.pickers.scroller"
|
local p_scroller = require "telescope.pickers.scroller"
|
||||||
local p_window = require "telescope.pickers.window"
|
local p_window = require "telescope.pickers.window"
|
||||||
|
local Layout = require "telescope.pickers.layout"
|
||||||
|
|
||||||
local EntryManager = require "telescope.entry_manager"
|
local EntryManager = require "telescope.entry_manager"
|
||||||
local MultiSelect = require "telescope.pickers.multi"
|
local MultiSelect = require "telescope.pickers.multi"
|
||||||
@@ -31,6 +32,183 @@ local ns_telescope_matching = a.nvim_create_namespace "telescope_matching"
|
|||||||
local ns_telescope_prompt = a.nvim_create_namespace "telescope_prompt"
|
local ns_telescope_prompt = a.nvim_create_namespace "telescope_prompt"
|
||||||
local ns_telescope_prompt_prefix = a.nvim_create_namespace "telescope_prompt_prefix"
|
local ns_telescope_prompt_prefix = a.nvim_create_namespace "telescope_prompt_prefix"
|
||||||
|
|
||||||
|
---@class telescope_popup_options
|
||||||
|
---@field border table<1|2|3|4, integer>
|
||||||
|
---@field borderchars table<1|2|3|4|5|6|7|8, string>
|
||||||
|
---@field borderhighlight string
|
||||||
|
---@field col integer
|
||||||
|
---@field enter boolean
|
||||||
|
---@field height integer
|
||||||
|
---@field highlight string
|
||||||
|
---@field line integer
|
||||||
|
---@field minheight integer
|
||||||
|
---@field title integer
|
||||||
|
---@field titlehighlight integer
|
||||||
|
---@field width integer
|
||||||
|
|
||||||
|
-- Create three windows:
|
||||||
|
-- 1. Prompt window
|
||||||
|
-- 2. Options window
|
||||||
|
-- 3. Preview window
|
||||||
|
--
|
||||||
|
---@param picker Picker
|
||||||
|
local function default_create_layout(picker)
|
||||||
|
local function make_border(border)
|
||||||
|
if not border then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
border.winid = border.win_id
|
||||||
|
return border
|
||||||
|
end
|
||||||
|
|
||||||
|
local layout = Layout {
|
||||||
|
picker = picker,
|
||||||
|
---@param self TelescopeLayout
|
||||||
|
mount = function(self)
|
||||||
|
local line_count = vim.o.lines - vim.o.cmdheight
|
||||||
|
if vim.o.laststatus ~= 0 then
|
||||||
|
line_count = line_count - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local popup_opts = picker: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.results.highlight = "TelescopeResultsNormal"
|
||||||
|
popup_opts.results.borderhighlight = "TelescopeResultsBorder"
|
||||||
|
popup_opts.results.titlehighlight = "TelescopeResultsTitle"
|
||||||
|
popup_opts.prompt.minheight = popup_opts.prompt.height
|
||||||
|
popup_opts.prompt.highlight = "TelescopePromptNormal"
|
||||||
|
popup_opts.prompt.borderhighlight = "TelescopePromptBorder"
|
||||||
|
popup_opts.prompt.titlehighlight = "TelescopePromptTitle"
|
||||||
|
if popup_opts.preview then
|
||||||
|
popup_opts.preview.minheight = popup_opts.preview.height
|
||||||
|
popup_opts.preview.highlight = "TelescopePreviewNormal"
|
||||||
|
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
|
||||||
|
popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
|
||||||
|
end
|
||||||
|
|
||||||
|
local results_win, results_opts = picker:_create_window("", popup_opts.results)
|
||||||
|
local results_bufnr = a.nvim_win_get_buf(results_win)
|
||||||
|
|
||||||
|
self.results = Layout.Window {
|
||||||
|
winid = results_win,
|
||||||
|
bufnr = results_bufnr,
|
||||||
|
border = make_border(results_opts.border),
|
||||||
|
}
|
||||||
|
|
||||||
|
if popup_opts.preview then
|
||||||
|
local preview_win, preview_opts = picker:_create_window("", popup_opts.preview)
|
||||||
|
local preview_bufnr = a.nvim_win_get_buf(preview_win)
|
||||||
|
|
||||||
|
self.preview = Layout.Window {
|
||||||
|
winid = preview_win,
|
||||||
|
bufnr = preview_bufnr,
|
||||||
|
border = make_border(preview_opts.border),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local prompt_win, prompt_opts = picker:_create_window("", popup_opts.prompt)
|
||||||
|
local prompt_bufnr = a.nvim_win_get_buf(prompt_win)
|
||||||
|
|
||||||
|
self.prompt = Layout.Window {
|
||||||
|
winid = prompt_win,
|
||||||
|
bufnr = prompt_bufnr,
|
||||||
|
border = make_border(prompt_opts.border),
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
---@param self TelescopeLayout
|
||||||
|
unmount = function(self)
|
||||||
|
utils.win_delete("results_win", self.results.winid, true, true)
|
||||||
|
if self.preview then
|
||||||
|
utils.win_delete("preview_win", self.preview.winid, true, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
utils.win_delete("prompt_border_win", self.prompt.border.winid, true, true)
|
||||||
|
utils.win_delete("results_border_win", self.results.border.winid, true, true)
|
||||||
|
if self.preview then
|
||||||
|
utils.win_delete("preview_border_win", self.preview.border.winid, true, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we cant use win_delete. We first need to close and then delete the buffer
|
||||||
|
if vim.api.nvim_win_is_valid(self.prompt.winid) then
|
||||||
|
vim.api.nvim_win_close(self.prompt.winid, true)
|
||||||
|
end
|
||||||
|
utils.buf_delete(self.prompt.bufnr)
|
||||||
|
end,
|
||||||
|
---@param self TelescopeLayout
|
||||||
|
update = function(self)
|
||||||
|
local line_count = vim.o.lines - vim.o.cmdheight
|
||||||
|
if vim.o.laststatus ~= 0 then
|
||||||
|
line_count = line_count - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local popup_opts = picker: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 prompt_win = self.prompt.winid
|
||||||
|
local results_win = self.results.winid
|
||||||
|
local preview_win = self.preview and self.preview.winid
|
||||||
|
|
||||||
|
local preview_opts
|
||||||
|
if popup_opts.preview then
|
||||||
|
if preview_win ~= nil then
|
||||||
|
-- Move all popups at the same time
|
||||||
|
popup.move(prompt_win, popup_opts.prompt)
|
||||||
|
popup.move(results_win, popup_opts.results)
|
||||||
|
popup.move(preview_win, popup_opts.preview)
|
||||||
|
else
|
||||||
|
popup_opts.preview.highlight = "TelescopePreviewNormal"
|
||||||
|
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
|
||||||
|
popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
|
||||||
|
local preview_bufnr = (self.preview and self.preview.bufnr ~= nil)
|
||||||
|
and vim.api.nvim_buf_is_valid(self.preview.bufnr)
|
||||||
|
and self.preview.bufnr
|
||||||
|
or ""
|
||||||
|
preview_win, preview_opts = picker:_create_window(preview_bufnr, popup_opts.preview)
|
||||||
|
if preview_bufnr == "" then
|
||||||
|
preview_bufnr = a.nvim_win_get_buf(preview_win)
|
||||||
|
end
|
||||||
|
self.preview = Layout.Window {
|
||||||
|
winid = preview_win,
|
||||||
|
bufnr = preview_bufnr,
|
||||||
|
border = make_border(preview_opts.border),
|
||||||
|
}
|
||||||
|
if picker.previewer and picker.previewer.state and picker.previewer.state.winid then
|
||||||
|
picker.previewer.state.winid = preview_win
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Move prompt and results after preview created
|
||||||
|
vim.defer_fn(function()
|
||||||
|
popup.move(prompt_win, popup_opts.prompt)
|
||||||
|
popup.move(results_win, popup_opts.results)
|
||||||
|
end, 0)
|
||||||
|
end
|
||||||
|
elseif preview_win ~= nil then
|
||||||
|
popup.move(prompt_win, popup_opts.prompt)
|
||||||
|
popup.move(results_win, popup_opts.results)
|
||||||
|
|
||||||
|
-- Remove preview after the prompt and results are moved
|
||||||
|
vim.defer_fn(function()
|
||||||
|
utils.win_delete("preview_win", preview_win, true)
|
||||||
|
utils.win_delete("preview_win", self.preview.border.winid, true)
|
||||||
|
self.preview = nil
|
||||||
|
end, 0)
|
||||||
|
else
|
||||||
|
popup.move(prompt_win, popup_opts.prompt)
|
||||||
|
popup.move(results_win, popup_opts.results)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout
|
||||||
|
end
|
||||||
|
|
||||||
local pickers = {}
|
local pickers = {}
|
||||||
|
|
||||||
-- TODO: Add overscroll option for results buffer
|
-- TODO: Add overscroll option for results buffer
|
||||||
@@ -141,6 +319,7 @@ function Picker:new(opts)
|
|||||||
__scrolling_limit = tonumber(vim.F.if_nil(opts.temp__scrolling_limit, 250)),
|
__scrolling_limit = tonumber(vim.F.if_nil(opts.temp__scrolling_limit, 250)),
|
||||||
}, self)
|
}, self)
|
||||||
|
|
||||||
|
obj.create_layout = opts.create_layout or config.values.create_layout or default_create_layout
|
||||||
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
|
||||||
|
|
||||||
if obj.all_previewers ~= nil and obj.all_previewers ~= false then
|
if obj.all_previewers ~= nil and obj.all_previewers ~= false then
|
||||||
@@ -325,13 +504,11 @@ end
|
|||||||
--- A helper function for creating each of the windows in a picker
|
--- A helper function for creating each of the windows in a picker
|
||||||
---@param bufnr number: the buffer number to be used in the window
|
---@param bufnr number: the buffer number to be used in the window
|
||||||
---@param popup_opts table: options to pass to `popup.create`
|
---@param popup_opts table: options to pass to `popup.create`
|
||||||
---@param nowrap boolean: is |'wrap'| disabled in the created window
|
function Picker:_create_window(bufnr, popup_opts)
|
||||||
function Picker:_create_window(bufnr, popup_opts, nowrap)
|
|
||||||
local what = bufnr or ""
|
local what = bufnr or ""
|
||||||
local win, opts = popup.create(what, popup_opts)
|
local win, opts = popup.create(what, popup_opts)
|
||||||
|
|
||||||
a.nvim_win_set_option(win, "winblend", self.window.winblend)
|
a.nvim_win_set_option(win, "winblend", self.window.winblend)
|
||||||
a.nvim_win_set_option(win, "wrap", not nowrap)
|
|
||||||
local border_win = opts and opts.border and opts.border.win_id
|
local border_win = opts and opts.border and opts.border.win_id
|
||||||
if border_win then
|
if border_win then
|
||||||
a.nvim_win_set_option(border_win, "winblend", self.window.winblend)
|
a.nvim_win_set_option(border_win, "winblend", self.window.winblend)
|
||||||
@@ -350,67 +527,35 @@ function Picker:find()
|
|||||||
-- User autocmd run it before create Telescope window
|
-- User autocmd run it before create Telescope window
|
||||||
vim.api.nvim_exec_autocmds("User", { pattern = "TelescopeFindPre" })
|
vim.api.nvim_exec_autocmds("User", { pattern = "TelescopeFindPre" })
|
||||||
|
|
||||||
-- Create three windows:
|
local layout = self:create_layout()
|
||||||
-- 1. Prompt window
|
layout:mount()
|
||||||
-- 2. Options window
|
|
||||||
-- 3. Preview window
|
|
||||||
|
|
||||||
local line_count = vim.o.lines - vim.o.cmdheight
|
self.layout = layout
|
||||||
if vim.o.laststatus ~= 0 then
|
self.prompt_win, self.prompt_bufnr, self.prompt_border =
|
||||||
line_count = line_count - 1
|
layout.prompt.winid, layout.prompt.bufnr, layout.prompt.border
|
||||||
|
self.results_win, self.results_bufnr, self.results_border =
|
||||||
|
layout.results.winid, layout.results.bufnr, layout.results.border
|
||||||
|
if layout.preview then
|
||||||
|
self.preview_win, self.preview_bufnr, self.preview_border =
|
||||||
|
layout.preview.winid, layout.preview.bufnr, layout.preview.border
|
||||||
|
else
|
||||||
|
self.preview_win, self.preview_bufnr, self.preview_border = nil, nil, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local popup_opts = self:get_window_options(vim.o.columns, line_count)
|
pcall(a.nvim_buf_set_option, self.results_bufnr, "tabstop", 1) -- #1834
|
||||||
|
pcall(a.nvim_buf_set_option, self.prompt_bufnr, "tabstop", 1) -- #1834
|
||||||
-- `popup.nvim` massaging so people don't have to remember minheight shenanigans
|
a.nvim_buf_set_option(self.prompt_bufnr, "buftype", "prompt")
|
||||||
popup_opts.results.minheight = popup_opts.results.height
|
if not self.wrap_results then
|
||||||
popup_opts.results.highlight = "TelescopeResultsNormal"
|
a.nvim_win_set_option(self.results_win, "wrap", false)
|
||||||
popup_opts.results.borderhighlight = "TelescopeResultsBorder"
|
|
||||||
popup_opts.results.titlehighlight = "TelescopeResultsTitle"
|
|
||||||
popup_opts.prompt.minheight = popup_opts.prompt.height
|
|
||||||
popup_opts.prompt.highlight = "TelescopePromptNormal"
|
|
||||||
popup_opts.prompt.borderhighlight = "TelescopePromptBorder"
|
|
||||||
popup_opts.prompt.titlehighlight = "TelescopePromptTitle"
|
|
||||||
if popup_opts.preview then
|
|
||||||
popup_opts.preview.minheight = popup_opts.preview.height
|
|
||||||
popup_opts.preview.highlight = "TelescopePreviewNormal"
|
|
||||||
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
|
|
||||||
popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
|
|
||||||
end
|
end
|
||||||
|
a.nvim_win_set_option(self.prompt_win, "wrap", true)
|
||||||
local results_win, results_opts, results_border_win =
|
if self.preview_win then
|
||||||
self:_create_window("", popup_opts.results, not self.wrap_results)
|
a.nvim_win_set_option(self.preview_win, "wrap", true)
|
||||||
|
|
||||||
local results_bufnr = a.nvim_win_get_buf(results_win)
|
|
||||||
pcall(a.nvim_buf_set_option, results_bufnr, "tabstop", 1) -- #1834
|
|
||||||
|
|
||||||
self.results_bufnr = results_bufnr
|
|
||||||
self.results_win = results_win
|
|
||||||
self.results_border = results_opts and results_opts.border
|
|
||||||
|
|
||||||
local preview_win, preview_opts, preview_bufnr, preview_border_win
|
|
||||||
if popup_opts.preview then
|
|
||||||
preview_win, preview_opts, preview_border_win = self:_create_window("", popup_opts.preview)
|
|
||||||
preview_bufnr = a.nvim_win_get_buf(preview_win)
|
|
||||||
end
|
end
|
||||||
-- This is needed for updating the title
|
|
||||||
local preview_border = preview_opts and preview_opts.border
|
|
||||||
self.preview_win = preview_win
|
|
||||||
self.preview_border = preview_border
|
|
||||||
|
|
||||||
local prompt_win, prompt_opts, prompt_border_win = self:_create_window("", popup_opts.prompt)
|
|
||||||
local prompt_bufnr = a.nvim_win_get_buf(prompt_win)
|
|
||||||
pcall(a.nvim_buf_set_option, prompt_bufnr, "tabstop", 1) -- #1834
|
|
||||||
|
|
||||||
self.prompt_bufnr = prompt_bufnr
|
|
||||||
self.prompt_win = prompt_win
|
|
||||||
self.prompt_border = prompt_opts and prompt_opts.border
|
|
||||||
|
|
||||||
-- Prompt prefix
|
-- Prompt prefix
|
||||||
local prompt_prefix = self.prompt_prefix
|
local prompt_prefix = self.prompt_prefix
|
||||||
a.nvim_buf_set_option(prompt_bufnr, "buftype", "prompt")
|
vim.fn.prompt_setprompt(self.prompt_bufnr, prompt_prefix)
|
||||||
vim.fn.prompt_setprompt(prompt_bufnr, prompt_prefix)
|
|
||||||
self.prompt_prefix = prompt_prefix
|
|
||||||
self:_reset_prefix_color()
|
self:_reset_prefix_color()
|
||||||
|
|
||||||
-- TODO: This could be configurable in the future, but I don't know why you would
|
-- TODO: This could be configurable in the future, but I don't know why you would
|
||||||
@@ -419,9 +564,9 @@ function Picker:find()
|
|||||||
-- This just lets us stop doing stuff after tons of things.
|
-- This just lets us stop doing stuff after tons of things.
|
||||||
self.max_results = self.__scrolling_limit
|
self.max_results = self.__scrolling_limit
|
||||||
|
|
||||||
vim.api.nvim_buf_set_lines(results_bufnr, 0, self.max_results, false, utils.repeated_table(self.max_results, ""))
|
vim.api.nvim_buf_set_lines(self.results_bufnr, 0, self.max_results, false, utils.repeated_table(self.max_results, ""))
|
||||||
|
|
||||||
local status_updater = self:get_status_updater(prompt_win, prompt_bufnr)
|
local status_updater = self:get_status_updater(self.prompt_win, self.prompt_bufnr)
|
||||||
local debounced_status = debounce.throttle_leading(status_updater, 50)
|
local debounced_status = debounce.throttle_leading(status_updater, 50)
|
||||||
|
|
||||||
local tx, rx = channel.mpsc()
|
local tx, rx = channel.mpsc()
|
||||||
@@ -455,8 +600,8 @@ function Picker:find()
|
|||||||
self.sorter:_init()
|
self.sorter:_init()
|
||||||
|
|
||||||
-- Do filetype last, so that users can register at the last second.
|
-- Do filetype last, so that users can register at the last second.
|
||||||
pcall(a.nvim_buf_set_option, prompt_bufnr, "filetype", "TelescopePrompt")
|
pcall(a.nvim_buf_set_option, self.prompt_bufnr, "filetype", "TelescopePrompt")
|
||||||
pcall(a.nvim_buf_set_option, results_bufnr, "filetype", "TelescopeResults")
|
pcall(a.nvim_buf_set_option, self.results_bufnr, "filetype", "TelescopeResults")
|
||||||
|
|
||||||
await_schedule()
|
await_schedule()
|
||||||
|
|
||||||
@@ -471,8 +616,8 @@ function Picker:find()
|
|||||||
|
|
||||||
self:_reset_track()
|
self:_reset_track()
|
||||||
|
|
||||||
if not vim.api.nvim_buf_is_valid(prompt_bufnr) then
|
if not vim.api.nvim_buf_is_valid(self.prompt_bufnr) then
|
||||||
log.debug("ON_LINES: Invalid prompt_bufnr", prompt_bufnr)
|
log.debug("ON_LINES: Invalid prompt_bufnr", self.prompt_bufnr)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -509,7 +654,7 @@ function Picker:find()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
-- Register attach
|
-- Register attach
|
||||||
vim.api.nvim_buf_attach(prompt_bufnr, false, {
|
vim.api.nvim_buf_attach(self.prompt_bufnr, false, {
|
||||||
on_lines = function(...)
|
on_lines = function(...)
|
||||||
if self._finder_attached then
|
if self._finder_attached then
|
||||||
find_id = self:_next_find_id()
|
find_id = self:_next_find_id()
|
||||||
@@ -527,46 +672,45 @@ function Picker:find()
|
|||||||
vim.api.nvim_create_augroup("PickerInsert", {})
|
vim.api.nvim_create_augroup("PickerInsert", {})
|
||||||
-- TODO: Use WinLeave as well?
|
-- TODO: Use WinLeave as well?
|
||||||
vim.api.nvim_create_autocmd("BufLeave", {
|
vim.api.nvim_create_autocmd("BufLeave", {
|
||||||
buffer = prompt_bufnr,
|
buffer = self.prompt_bufnr,
|
||||||
group = "PickerInsert",
|
group = "PickerInsert",
|
||||||
nested = true,
|
nested = true,
|
||||||
once = true,
|
once = true,
|
||||||
callback = function()
|
callback = function()
|
||||||
require("telescope.pickers").on_close_prompt(prompt_bufnr)
|
require("telescope.pickers").on_close_prompt(self.prompt_bufnr)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
vim.api.nvim_create_autocmd("VimResized", {
|
vim.api.nvim_create_autocmd("VimResized", {
|
||||||
buffer = prompt_bufnr,
|
buffer = self.prompt_bufnr,
|
||||||
group = "PickerInsert",
|
group = "PickerInsert",
|
||||||
nested = true,
|
nested = true,
|
||||||
callback = function()
|
callback = function()
|
||||||
require("telescope.pickers").on_resize_window(prompt_bufnr)
|
require("telescope.pickers").on_resize_window(self.prompt_bufnr)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
self.prompt_bufnr = prompt_bufnr
|
|
||||||
|
|
||||||
state.set_status(
|
state.set_status(
|
||||||
prompt_bufnr,
|
self.prompt_bufnr,
|
||||||
setmetatable({
|
setmetatable({
|
||||||
prompt_bufnr = prompt_bufnr,
|
layout = layout,
|
||||||
prompt_win = prompt_win,
|
|
||||||
prompt_border_win = prompt_border_win,
|
|
||||||
|
|
||||||
results_bufnr = results_bufnr,
|
|
||||||
results_win = results_win,
|
|
||||||
results_border_win = results_border_win,
|
|
||||||
|
|
||||||
preview_bufnr = preview_bufnr,
|
|
||||||
preview_win = preview_win,
|
|
||||||
preview_border_win = preview_border_win,
|
|
||||||
picker = self,
|
picker = self,
|
||||||
|
|
||||||
|
-- compatibility
|
||||||
|
prompt_bufnr = self.prompt_bufnr,
|
||||||
|
prompt_win = self.prompt_win,
|
||||||
|
prompt_border_win = self.prompt_border.winid,
|
||||||
|
results_bufnr = self.results_bufnr,
|
||||||
|
results_win = self.results_win,
|
||||||
|
results_border_win = self.results_border.winid,
|
||||||
|
preview_bufnr = self.preview_bufnr,
|
||||||
|
preview_win = self.preview_win,
|
||||||
|
preview_border_win = self.preview_border and self.preview_border.winid,
|
||||||
}, {
|
}, {
|
||||||
__mode = "kv",
|
__mode = "kv",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
mappings.apply_keymap(prompt_bufnr, self.attach_mappings, config.values.mappings)
|
mappings.apply_keymap(self.prompt_bufnr, self.attach_mappings, config.values.mappings)
|
||||||
|
|
||||||
tx.send()
|
tx.send()
|
||||||
main_loop()
|
main_loop()
|
||||||
@@ -574,79 +718,20 @@ end
|
|||||||
|
|
||||||
--- A helper function to update picker windows when layout options are changed
|
--- A helper function to update picker windows when layout options are changed
|
||||||
function Picker:recalculate_layout()
|
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 status = state.get_status(self.prompt_bufnr)
|
||||||
|
|
||||||
local prompt_win = status.prompt_win
|
status.layout:update()
|
||||||
local results_win = status.results_win
|
|
||||||
local preview_win = status.preview_win
|
|
||||||
|
|
||||||
local preview_opts, preview_border_win
|
local layout = status.layout
|
||||||
if popup_opts.preview then
|
self.prompt_win, self.prompt_bufnr, self.prompt_border =
|
||||||
if preview_win ~= nil then
|
layout.prompt.winid, layout.prompt.bufnr, layout.prompt.border
|
||||||
-- Move all popups at the same time
|
self.results_win, self.results_bufnr, self.results_border =
|
||||||
popup.move(prompt_win, popup_opts.prompt)
|
layout.results.winid, layout.results.bufnr, layout.results.border
|
||||||
popup.move(results_win, popup_opts.results)
|
if layout.preview then
|
||||||
popup.move(preview_win, popup_opts.preview)
|
self.preview_win, self.preview_bufnr, self.preview_border =
|
||||||
else
|
layout.preview.winid, layout.preview.bufnr, layout.preview.border
|
||||||
popup_opts.preview.highlight = "TelescopePreviewNormal"
|
|
||||||
popup_opts.preview.borderhighlight = "TelescopePreviewBorder"
|
|
||||||
popup_opts.preview.titlehighlight = "TelescopePreviewTitle"
|
|
||||||
local preview_bufnr = status.preview_bufnr ~= nil
|
|
||||||
and 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_bufnr = preview_bufnr
|
|
||||||
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
|
|
||||||
if self.previewer and self.previewer.state and self.previewer.state.winid then
|
|
||||||
self.previewer.state.winid = preview_win
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Move prompt and results after preview created
|
|
||||||
vim.defer_fn(function()
|
|
||||||
popup.move(prompt_win, popup_opts.prompt)
|
|
||||||
popup.move(results_win, popup_opts.results)
|
|
||||||
end, 0)
|
|
||||||
end
|
|
||||||
elseif preview_win ~= nil then
|
|
||||||
popup.move(prompt_win, popup_opts.prompt)
|
|
||||||
popup.move(results_win, popup_opts.results)
|
|
||||||
|
|
||||||
-- Remove preview after the prompt and results are moved
|
|
||||||
vim.defer_fn(function()
|
|
||||||
utils.win_delete("preview_win", preview_win, true)
|
|
||||||
utils.win_delete("preview_win", status.preview_border_win, true)
|
|
||||||
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, 0)
|
|
||||||
else
|
else
|
||||||
popup.move(prompt_win, popup_opts.prompt)
|
self.preview_win, self.preview_bufnr, self.preview_border = nil, nil, nil
|
||||||
popup.move(results_win, popup_opts.results)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Temporarily disabled: Draw the screen ASAP. This makes things feel speedier.
|
-- Temporarily disabled: Draw the screen ASAP. This makes things feel speedier.
|
||||||
@@ -749,20 +834,9 @@ end
|
|||||||
---@param status table: table containing information on the picker
|
---@param status table: table containing information on the picker
|
||||||
--- and associated windows. Generally obtained from `state.get_status`
|
--- and associated windows. Generally obtained from `state.get_status`
|
||||||
function Picker.close_windows(status)
|
function Picker.close_windows(status)
|
||||||
utils.win_delete("results_win", status.results_win, true, true)
|
local prompt_bufnr = status.layout.prompt.bufnr
|
||||||
utils.win_delete("preview_win", status.preview_win, true, true)
|
status.layout:unmount()
|
||||||
|
state.clear_status(prompt_bufnr)
|
||||||
utils.win_delete("prompt_border_win", status.prompt_border_win, true, true)
|
|
||||||
utils.win_delete("results_border_win", status.results_border_win, true, true)
|
|
||||||
utils.win_delete("preview_border_win", status.preview_border_win, true, true)
|
|
||||||
|
|
||||||
-- we cant use win_delete. We first need to close and then delete the buffer
|
|
||||||
if vim.api.nvim_win_is_valid(status.prompt_win) then
|
|
||||||
vim.api.nvim_win_close(status.prompt_win, true)
|
|
||||||
end
|
|
||||||
utils.buf_delete(status.prompt_bufnr)
|
|
||||||
|
|
||||||
state.clear_status(status.prompt_bufnr)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the entry table of the current selection
|
--- Get the entry table of the current selection
|
||||||
@@ -1079,7 +1153,12 @@ end
|
|||||||
--- Refresh the previewer based on the current `status` of the picker
|
--- Refresh the previewer based on the current `status` of the picker
|
||||||
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 self.previewer and status.preview_win and a.nvim_win_is_valid(status.preview_win) then
|
if
|
||||||
|
self.previewer
|
||||||
|
and status.layout.preview
|
||||||
|
and status.layout.preview.winid
|
||||||
|
and a.nvim_win_is_valid(status.layout.preview.winid)
|
||||||
|
then
|
||||||
self:_increment "previewed"
|
self:_increment "previewed"
|
||||||
|
|
||||||
self.previewer:preview(self._selection_entry, status)
|
self.previewer:preview(self._selection_entry, status)
|
||||||
@@ -1091,7 +1170,7 @@ function Picker:refresh_previewer()
|
|||||||
local new_title = self.previewer:title(self._selection_entry, config.values.dynamic_preview_title)
|
local new_title = self.previewer:title(self._selection_entry, config.values.dynamic_preview_title)
|
||||||
if new_title ~= nil and new_title ~= self.preview_title then
|
if new_title ~= nil and new_title ~= self.preview_title then
|
||||||
self.preview_title = new_title
|
self.preview_title = new_title
|
||||||
self.preview_border:change_title(new_title)
|
self.layout.preview.border:change_title(new_title)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ entry_display.create = function(configuration)
|
|||||||
if width == nil then
|
if width == nil then
|
||||||
local status = state.get_status(vim.F.if_nil(configuration.prompt_bufnr, vim.api.nvim_get_current_buf()))
|
local status = state.get_status(vim.F.if_nil(configuration.prompt_bufnr, vim.api.nvim_get_current_buf()))
|
||||||
local s = {}
|
local s = {}
|
||||||
s[1] = vim.api.nvim_win_get_width(status.results_win) - #status.picker.selection_caret
|
s[1] = vim.api.nvim_win_get_width(status.layout.results.winid) - #status.picker.selection_caret
|
||||||
s[2] = vim.api.nvim_win_get_height(status.results_win)
|
s[2] = vim.api.nvim_win_get_height(status.layout.results.winid)
|
||||||
width = resolve.resolve_width(v.width)(nil, s[1], s[2])
|
width = resolve.resolve_width(v.width)(nil, s[1], s[2])
|
||||||
end
|
end
|
||||||
if type(item) == "table" then
|
if type(item) == "table" then
|
||||||
|
|||||||
193
lua/telescope/pickers/layout.lua
Normal file
193
lua/telescope/pickers/layout.lua
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
---@tag telescope.pickers.layout
|
||||||
|
---@config { ["module"] = "telescope.pickers.layout" }
|
||||||
|
|
||||||
|
---@brief [[
|
||||||
|
--- The telescope pickers layout can be configured using the
|
||||||
|
--- |telescope.defaults.create_layout| option.
|
||||||
|
---
|
||||||
|
--- Parameters: ~
|
||||||
|
--- - picker : A Picker object.
|
||||||
|
---
|
||||||
|
--- Return: ~
|
||||||
|
--- - layout : instance of `TelescopeLayout` class.
|
||||||
|
---
|
||||||
|
--- Example: ~
|
||||||
|
--- <code>
|
||||||
|
--- local Layout = require "telescope.pickers.layout"
|
||||||
|
---
|
||||||
|
--- require("telescope").setup {
|
||||||
|
--- create_layout = function(picker)
|
||||||
|
--- local function create_window(enter, width, height, row, col, title)
|
||||||
|
--- local bufnr = vim.api.nvim_create_buf(false, true)
|
||||||
|
--- local winid = vim.api.nvim_open_win(bufnr, enter, {
|
||||||
|
--- style = "minimal",
|
||||||
|
--- relative = "editor",
|
||||||
|
--- width = width,
|
||||||
|
--- height = height,
|
||||||
|
--- row = row,
|
||||||
|
--- col = col,
|
||||||
|
--- border = "single",
|
||||||
|
--- title = title,
|
||||||
|
--- })
|
||||||
|
---
|
||||||
|
--- vim.wo[winid].winhighlight = "Normal:Normal"
|
||||||
|
---
|
||||||
|
--- return Layout.Window {
|
||||||
|
--- bufnr = bufnr,
|
||||||
|
--- winid = winid,
|
||||||
|
--- }
|
||||||
|
--- end
|
||||||
|
---
|
||||||
|
--- local function destory_window(window)
|
||||||
|
--- if window then
|
||||||
|
--- if vim.api.nvim_win_is_valid(window.winid) then
|
||||||
|
--- vim.api.nvim_win_close(window.winid, true)
|
||||||
|
--- end
|
||||||
|
--- if vim.api.nvim_buf_is_valid(window.bufnr) then
|
||||||
|
--- vim.api.nvim_buf_delete(window.bufnr, { force = true })
|
||||||
|
--- end
|
||||||
|
--- end
|
||||||
|
--- end
|
||||||
|
---
|
||||||
|
--- local layout = Layout {
|
||||||
|
--- picker = picker,
|
||||||
|
--- mount = function(self)
|
||||||
|
--- self.results = create_window(false, 40, 20, 0, 0, "Results")
|
||||||
|
--- self.preview = create_window(false, 40, 23, 0, 42, "Preview")
|
||||||
|
--- self.prompt = create_window(true, 40, 1, 22, 0, "Prompt")
|
||||||
|
--- end,
|
||||||
|
--- unmount = function(self)
|
||||||
|
--- destory_window(self.results)
|
||||||
|
--- destory_window(self.preview)
|
||||||
|
--- destory_window(self.prompt)
|
||||||
|
--- end,
|
||||||
|
--- update = function(self) end,
|
||||||
|
--- }
|
||||||
|
---
|
||||||
|
--- return layout
|
||||||
|
--- end,
|
||||||
|
--- }
|
||||||
|
--- </code>
|
||||||
|
---@brief ]]
|
||||||
|
|
||||||
|
local function wrap_instance(class, instance)
|
||||||
|
local self = instance
|
||||||
|
if not getmetatable(instance) then
|
||||||
|
self = setmetatable(instance, { __index = class })
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class TelescopeWindowBorder.config
|
||||||
|
---@field bufnr integer
|
||||||
|
---@field winid integer|nil
|
||||||
|
---@field change_title nil|function: (self: TelescopeWindowBorder, title: string, pos?: "NW"|"N"|"NE"|"SW"|"S"|"SE"):nil
|
||||||
|
|
||||||
|
---@param class TelescopeWindowBorder
|
||||||
|
---@param config TelescopeWindowBorder.config
|
||||||
|
---@return TelescopeWindowBorder
|
||||||
|
local function init_border(class, config)
|
||||||
|
config = config or {}
|
||||||
|
|
||||||
|
---@type TelescopeWindowBorder
|
||||||
|
local self = wrap_instance(class, config)
|
||||||
|
if not self.change_title then
|
||||||
|
self.change_title = class.change_title
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class TelescopeWindowBorder
|
||||||
|
---@field bufnr integer|nil
|
||||||
|
---@field winid integer|nil
|
||||||
|
local Border = setmetatable({}, {
|
||||||
|
__call = init_border,
|
||||||
|
__name = "TelescopeWindowBorder",
|
||||||
|
})
|
||||||
|
|
||||||
|
---@param title string
|
||||||
|
---@param pos "NW"|"N"|"NE"|"SW"|"S"|"SE"|nil
|
||||||
|
function Border:change_title(title, pos) end
|
||||||
|
|
||||||
|
---@class TelescopeWindow.config
|
||||||
|
---@field bufnr integer
|
||||||
|
---@field winid integer|nil
|
||||||
|
---@field border TelescopeWindowBorder.config|nil
|
||||||
|
|
||||||
|
---@param class TelescopeWindow
|
||||||
|
---@param config TelescopeWindow.config
|
||||||
|
---@return TelescopeWindow
|
||||||
|
local function init_window(class, config)
|
||||||
|
config = config or {}
|
||||||
|
|
||||||
|
---@type TelescopeWindow
|
||||||
|
local self = wrap_instance(class, config)
|
||||||
|
self.border = Border(config.border)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class TelescopeWindow
|
||||||
|
---@field border TelescopeWindowBorder
|
||||||
|
---@field bufnr integer
|
||||||
|
---@field winid integer
|
||||||
|
local Window = setmetatable({}, {
|
||||||
|
__call = init_window,
|
||||||
|
__name = "TelescopeWindow",
|
||||||
|
})
|
||||||
|
|
||||||
|
---@class TelescopeLayout.config
|
||||||
|
---@field mount function: (self: TelescopeLayout):nil
|
||||||
|
---@field unmount function: (self: TelescopeLayout):nil
|
||||||
|
---@field update function: (self: TelescopeLayout):nil
|
||||||
|
---@field prompt TelescopeWindow|nil
|
||||||
|
---@field results TelescopeWindow|nil
|
||||||
|
---@field preview TelescopeWindow|nil
|
||||||
|
|
||||||
|
---@param class TelescopeLayout
|
||||||
|
---@param config TelescopeLayout.config
|
||||||
|
---@return TelescopeLayout
|
||||||
|
local function init_layout(class, config)
|
||||||
|
config = config or {}
|
||||||
|
|
||||||
|
---@type TelescopeLayout
|
||||||
|
local self = wrap_instance(class, config)
|
||||||
|
|
||||||
|
assert(config.mount, "missing layout:mount")
|
||||||
|
assert(config.unmount, "missing layout:unmount")
|
||||||
|
assert(config.update, "missing layout:update")
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class TelescopeLayout
|
||||||
|
---@field prompt TelescopeWindow
|
||||||
|
---@field results TelescopeWindow
|
||||||
|
---@field preview TelescopeWindow|nil
|
||||||
|
local Layout = setmetatable({
|
||||||
|
Window = Window,
|
||||||
|
}, {
|
||||||
|
__call = init_layout,
|
||||||
|
__name = "TelescopeLayout",
|
||||||
|
})
|
||||||
|
|
||||||
|
--- Create the layout.
|
||||||
|
--- This needs to ensure the required properties are populated.
|
||||||
|
function Layout:mount() end
|
||||||
|
|
||||||
|
--- Destroy the layout.
|
||||||
|
--- This is responsible for performing clean-up, for example:
|
||||||
|
--- - deleting buffers
|
||||||
|
--- - closing windows
|
||||||
|
--- - clearing autocmds
|
||||||
|
function Layout:unmount() end
|
||||||
|
|
||||||
|
--- Refresh the layout.
|
||||||
|
--- This is called when, for example, vim is resized.
|
||||||
|
function Layout:update() end
|
||||||
|
|
||||||
|
---@alias TelescopeWindow.constructor fun(config: TelescopeWindow.config): TelescopeWindow
|
||||||
|
---@alias TelescopeLayout.constructor fun(config: TelescopeLayout.config): TelescopeLayout
|
||||||
|
|
||||||
|
return Layout --[[@as TelescopeLayout.constructor|{ Window: TelescopeWindow.constructor }]]
|
||||||
@@ -409,32 +409,33 @@ previewers.new_buffer_previewer = function(opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function opts.preview_fn(self, entry, status)
|
function opts.preview_fn(self, entry, status)
|
||||||
|
local preview_winid = status.layout.preview and status.layout.preview.winid
|
||||||
if get_bufnr(self) == nil then
|
if get_bufnr(self) == nil then
|
||||||
set_bufnr(self, vim.api.nvim_win_get_buf(status.preview_win))
|
set_bufnr(self, vim.api.nvim_win_get_buf(preview_winid))
|
||||||
preview_window_id = status.preview_win
|
preview_window_id = preview_winid
|
||||||
end
|
end
|
||||||
|
|
||||||
if opts.get_buffer_by_name and get_bufnr_by_bufname(self, opts.get_buffer_by_name(self, entry)) then
|
if opts.get_buffer_by_name and get_bufnr_by_bufname(self, opts.get_buffer_by_name(self, entry)) then
|
||||||
self.state.bufname = opts.get_buffer_by_name(self, entry)
|
self.state.bufname = opts.get_buffer_by_name(self, entry)
|
||||||
self.state.bufnr = get_bufnr_by_bufname(self, self.state.bufname)
|
self.state.bufnr = get_bufnr_by_bufname(self, self.state.bufname)
|
||||||
utils.win_set_buf_noautocmd(status.preview_win, self.state.bufnr)
|
utils.win_set_buf_noautocmd(preview_winid, self.state.bufnr)
|
||||||
else
|
else
|
||||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||||
set_bufnr(self, bufnr)
|
set_bufnr(self, bufnr)
|
||||||
|
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
if vim.api.nvim_buf_is_valid(bufnr) then
|
if vim.api.nvim_buf_is_valid(bufnr) then
|
||||||
utils.win_set_buf_noautocmd(status.preview_win, bufnr)
|
utils.win_set_buf_noautocmd(preview_winid, bufnr)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
vim.api.nvim_win_set_option(status.preview_win, "winhl", "Normal:TelescopePreviewNormal")
|
vim.api.nvim_win_set_option(preview_winid, "winhl", "Normal:TelescopePreviewNormal")
|
||||||
vim.api.nvim_win_set_option(status.preview_win, "signcolumn", "no")
|
vim.api.nvim_win_set_option(preview_winid, "signcolumn", "no")
|
||||||
vim.api.nvim_win_set_option(status.preview_win, "foldlevel", 100)
|
vim.api.nvim_win_set_option(preview_winid, "foldlevel", 100)
|
||||||
vim.api.nvim_win_set_option(status.preview_win, "wrap", false)
|
vim.api.nvim_win_set_option(preview_winid, "wrap", false)
|
||||||
vim.api.nvim_win_set_option(status.preview_win, "scrollbind", false)
|
vim.api.nvim_win_set_option(preview_winid, "scrollbind", false)
|
||||||
|
|
||||||
self.state.winid = status.preview_win
|
self.state.winid = preview_winid
|
||||||
self.state.bufname = nil
|
self.state.bufname = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1012,13 +1013,15 @@ previewers.autocommands = defaulter(function(_)
|
|||||||
pcall(vim.api.nvim_buf_clear_namespace, self.state.last_set_bufnr, ns_previewer, 0, -1)
|
pcall(vim.api.nvim_buf_clear_namespace, self.state.last_set_bufnr, ns_previewer, 0, -1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local preview_winid = status.layout.preview and status.layout.preview.winid
|
||||||
|
|
||||||
local selected_row = 0
|
local selected_row = 0
|
||||||
if self.state.bufname ~= entry.value.group_name then
|
if self.state.bufname ~= entry.value.group_name then
|
||||||
local display = {}
|
local display = {}
|
||||||
table.insert(display, string.format(" augroup: %s - [ %d entries ]", entry.value.group_name, #results))
|
table.insert(display, string.format(" augroup: %s - [ %d entries ]", entry.value.group_name, #results))
|
||||||
-- TODO: calculate banner width/string in setup()
|
-- TODO: calculate banner width/string in setup()
|
||||||
-- TODO: get column characters to be the same HL group as border
|
-- TODO: get column characters to be the same HL group as border
|
||||||
table.insert(display, string.rep("─", vim.fn.getwininfo(status.preview_win)[1].width))
|
table.insert(display, string.rep("─", vim.fn.getwininfo(preview_winid)[1].width))
|
||||||
|
|
||||||
for idx, item in ipairs(results) do
|
for idx, item in ipairs(results) do
|
||||||
if item == entry then
|
if item == entry then
|
||||||
@@ -1046,7 +1049,7 @@ previewers.autocommands = defaulter(function(_)
|
|||||||
-- set the cursor position after self.state.bufnr is connected to the
|
-- set the cursor position after self.state.bufnr is connected to the
|
||||||
-- preview window (which is scheduled in new_buffer_previewer)
|
-- preview window (which is scheduled in new_buffer_previewer)
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
pcall(vim.api.nvim_win_set_cursor, status.preview_win, { selected_row, 0 })
|
pcall(vim.api.nvim_win_set_cursor, preview_winid, { selected_row, 0 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
self.state.last_set_bufnr = self.state.bufnr
|
self.state.last_set_bufnr = self.state.bufnr
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function Previewer:preview(entry, status)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if vim.api.nvim_buf_is_valid(self._empty_bufnr) then
|
if vim.api.nvim_buf_is_valid(self._empty_bufnr) then
|
||||||
vim.api.nvim_win_set_buf(status.preview_win, self._empty_bufnr)
|
vim.api.nvim_win_set_buf(status.layout.preview.winid, self._empty_bufnr)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -185,19 +185,20 @@ previewers.new_termopen_previewer = function(opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function opts.preview_fn(self, entry, status)
|
function opts.preview_fn(self, entry, status)
|
||||||
|
local preview_winid = status.layout.preview and status.layout.preview.winid
|
||||||
if get_bufnr(self) == nil then
|
if get_bufnr(self) == nil then
|
||||||
set_bufnr(self, vim.api.nvim_win_get_buf(status.preview_win))
|
set_bufnr(self, vim.api.nvim_win_get_buf(preview_winid))
|
||||||
end
|
end
|
||||||
|
|
||||||
local prev_bufnr = get_bufnr_by_bufentry(self, entry)
|
local prev_bufnr = get_bufnr_by_bufentry(self, entry)
|
||||||
if prev_bufnr then
|
if prev_bufnr then
|
||||||
self.state.termopen_bufnr = prev_bufnr
|
self.state.termopen_bufnr = prev_bufnr
|
||||||
utils.win_set_buf_noautocmd(status.preview_win, self.state.termopen_bufnr)
|
utils.win_set_buf_noautocmd(preview_winid, self.state.termopen_bufnr)
|
||||||
self.state.termopen_id = term_ids[self.state.termopen_bufnr]
|
self.state.termopen_id = term_ids[self.state.termopen_bufnr]
|
||||||
else
|
else
|
||||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||||
set_bufnr(self, bufnr)
|
set_bufnr(self, bufnr)
|
||||||
utils.win_set_buf_noautocmd(status.preview_win, bufnr)
|
utils.win_set_buf_noautocmd(preview_winid, bufnr)
|
||||||
|
|
||||||
local term_opts = {
|
local term_opts = {
|
||||||
cwd = opts.cwd or vim.loop.cwd(),
|
cwd = opts.cwd or vim.loop.cwd(),
|
||||||
@@ -277,7 +278,7 @@ previewers.vimgrep = defaulter(function(opts)
|
|||||||
end,
|
end,
|
||||||
|
|
||||||
get_command = function(entry, status)
|
get_command = function(entry, status)
|
||||||
local win_id = status.preview_win
|
local win_id = status.layout.preview and status.layout.preview.winid
|
||||||
local height = vim.api.nvim_win_get_height(win_id)
|
local height = vim.api.nvim_win_get_height(win_id)
|
||||||
|
|
||||||
local p = from_entry.path(entry, true, false)
|
local p = from_entry.path(entry, true, false)
|
||||||
@@ -312,7 +313,7 @@ previewers.qflist = defaulter(function(opts)
|
|||||||
end,
|
end,
|
||||||
|
|
||||||
get_command = function(entry, status)
|
get_command = function(entry, status)
|
||||||
local win_id = status.preview_win
|
local win_id = status.layout.preview and status.layout.preview.winid
|
||||||
local height = vim.api.nvim_win_get_height(win_id)
|
local height = vim.api.nvim_win_get_height(win_id)
|
||||||
|
|
||||||
local p = from_entry.path(entry, true, false)
|
local p = from_entry.path(entry, true, false)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ end
|
|||||||
|
|
||||||
test_helpers.get_results_bufnr = function()
|
test_helpers.get_results_bufnr = function()
|
||||||
local state = require "telescope.state"
|
local state = require "telescope.state"
|
||||||
return state.get_status(vim.api.nvim_get_current_buf()).results_bufnr
|
return state.get_status(vim.api.nvim_get_current_buf()).layout.results.bufnr
|
||||||
end
|
end
|
||||||
|
|
||||||
test_helpers.get_file = function()
|
test_helpers.get_file = function()
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ end
|
|||||||
|
|
||||||
local calc_result_length = function(truncate_len)
|
local calc_result_length = function(truncate_len)
|
||||||
local status = get_status(vim.api.nvim_get_current_buf())
|
local status = get_status(vim.api.nvim_get_current_buf())
|
||||||
local len = vim.api.nvim_win_get_width(status.results_win) - status.picker.selection_caret:len() - 2
|
local len = vim.api.nvim_win_get_width(status.layout.results.winid) - status.picker.selection_caret:len() - 2
|
||||||
return type(truncate_len) == "number" and len - truncate_len or len
|
return type(truncate_len) == "number" and len - truncate_len or len
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ docs.test = function()
|
|||||||
"./lua/telescope/builtin/init.lua",
|
"./lua/telescope/builtin/init.lua",
|
||||||
"./lua/telescope/themes.lua",
|
"./lua/telescope/themes.lua",
|
||||||
"./lua/telescope/mappings.lua",
|
"./lua/telescope/mappings.lua",
|
||||||
|
"./lua/telescope/pickers/layout.lua",
|
||||||
"./lua/telescope/pickers/layout_strategies.lua",
|
"./lua/telescope/pickers/layout_strategies.lua",
|
||||||
"./lua/telescope/config/resolve.lua",
|
"./lua/telescope/config/resolve.lua",
|
||||||
"./lua/telescope/make_entry.lua",
|
"./lua/telescope/make_entry.lua",
|
||||||
|
|||||||
Reference in New Issue
Block a user