Skip to content

Commit

Permalink
feat(fzf): allow fzf win_configs to contain functions, fix vertical o…
Browse files Browse the repository at this point in the history
…ffsets (#131)

* feat(fzf): allow `win_configs` options to be functions

fix(fzf): vertical offset for border

refactor(fzf): move `win_config` elements into default config

* fix(ui-select): modify fzf border depending on prompt

* refactor(fzf): move fzf win configs to config functions

* fix: row and col when menu border is 'none'

* fix: differing fzf and menu widths

* fix: border width accumulation

* fix: shadow border

* refactor: simplify condition

* fix: fzf offset for 4-char array border
  • Loading branch information
willothy authored Feb 5, 2024
1 parent 4855b9b commit ef73236
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 37 deletions.
94 changes: 93 additions & 1 deletion lua/dropbar/configs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,99 @@ M.opts = {
},
},
fzf = {
win_configs = {
relative = 'win',
anchor = 'NW',
height = 1,
win = function(menu)
return menu.win
end,
width = function(menu)
local function border_width(border)
if type(border) == 'string' then
if border == 'none' or border == 'shadow' then
return 0
end
return 2 -- left and right border
end

local left, right = 1, 1
if
(#border == 1 and border[1] == '')
or (#border == 4 and border[4] == '')
or (#border == 8 and border[8] == '')
then
left = 0
end
if
(#border == 1 and border[1] == '')
or (#border == 4 and border[4] == '')
or (#border == 8 and border[4] == '')
then
right = 0
end
return left + right
end
local menu_width = menu._win_configs.width
+ border_width(menu._win_configs.border)
local self_width = menu._win_configs.width
local self_border = border_width(
(
M.opts.fzf.win_configs
and M.eval(M.opts.fzf.win_configs.border, menu)
)
or (menu.fzf_win_configs and M.eval(
menu.fzf_win_configs.border,
menu
))
or menu._win_configs.border
)

if self_width + self_border > menu_width then
return self_width - self_border
else
return menu_width - self_border
end
end,
row = function(menu)
local menu_border = menu._win_configs.border
if
type(menu_border) == 'string'
and menu_border ~= 'shadow'
and menu_border ~= 'none'
then
return menu._win_configs.height + 1
elseif menu_border == 'none' then
return menu._win_configs.height
end
local len_menu_border = #menu_border
if
len_menu_border == 1 and menu_border[1] ~= ''
or (len_menu_border == 2 or len_menu_border == 4) and menu_border[2] ~= ''
or len_menu_border == 8 and menu_border[8] ~= ''
then
return menu._win_configs.height + 1
else
return menu._win_configs.height
end
end,
col = function(menu)
local menu_border = menu._win_configs.border
if
type(menu_border) == 'string'
and menu_border ~= 'shadow'
and menu_border ~= 'none'
then
return -1
end
if
type(menu_border) == 'table' and menu_border[#menu_border] ~= ''
then
return -1
end
return 0
end,
},
---@type table<string, string | fun()>
keymaps = {
['<LeftMouse>'] = function()
Expand Down Expand Up @@ -418,7 +511,6 @@ M.opts = {
api.fuzzy_find_click(-1)
end,
},
win_configs = {},
prompt = '%#htmlTag# ',
char_pattern = '[%w%p]',
retain_inner_spaces = true,
Expand Down
80 changes: 44 additions & 36 deletions lua/dropbar/menu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ end
---@field prev_cursor integer[]? previous cursor position
---@field symbol_previewed dropbar_symbol_t? symbol being previewed
---@field fzf_state fzf_state_t? fuzzy-finding state, or nil if not currently fuzzy-finding
---@field fzf_win_configs table window configuration, value can be a function
---@field scrollbar { thumb: integer, background: integer }? scrollbar window handlers
local dropbar_menu_t = {}
dropbar_menu_t.__index = dropbar_menu_t
Expand Down Expand Up @@ -251,14 +252,7 @@ end
---@see vim.api.nvim_open_win
function dropbar_menu_t:eval_win_configs()
-- Evaluate function-valued window configurations
self._win_configs = {}
for k, config in pairs(self.win_configs) do
if type(config) == 'function' then
self._win_configs[k] = config(self)
else
self._win_configs[k] = config
end
end
self._win_configs = self:merge_win_configs(self.win_configs)

-- See https://github.com/Bekaboo/dropbar.nvim/pull/90
-- Ensure `win` field is nil if `relative` ~= 'win', else nvim will
Expand Down Expand Up @@ -813,6 +807,7 @@ function dropbar_menu_t:fuzzy_find_close()
vim.api.nvim_win_close(input_win, false)
end
_G.dropbar.menus[input_win] = nil
self:update_border()
end

---Click on the currently selected fuzzy find menu entry, choosing the component
Expand Down Expand Up @@ -888,6 +883,40 @@ function dropbar_menu_t:fuzzy_find_navigate(dir)
vim.api.nvim_exec_autocmds('CursorMoved', { buffer = self.buf })
end

function dropbar_menu_t:update_border()
if self.win_configs.border then
local border = self.win_configs.border
if type(self.win_configs.border) == 'function' then
border = self.win_configs.border(self)
end
local config = vim.api.nvim_win_get_config(self.win)
config.border = border
vim.api.nvim_win_set_config(self.win, config)
self._win_configs.border = border
end
end

---Merges win configs, with the last one taking precedence.
---@private
---@param ... nil | table | fun(self: dropbar_menu_t): table window configuration, value can be a function
---@return table
function dropbar_menu_t:merge_win_configs(...)
local merged = {}
for i = 1, select('#', ...) do
local chunk = select(i, ...)
if chunk then
for k, v in pairs(chunk) do
if type(v) == 'function' then
merged[k] = v(self) or merged[k]
else
merged[k] = v
end
end
end
end
return merged
end

---Enable fuzzy finding mode
---@param opts? table<string, any>
---@version JIT
Expand Down Expand Up @@ -924,34 +953,11 @@ function dropbar_menu_t:fuzzy_find_open(opts)
vim.bo[buf].filetype = 'dropbar_menu_fzf'
vim.bo[buf].bufhidden = 'wipe'

-- check if menu has left or bottom border to adjust fzf window's
-- col/row option to align with menu window
local menu_border = self._win_configs.border
local menu_has_left_border = false
local menu_has_bottom_border = false
if type(menu_border) == 'string' then
if menu_border ~= 'shadow' and menu_border ~= 'none' then
menu_has_left_border = true
menu_has_bottom_border = true
end
else -- border is non-empty (guaranteed by nvim api) array
local len_menu_border = #menu_border
menu_has_left_border = menu_border[len_menu_border] ~= ''
menu_has_bottom_border = len_menu_border == 1 and menu_border[1] ~= ''
or (len_menu_border == 2 or len_menu_border == 4) and menu_border[2] ~= ''
or len_menu_border == 8 and menu_border[8] ~= ''
end

local win_config =
vim.tbl_extend('force', self._win_configs, opts.win_configs or {}, {
relative = 'win',
win = self.win,
anchor = 'NW',
height = 1,
-- make sure that fzf window aligns well with menu window
col = menu_has_left_border and -1 or 0,
row = self._win_configs.height + (menu_has_bottom_border and 1 or 0),
})
local win_config = self:merge_win_configs(
self.win_configs,
self.fzf_win_configs,
opts.win_configs
)

-- don't show title in the fzf window
win_config.title = nil
Expand All @@ -962,6 +968,8 @@ function dropbar_menu_t:fuzzy_find_open(opts)
_G.dropbar.menus[win] = self
self.fzf_state = utils.fzf.fzf_state_t:new(self, win, opts)

self:update_border()

local should_preview = configs.opts.menu.preview
local function move_cursor(pos)
vim.api.nvim_win_set_cursor(self.win, pos)
Expand Down
6 changes: 6 additions & 0 deletions lua/dropbar/utils/menu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,25 @@ function M.select(items, opts, on_choice)
relative = 'cursor',
title = opts.prompt,
}
local fzf_win_configs = {}
-- Change border settings if the default top border is empty
-- to allow prompt to be displayed
if opts.prompt then
local border = configs.opts.menu.win_configs.border
local border_none_with_prompt = { '', ' ', '', '', '', '', '', '' }
if border == 'none' or border == 'shadow' then
win_configs.border = border_none_with_prompt
fzf_win_configs.border = 'none'
elseif type(border) == 'table' then
if #border == 1 and border[1] == '' then
win_configs.border = border_none_with_prompt
fzf_win_configs.border = 'none'
elseif #border > 1 and border[2] == '' then
local border_cp = vim.deepcopy(border)
border_cp[2] = ' '
win_configs.border = border_cp
-- use the original headerless border for fzf
fzf_win_configs.border = border
end
end
end
Expand All @@ -200,6 +205,7 @@ function M.select(items, opts, on_choice)
prev_win = win,
entries = entries,
win_configs = win_configs,
fzf_win_configs = fzf_win_configs,
})

smenu:open()
Expand Down

0 comments on commit ef73236

Please sign in to comment.