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
- Modified defaults (backward compat):
  + winopts.preview.wrap: `nowrap` -> `false`
  + winopts.preview.hidden: `nohidden` -> `false`
  + winopts.preview.border: `border` -> `rounded`
  • Loading branch information
ibhagwan committed Jan 6, 2025
1 parent 60428a8 commit 1af5676
Show file tree
Hide file tree
Showing 22 changed files with 594 additions and 656 deletions.
6 changes: 3 additions & 3 deletions OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,13 @@ Debounce time (milliseconds) for displaying the preview buffer in the builtin pr

#### globals.winopts.preview.wrap

Type: `string`, Default: `nowrap`
Type: `boolean`, Default: `false`

Line wrap in both native fzf and the builtin previewer, mapped to fzf's `--preview-window:[no]wrap` flag.

#### globals.winopts.preview.hidden

Type: `string`, Default: `nohidden`
Type: `boolean`, Default: `false`

Preview startup visibility in both native fzf and the builtin previewer, mapped to fzf's `--preview-window:[no]hidden` flag.

Expand Down 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
60 changes: 32 additions & 28 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 = "rounded", -- 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 = false, -- preview line wrap (fzf's 'wrap|nowrap')
hidden = false, -- start preview hidden
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 @@ -1248,7 +1249,7 @@ previewers = {
-- actions inherit from 'actions.files' and merge
actions = { ["enter"] = actions.complete },
-- previewer hidden by default
winopts = { preview = { hidden = "hidden" } },
winopts = { preview = { hidden = true } },
},
-- uncomment to use fzf native previewers
-- (instead of using a neovim floating window)
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 Expand Up @@ -1386,7 +1390,7 @@ vim.keymap.set({ "i" }, "<C-x><C-f>",
function()
require("fzf-lua").complete_file({
cmd = "rg --files",
winopts = { preview = { hidden = "nohidden" } }
winopts = { preview = { hidden = true } }
})
end, { silent = true, desc = "Fuzzy complete file" })
```
Expand Down
8 changes: 4 additions & 4 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: 2025 January 05

==============================================================================
Table of Contents *fzf-lua-opts-table-of-contents*
Expand Down Expand Up @@ -408,7 +408,7 @@ previewer.

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

Type: `string`, Default: `nowrap`
Type: `boolean`, Default: `false`

Line wrap in both native fzf and the builtin previewer, mapped to fzf's
`--preview-window:[no]wrap` flag.
Expand All @@ -417,7 +417,7 @@ Line wrap in both native fzf and the builtin previewer, mapped to fzf's

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

Type: `string`, Default: `nohidden`
Type: `boolean`, Default: `false`

Preview startup visibility in both native fzf and the builtin previewer,
mapped to fzf's `--preview-window:[no]hidden` flag.
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
55 changes: 44 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 All @@ -268,6 +288,14 @@ function M.normalize_opts(opts, globals, __resume_key)
if v == "" then opts.fzf_opts[k] = true end
end

-- backward compat for `winopts.preview.{wrap|hidden}`
for k, v in pairs({ wrap = "nowrap", hidden = "nohidden" }) do
local val = utils.map_get(opts, "winopts.preview." .. k)
if type(val) == "string" then
utils.map_set(opts, "winopts.preview." .. k, not val:match(v))
end
end

-- fzf.vim's `g:fzf_history_dir` (#1127)
if vim.g.fzf_history_dir and opts.fzf_opts["--history"] == nil then
local histdir = libuv.expand(vim.g.fzf_history_dir)
Expand All @@ -279,12 +307,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 +471,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 ~= "nohidden")
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
45 changes: 40 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,50 @@ 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 not border then border = "none" end
if border == true then border = "border" end
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 and "hidden" or "nohidden",
o.winopts.preview.wrap and "wrap" or "nowrap",
(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
Loading

0 comments on commit 1af5676

Please sign in to comment.