Skip to content

Commit

Permalink
feat(win)!: support additional border styles (#1668)
Browse files Browse the repository at this point in the history
Refactor win class code:

- Support both neovim and fzf border styles for
  `winopts.border|winopts.preview.border`, styles inlcude:
  ```
  # `nvim_open_win` styles
  none single double rounded solid shadow
  # fzf-lua styles (some are aliases)
  empty bold block solidblock thicc thiccc thicccc
  # fzf borders
  border noborder border-none border-rounded border-sharp
  border-bold border-double border-block border-thinblock
  border-horizontal border-top border-bottom
  ```
- Improve `treesitter-context` attach
- Refactor (normalize) layout generation code
- Refactor scrollbar code
- Refactor preview border: remove dedicated border window
  and use `nvim_open_win` title options instead (neovim >= 0.9)
- Fix scroll position caching with entries that have no line|col
- Fix fullscreen with `winopts.relative=cursor`
- Added an option for custom `winopts.split` function, this
  enables the use to create their own window for fzf-lua

Other changes:
- Require Neovim 0.7, remove backward compat code for 0.5|0.6
- Default profile set to `default-title` on neovim >= 0.9
- Renamed profile `borderless_full` -> `borderless-full`
- Modify profiles `borderless|borderless-full` to use the new
  border options
- New profile: `border-fused`, fuse fzf and preview window together
  with minimum spacing, will look similar to fzf's native layout
  where the preivewer is "contained" inside fzf
  • Loading branch information
ibhagwan committed Jan 6, 2025
1 parent 60428a8 commit fbb652b
Show file tree
Hide file tree
Showing 19 changed files with 544 additions and 619 deletions.
2 changes: 1 addition & 1 deletion OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ Scrollbar style in the builtin previewer, set to `false` to disable, possible va

#### globals.winopts.preview.scrolloff

Type: `number`, Default: `-2`
Type: `number`, Default: `-1`

Float style scrollbar offset from the right edge of the preview window.

Expand Down
56 changes: 30 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# fzf :heart: lua

![Neovim version](https://img.shields.io/badge/Neovim-0.5-57A143?style=flat-square&logo=neovim)
![Neovim version](https://img.shields.io/badge/Neovim-0.7-57A143?style=flat-square&logo=neovim)

[Quickstart](#quickstart)[Installation](#installation)[Usage](#usage)[Commands](#commands)[Customization](#customization)[Wiki](https://github.com/ibhagwan/fzf-lua/wiki)

Expand Down Expand Up @@ -55,7 +55,7 @@ Using [lazy.nvim](https://github.com/folke/lazy.nvim)

### Dependencies

- [`neovim`](https://github.com/neovim/neovim/releases) version > `0.5.0`
- [`neovim`](https://github.com/neovim/neovim/releases) version > `0.7.0`
- [`fzf`](https://github.com/junegunn/fzf) version > `0.25`
or [`skim`](https://github.com/skim-rs/skim) binary installed
- [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)
Expand Down Expand Up @@ -406,9 +406,8 @@ winopts = {
width = 0.80, -- window width
row = 0.35, -- window row position (0=top, 1=bottom)
col = 0.50, -- window col position (0=left, 1=right)
-- border argument passthrough to nvim_open_win(), also used
-- 'none', 'single', 'double', 'thicc' (+cc) or 'rounded' (default)
border = { '', '', '', '', '', '', '', '' },
-- border argument passthrough to nvim_open_win()
border = "rounded",
-- Backdrop opacity, 0 is fully opaque, 100 is fully transparent (i.e. disabled)
backdrop = 60,
-- title = "Title",
Expand All @@ -425,34 +424,36 @@ winopts = {
preview = {
-- default = 'bat', -- override the default previewer?
-- default uses the 'builtin' previewer
border = 'border', -- border|noborder, applies only to
border = "border", -- preview border: accepts both `nvim_open_win`
-- and fzf values (e.g. "border-top", "none")
-- native fzf previewers (bat/cat/git/etc)
wrap = 'nowrap', -- wrap|nowrap
hidden = 'nohidden', -- hidden|nohidden
vertical = 'down:45%', -- up|down:size
horizontal = 'right:60%', -- right|left:size
layout = 'flex', -- horizontal|vertical|flex
-- can also be set to `fun(winopts, metadata)`
wrap = "nowrap", -- wrap|nowrap
hidden = "nohidden", -- hidden|nohidden
vertical = "down:45%", -- up|down:size
horizontal = "right:60%", -- right|left:size
layout = "flex", -- horizontal|vertical|flex
flip_columns = 100, -- #cols to switch to horizontal on flex
-- Only used with the builtin previewer:
title = true, -- preview border title (file/buf)?
title_pos = "center", -- left|center|right, title alignment
scrollbar = 'float', -- `false` or string:'float|border'
scrollbar = "float", -- `false` or string:'float|border'
-- float: in-window floating border
-- border: in-border "block" marker
scrolloff = '-2', -- float scrollbar offset from right
scrolloff = -1, -- float scrollbar offset from right
-- applies only when scrollbar = 'float'
delay = 20, -- delay(ms) displaying the preview
-- prevents lag on fast scrolling
winopts = { -- builtin previewer window options
number = true,
relativenumber = false,
cursorline = true,
cursorlineopt = 'both',
cursorlineopt = "both",
cursorcolumn = false,
signcolumn = 'no',
signcolumn = "no",
list = false,
foldenable = false,
foldmethod = 'manual',
foldmethod = "manual",
},
},
on_create = function()
Expand Down Expand Up @@ -1345,16 +1346,19 @@ require('fzf-lua').setup({'fzf-vim'})

#### Available Profiles

| Profile | Details |
| --------------- | --------------------------------------------------------------------------------------------------- |
| `default` | fzf-lua defaults, uses neovim "builtin" previewer and devicons (if available) for git/files/buffers |
| `default-title` | fzf-lua defaults, using title instead of prompt |
| `fzf-native` | utilizes fzf's native previewing ability in the terminal where possible using `bat` for previews |
| `fzf-tmux` | similar to `fzf-native` and opens in a tmux popup (requires tmux > 3.2) |
| `fzf-vim` | closest to `fzf.vim`'s defaults (+icons), also sets up user commands (`:Files`, `:Rg`, etc) |
| `max-perf` | similar to `fzf-native` and disables icons globally for max performance |
| `telescope` | closest match to telescope defaults in look and feel and keybinds |
| `skim` | uses [`skim`](https://github.com/skim-rs/skim) as an fzf alternative, (requires the `sk` binary) |
| Profile | Details |
| ----------------- | --------------------------------------------------------------------------------------------------- |
| `default` | fzf-lua defaults, uses neovim "builtin" previewer and devicons (if available) for git/files/buffers |
| `default-title` | fzf-lua defaults, using title instead of prompt (default on neovim > =0.9) |
| `fzf-native` | utilizes fzf's native previewing ability in the terminal where possible using `bat` for previews |
| `fzf-tmux` | similar to `fzf-native` and opens in a tmux popup (requires tmux > 3.2) |
| `fzf-vim` | closest to `fzf.vim`'s defaults (+icons), also sets up user commands (`:Files`, `:Rg`, etc) |
| `max-perf` | similar to `fzf-native` and disables icons globally for max performance |
| `telescope` | closest match to telescope defaults in look and feel and keybinds |
| `skim` | uses [`skim`](https://github.com/skim-rs/skim) as an fzf alternative, (requires the `sk` binary) |
| `borderless` | borderless and minimalistic seamless look & feel |
| `borderless-full` | borderless with description in window title (instead of prompt) |
| `border-fused` | single border around both fzf and the previewer |

</details>

Expand Down
4 changes: 2 additions & 2 deletions doc/fzf-lua-opts.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*fzf-lua-opts.txt* For Neovim >= 0.8.0 Last change: 2024 December 18
*fzf-lua-opts.txt* For Neovim >= 0.8.0 Last change: 2024 December 27

==============================================================================
Table of Contents *fzf-lua-opts-table-of-contents*
Expand Down Expand Up @@ -504,7 +504,7 @@ values are `float|border`.

globals.winopts.preview.scrolloff*fzf-lua-opts-globals.winopts.preview.scrolloff*

Type: `number`, Default: `-2`
Type: `number`, Default: `-1`

Float style scrollbar offset from the right edge of the preview window.

Expand Down
47 changes: 36 additions & 11 deletions lua/fzf-lua/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -236,17 +236,37 @@ function M.normalize_opts(opts, globals, __resume_key)
-- merge with provider defaults from globals (defaults + setup options)
opts = vim.tbl_deep_extend("keep", opts, utils.tbl_deep_clone(globals))

-- Backward compat: merge `winopts` with outputs from `winopts_fn`
local winopts_fn = opts.winopts_fn or M.globals.winopts_fn
if type(winopts_fn) == "function" then
if not opts.silent then
utils.warn(
"Deprecated option: 'winopts_fn' -> 'winopts'. Add 'silent=true' to hide this message.")
end
local ret = winopts_fn(opts) or {}
if not utils.tbl_isempty(ret) and (not opts.winopts or type(opts.winopts) == "table") then
opts.winopts = vim.tbl_deep_extend("force", opts.winopts or {}, ret)
end
end

-- Merge values from globals
for _, k in ipairs({
"winopts", "keymap", "fzf_opts", "fzf_colors", "fzf_tmux_opts", "hls"
}) do
local setup_val = M.globals[k]
if type(setup_val) == "function" then
setup_val = setup_val(opts)
if type(setup_val) == "table" then
local default_val = utils.map_get(M.defaults, k)
if type(default_val) == "table" then
setup_val = vim.tbl_deep_extend("force", {}, default_val, setup_val)
end
end
end
if type(setup_val) == "table" then
-- must clone or map will be saved as reference
-- and then overwritten if found in 'backward_compat'
setup_val = utils.tbl_deep_clone(setup_val)
elseif type(setup_val) == "function" then
setup_val = setup_val(opts)
end
if opts[k] == nil then
opts[k] = setup_val
Expand Down Expand Up @@ -279,12 +299,6 @@ function M.normalize_opts(opts, globals, __resume_key)
end
end

-- Merge `winopts` with outputs from `winopts_fn`
local winopts_fn = opts.winopts_fn or M.globals.winopts_fn
if type(winopts_fn) == "function" then
opts.winopts = vim.tbl_deep_extend("force", opts.winopts, winopts_fn(opts) or {})
end

-- Merge arrays from globals|defaults, can't use 'vim.tbl_xxx'
-- for these as they only work for maps, ie. '{ key = value }'
for _, k in ipairs({ "file_ignore_patterns" }) do
Expand Down Expand Up @@ -449,10 +463,21 @@ function M.normalize_opts(opts, globals, __resume_key)
-- globals.winopts.preview.default
opts.previewer = opts.previewer()
end
if type(opts.previewer) == "table" or opts.previewer == true then
-- merge with the default builtin previewer
-- "Shortcut" values to the builtin previewer
-- merge with builtin previewer defaults
if type(opts.previewer) == "table"
or opts.previewer == true
or opts.previewer == "hidden"
or opts.previewer == "nohidden"
then
-- of type string, can only be "hidden|nohidden"
if type(opts.previewer) == "string" then
assert(opts.previewer == "hidden" or opts.previewer == "nohidden")
utils.map_set(opts, "winopts.preview.hidden", opts.previewer)
end
opts.previewer = vim.tbl_deep_extend("keep",
type(opts.previewer) == "table" and opts.previewer or {}, M.globals.previewers.builtin)
type(opts.previewer) == "table" and opts.previewer or {},
M.globals.previewers.builtin)
end

-- Convert again in case the bool option came from global opts
Expand Down
42 changes: 37 additions & 5 deletions lua/fzf-lua/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,6 @@ M.fzf = function(contents, opts)

fzf_win:attach_previewer(previewer)
local fzf_bufnr = fzf_win:create()
-- save the normalized winopts, otherwise we
-- lose overrides by 'winopts_fn|winopts_raw'
opts.winopts.preview = fzf_win.winopts.preview
-- convert "reload" actions to fzf's `reload` binds
-- convert "exec_silent" actions to fzf's `execute-silent` binds
opts = M.convert_reload_actions(opts.__reload_cmd or contents, opts)
Expand Down Expand Up @@ -464,12 +461,47 @@ M.fzf = function(contents, opts)
return selected
end

-- Best approximation of neovim border types to fzf border types
local function translate_border(winopts, metadata)
local neovim2fzf = {
none = "noborder",
single = "border-sharp",
double = "border-double",
rounded = "border-rounded",
solid = "noborder",
empty = "border-block",
shadow = "border-thinblock",
bold = "border-bold",
block = "border-block",
solidblock = "border-block",
thicc = "border-bold",
thiccc = "border-block",
thicccc = "border-block",
}
local border = winopts.border
if type(border) == "function" then
border = border(winopts, metadata)
end
border = type(border) == "string" and (neovim2fzf[border] or border) or nil
return border
end

---@param o table
---@return string
M.preview_window = function(o, fzf_win)
local layout
local prefix = string.format("%s:%s:%s",
o.winopts.preview.hidden, o.winopts.preview.border, o.winopts.preview.wrap)
local prefix = string.format("%s:%s%s",
o.winopts.preview.hidden,
o.winopts.preview.wrap,
(function()
local border = (function()
local preview_str = fzf_win:fzf_preview_layout_str()
local preview_pos = preview_str:match("[^:]+") or "right"
return translate_border(o.winopts.preview,
{ type = "fzf", name = "prev", layout = preview_pos })
end)()
return border and string.format(":%s", border) or ""
end)())
if utils.has(o, "fzf", { 0, 31 })
and o.winopts.preview.layout == "flex"
and tonumber(o.winopts.preview.flip_columns) > 0
Expand Down
34 changes: 9 additions & 25 deletions lua/fzf-lua/defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ local previewers = require "fzf-lua.previewer"
local M = {}

function M._default_previewer_fn()
local previewer = M.globals.default_previewer or M.globals.winopts.preview.default
local winopts = M.globals.winopts
if type(winopts) == "function" then
winopts = winopts() or {}
winopts.preview = type(winopts.preview) == "table" and winopts.preview or {}
winopts.preview.default = winopts.preview.default or M.defaults.winopts.preview.default
end
local previewer = M.globals.default_previewer or winopts.preview.default
-- the setup function cannot have a custom previewer as deepcopy
-- fails with stack overflow while trying to copy the custom class
-- the workaround is to define the previewer as a function instead
Expand Down Expand Up @@ -62,7 +68,7 @@ M.defaults = {
title = true,
title_pos = "center",
scrollbar = "border",
scrolloff = "-2",
scrolloff = -1,
-- default preview delay, fzf native previewers has a 100ms delay:
-- https://github.com/junegunn/fzf/issues/2417#issuecomment-809886535
delay = 20,
Expand Down Expand Up @@ -600,6 +606,7 @@ M.defaults.buffers = {
color_icons = true,
sort_lastused = true,
show_unloaded = true,
show_unlisted = false,
ignore_current_buffer = false,
no_action_set_cursor = true,
cwd_only = false,
Expand Down Expand Up @@ -1252,27 +1259,4 @@ M.defaults.__HLS = {
}
}

M.defaults.__WINOPTS = {
borderchars = {
["none"] = { "", "", "", "", "", "", "", "" },
["empty"] = { " ", " ", " ", " ", " ", " ", " ", " " },
["single"] = { "", "", "", "", "", "", "", "" },
["double"] = { "", "", "", "", "", "", "", "" },
["rounded"] = { "", "", "", "", "", "", "", "" },
["thicc"] = { "", "", "", "", "", "", "", "" },
["thiccc"] = { "", "", "", "", "", "", "", "" },
["thicccc"] = { "", "", "", "", "", "", "", "" },
},
-- border chars reverse lookup for ambiwidth="double"
border2string = {
[" "] = "empty",
[""] = "single",
[""] = "double",
[""] = "rounded",
[""] = "double",
[""] = "double",
[""] = "double",
},
}

return M
2 changes: 1 addition & 1 deletion lua/fzf-lua/devicons.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ end
function NvimWebDevicons:load(do_not_lazy_load)
-- limit devicons support to nvim >=0.8, although official support is >=0.7
-- running setup on 0.7 errs with "W18: Invalid character in group name"
if not self._package_loaded and utils.__HAS_NVIM_07
if not self._package_loaded
-- do not trigger lazy loading
and (not do_not_lazy_load or package.loaded[self._package_name])
then
Expand Down
Loading

0 comments on commit fbb652b

Please sign in to comment.