diff --git a/OPTIONS.md b/OPTIONS.md index 0522c2da..12b6bdf1 100644 --- a/OPTIONS.md +++ b/OPTIONS.md @@ -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. diff --git a/README.md b/README.md index edb38b04..ac654963 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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) @@ -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", @@ -425,21 +424,23 @@ 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 @@ -447,12 +448,12 @@ winopts = { 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() @@ -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 | diff --git a/doc/fzf-lua-opts.txt b/doc/fzf-lua-opts.txt index 60d0b233..a27089ac 100644 --- a/doc/fzf-lua-opts.txt +++ b/doc/fzf-lua-opts.txt @@ -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* @@ -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. diff --git a/lua/fzf-lua/config.lua b/lua/fzf-lua/config.lua index 00b765bd..3e234004 100644 --- a/lua/fzf-lua/config.lua +++ b/lua/fzf-lua/config.lua @@ -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 {}, winopts_fn(opts) or {}) + 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 @@ -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 @@ -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 diff --git a/lua/fzf-lua/core.lua b/lua/fzf-lua/core.lua index 2084c439..5ba44753 100644 --- a/lua/fzf-lua/core.lua +++ b/lua/fzf-lua/core.lua @@ -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) @@ -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 diff --git a/lua/fzf-lua/defaults.lua b/lua/fzf-lua/defaults.lua index e3b728e0..364bc6c2 100644 --- a/lua/fzf-lua/defaults.lua +++ b/lua/fzf-lua/defaults.lua @@ -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 + 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 @@ -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, @@ -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, @@ -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 diff --git a/lua/fzf-lua/devicons.lua b/lua/fzf-lua/devicons.lua index dd3a4990..47347bdb 100644 --- a/lua/fzf-lua/devicons.lua +++ b/lua/fzf-lua/devicons.lua @@ -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 diff --git a/lua/fzf-lua/fzf.lua b/lua/fzf-lua/fzf.lua index 451a6564..3a46cf21 100644 --- a/lua/fzf-lua/fzf.lua +++ b/lua/fzf-lua/fzf.lua @@ -221,26 +221,24 @@ function M.raw_fzf(contents, fzf_cli_args, opts) -- sending `feedkeys|startinsert` after the term job is started, this approach -- seems more consistent as it triggers when entering terminal normal mode "nt" -- NOTE: "ModeChanged" was added with neovim 0.7 - if utils.__HAS_NVIM_07 then - vim.api.nvim_create_autocmd("ModeChanged", { - once = true, - buffer = 0, - callback = function(e) - if e.match:match(":nt") then - vim.defer_fn(function() - -- Prevents inserting "i" when spamming `ctrl-g` in `grep_lgrep` - -- Also verify we're not already in TERMINAL mode, could happen - -- if the user has an autocmd for TermOpen with `startinsert` - if vim.api.nvim_buf_is_valid(e.buf) - and vim.api.nvim_get_mode().mode ~= "t" - then - vim.cmd("startinsert") - end - end, 0) - end + vim.api.nvim_create_autocmd("ModeChanged", { + once = true, + buffer = 0, + callback = function(e) + if e.match:match(":nt") then + vim.defer_fn(function() + -- Prevents inserting "i" when spamming `ctrl-g` in `grep_lgrep` + -- Also verify we're not already in TERMINAL mode, could happen + -- if the user has an autocmd for TermOpen with `startinsert` + if vim.api.nvim_buf_is_valid(e.buf) + and vim.api.nvim_get_mode().mode ~= "t" + then + vim.cmd("startinsert") + end + end, 0) end - }) - end + end + }) end if opts.debug then @@ -318,22 +316,6 @@ function M.raw_fzf(contents, fzf_cli_args, opts) -- fzf-tmux spawns outside neovim, don't set filetype/insert mode if not opts.is_fzf_tmux then vim.bo.filetype = "fzf" - - -- https://github.com/neovim/neovim/pull/15878 - -- Since patch-8.2.3461 which was released with 0.6 neovim distinguishes between - -- Normal mode and Terminal-Normal mode. However, this seems to have also introduced - -- a bug with `startinsert`: When fzf-lua reuses interfaces (e.g. called from "builtin" - -- or grep<->live_grep toggle) the current mode will be "t" which is Terminal (INSERT) - -- mode but our interface is still opened in NORMAL mode, either `startinsert` is not - -- working (as it's technically already in INSERT) or creating a new terminal buffer - -- within the same window starts in NORMAL mode while returning the wrong `nvim_get_mode` - if not utils.__HAS_NVIM_07 then - if utils.__HAS_NVIM_06 and vim.api.nvim_get_mode().mode == "t" then - utils.feed_keys_termcodes("i") - else - vim.cmd [[startinsert]] - end - end end if not utils.__IS_WINDOWS diff --git a/lua/fzf-lua/init.lua b/lua/fzf-lua/init.lua index 452dc8d9..ff228fde 100644 --- a/lua/fzf-lua/init.lua +++ b/lua/fzf-lua/init.lua @@ -127,26 +127,12 @@ function M.setup_highlights(override) hl_def.default = false end end - if utils.__HAS_NVIM_07 then - vim.api.nvim_set_hl(0, hl_name, hl_def) - else - if hl_def.link then - vim.cmd(string.format("hi! %s link %s %s", - hl_def.default and "default" or "", - hl_name, hl_def.link)) - else - vim.cmd(string.format("hi! %s %s %s%s%s", - hl_def.default and "default" or "", hl_name, - hl_def.fg and string.format(" guifg=%s", hl_def.fg) or "", - hl_def.bg and string.format(" guibg=%s", hl_def.bg) or "", - hl_def.bold and " gui=bold" or "")) - end - end + vim.api.nvim_set_hl(0, hl_name, hl_def) end -- linking to a cleared hl is bugged in neovim 0.8.x -- resulting in a pink background for hls linked to `Normal` - if vim.fn.has("nvim-0.9") == 0 and vim.fn.has("nvim-0.8") == 1 then + if not utils.__HAS_NVIM_09 and utils.__HAS_NVIM_08 then for _, a in ipairs(highlights) do local hl_name, opt_name = a[1], a[2] if utils.is_hl_cleared(hl_name) then @@ -172,8 +158,10 @@ local function load_profiles(profiles) or type(profiles) == "string" and { profiles } or {} for _, profile in ipairs(profiles) do + -- backward compat, renamed "borderless_full" > "borderless-full" + if profile == "borderless_full" then profile = "borderless-full" end local fname = path.join({ vim.g.fzf_lua_directory, "profiles", profile .. ".lua" }) - local profile_opts = utils.load_profile_fname(fname, nil, true) + local profile_opts = utils.load_profile_fname(fname, nil, 1) if type(profile_opts) == "table" then if profile_opts[1] then -- profile requires loading base profile(s) @@ -192,6 +180,8 @@ end function M.setup(opts, do_not_reset_defaults) opts = type(opts) == "table" and opts or {} + -- Default to picker info in win title (vs fzf prompt) if neovim version >= 0.9 + opts[1] = opts[1] == nil and utils.__HAS_NVIM_09 and "default-title" or opts[1] if opts[1] then -- Did the user supply profile(s) to load? opts = vim.tbl_deep_extend("keep", opts, load_profiles(opts[1])) diff --git a/lua/fzf-lua/previewer/builtin.lua b/lua/fzf-lua/previewer/builtin.lua index 391d3aa4..1f0bcd9b 100644 --- a/lua/fzf-lua/previewer/builtin.lua +++ b/lua/fzf-lua/previewer/builtin.lua @@ -99,15 +99,16 @@ function TSContext.update(winid, bufnr, opts) TSContext._winids[tostring(winid)] = bufnr end end - if TSContext.is_attached(winid) == bufnr then - open() - else - -- HACK: but the entire nvim-treesitter-context is essentially a hack - -- https://github.com/ibhagwan/fzf-lua/issues/1552#issuecomment-2525456813 - for _, t in ipairs({ 0, 20 }) do - vim.defer_fn(function() open() end, t) - end - end + -- NOTE: no longer required since adding `eventignore` to `FzfWin:set_winopts` + -- if TSContext.is_attached(winid) == bufnr then + open() + -- else + -- -- HACK: but the entire nvim-treesitter-context is essentially a hack + -- -- https://github.com/ibhagwan/fzf-lua/issues/1552#issuecomment-2525456813 + -- for _, t in ipairs({ 0, 20 }) do + -- vim.defer_fn(function() open() end, t) + -- end + -- end end end @@ -212,7 +213,8 @@ function Previewer.base:restore_winopts() end function Previewer.base:set_style_winopts() - self.win:set_winopts(self.win.preview_winid, self:gen_winopts()) + -- NOTE: `true` to ignore events for initial TSContext.update + self.win:set_winopts(self.win.preview_winid, self:gen_winopts(), true) end function Previewer.base:preview_is_terminal() @@ -322,8 +324,7 @@ function Previewer.base:clear_preview_buf(newbuf) retbuf = self:get_tmp_buffer() utils.win_set_buf_noautocmd(self.win.preview_winid, retbuf) -- redraw the title line and clear the scrollbar - self.win:redraw_preview_border() - self.win:update_scrollbar(true) + self.win:close_preview_scrollbar() end -- since our temp buffers have 'bufhidden=wipe' the tmp -- buffer will be automatically wiped and 'nvim_buf_is_valid' @@ -372,10 +373,6 @@ function Previewer.base:display_entry(entry_str) local populate_preview_buf = function(entry_str_) if not self.win or not self.win:validate_preview() then return end - -- redraw the preview border, resets title - -- border scrollbar and border highlights - self.win:redraw_preview_border() - -- specialized previewer populate function self:populate_preview_buf(entry_str_) @@ -474,7 +471,7 @@ function Previewer.base:scroll(direction) end utils.zz() end) - elseif not self:preview_is_terminal() then + else pcall(vim.api.nvim_win_call, preview_winid, function() -- ctrl-b (page-up) behaves in a non consistent way, unlike ctrl-u, if it can't -- scroll a full page upwards it won't move the cursor, if the cursor is within @@ -492,18 +489,6 @@ function Previewer.base:scroll(direction) end utils.zz() end) - else - -- we get here when using custom term commands using - -- the extensions map (i.e. view term images with 'vui') - -- we can't use ":norm!" with terminal buffers due to: - -- 'Vim(normal):Can't re-enter normal mode from terminal mode' - -- https://github.com/neovim/neovim/issues/4895#issuecomment-303073838 - -- according to the above comment feedkeys is the correct workaround - -- TODO: hide the typed command from the user (possible?) - vim.cmd("stopinsert") - utils.feed_keys_termcodes((":noa lua vim.api.nvim_win_call(" .. - [[%d, function() vim.cmd("norm! %s") vim.cmd("startinsert") end)]]) - :format(tonumber(preview_winid), input)) end -- 'cursorline' is effectively our match highlight. Once the -- user scrolls, the highlight is no longer relevant (#462). @@ -517,9 +502,9 @@ function Previewer.base:scroll(direction) self.cached_bufnrs[tostring(self.preview_bufnr)] = vim.api.nvim_win_get_cursor(preview_winid) end end - self:update_ts_context() + self.win:update_preview_scrollbar() self:update_render_markdown() - self.win:update_scrollbar() + self:update_ts_context() end function Previewer.base:ts_ctx_toggle() @@ -710,14 +695,14 @@ end function Previewer.buffer_or_file:key_from_entry(entry) assert(entry) - return entry.bufname - or entry.bufnr and string.format("bufnr:%d", entry.bufnr) + return entry.bufnr and string.format("bufnr:%d", entry.bufnr) or entry.uri or entry.path end function Previewer.buffer_or_file:populate_from_cache(entry) local key = self:key_from_entry(entry) + assert(type(key) == "string" and #key > 0) local cached = self.cached_buffers[key] assert(not cached or self.cached_bufnrs[tostring(cached.bufnr)]) assert(not cached or vim.api.nvim_buf_is_valid(cached.bufnr)) @@ -744,11 +729,13 @@ function Previewer.buffer_or_file:populate_preview_buf(entry_str) end if not self:should_load_buffer(entry) then -- same file/buffer as previous entry no need to reload content - -- call post to set cursor location, if line|col changed clear cached buffer position + -- only call post to set cursor location if type(self.cached_bufnrs[tostring(self.preview_bufnr)]) == "table" - and ((tonumber(entry.line) and entry.line ~= self.orig_pos[1]) - or (tonumber(entry.col) and entry.col - 1 ~= self.orig_pos[2])) + and ((tonumber(entry.line) and entry.line > 0 and entry.line ~= self.orig_pos[1]) + or (tonumber(entry.col) and entry.col > 0 and entry.col - 1 ~= self.orig_pos[2])) then + -- entry is within the same buffer but line|col has changed + -- clear cached buffer position so we scroll to entry's line|col self.cached_bufnrs[tostring(self.preview_bufnr)] = true end self:preview_buf_post(entry) @@ -784,7 +771,7 @@ function Previewer.buffer_or_file:populate_preview_buf(entry_str) self.preview_bufnr = vim.api.nvim_get_current_buf() else -- in case of an error display the stacktrace in the preview buffer - local lines = vim.split(res, "\n") or { "null" } + local lines = type(res) == "string" and utils.strsplit(res, "\n") or { "null" } table.insert(lines, 1, string.format("lsp.util.%s failed for '%s':", utils.__HAS_NVIM_011 and "show_document" or "jump_to_location", entry.uri)) @@ -1078,31 +1065,29 @@ function Previewer.buffer_or_file:set_cursor_hl(entry) end) end -function Previewer.buffer_or_file:update_border(entry) - if self.title then - local filepath = entry.path - if filepath then - if filepath:match("^%[DEBUG]") then - filepath = "[DEBUG]" - else - if self.opts.cwd then - filepath = path.relative_to(entry.path, self.opts.cwd) - end - filepath = path.HOME_to_tilde(filepath) +function Previewer.buffer_or_file:update_title(entry) + if not self.title then return end + local filepath = entry.path + if filepath then + if filepath:match("^%[DEBUG]") then + filepath = "[DEBUG]" + else + if self.opts.cwd then + filepath = path.relative_to(entry.path, self.opts.cwd) end + filepath = path.HOME_to_tilde(filepath) end - local title = filepath or entry.uri or entry.bufname - -- was transform function defined? - if self.title_fnamemodify then - local wincfg = vim.api.nvim_win_get_config(self.win.border_winid) - title = self.title_fnamemodify(title, wincfg and wincfg.width) - end - if entry.bufnr then - title = string.format("buf %d: %s", entry.bufnr, title) - end - self.win:update_title(" " .. title .. " ") end - self.win:update_scrollbar(entry.no_scrollbar) + local title = filepath or entry.uri or entry.bufname + -- was transform function defined? + if self.title_fnamemodify then + local wincfg = vim.api.nvim_win_get_config(self.win.preview_winid) + title = self.title_fnamemodify(title, wincfg and wincfg.width) + end + if entry.bufnr then + title = string.format("buf %d: %s", entry.bufnr, title) + end + self.win:update_preview_title(" " .. title .. " ") end function Previewer.buffer_or_file:preview_buf_post(entry, min_winopts) @@ -1127,7 +1112,13 @@ function Previewer.buffer_or_file:preview_buf_post(entry, min_winopts) end end - self:update_border(entry) + self:update_title(entry) + + if entry.no_scrollbar then + self.win:close_preview_scrollbar() + else + self.win:update_preview_scrollbar() + end -- save the loaded entry so we can compare -- bufnr|path with the next entry. If equal @@ -1222,7 +1213,7 @@ function Previewer.man_pages:populate_preview_buf(entry_str) vim.api.nvim_buf_set_lines(tmpbuf, 0, -1, false, output) vim.bo[tmpbuf].filetype = self.filetype self:set_preview_buf(tmpbuf) - self.win:update_scrollbar() + self.win:update_preview_scrollbar() end Previewer.marks = Previewer.buffer_or_file:extend() @@ -1393,7 +1384,7 @@ function Previewer.highlights:populate_preview_buf(entry_str) self.orig_pos = api.nvim_win_get_cursor(0) utils.zz() end) - self.win:update_scrollbar() + self.win:update_preview_scrollbar() end Previewer.quickfix = Previewer.base:extend() @@ -1444,8 +1435,8 @@ function Previewer.quickfix:populate_preview_buf(entry_str) vim.api.nvim_buf_set_lines(self.tmpbuf, 0, -1, false, lines) vim.bo[self.tmpbuf].filetype = "qf" self:set_preview_buf(self.tmpbuf) - self.win:update_title(string.format("%s: %s", nr, qf_list.title)) - self.win:update_scrollbar() + self.win:update_preview_title(string.format(" %s: %s ", nr, qf_list.title)) + self.win:update_preview_scrollbar() end Previewer.autocmds = Previewer.buffer_or_file:extend() diff --git a/lua/fzf-lua/previewer/codeaction.lua b/lua/fzf-lua/previewer/codeaction.lua index bb2970df..14df6537 100644 --- a/lua/fzf-lua/previewer/codeaction.lua +++ b/lua/fzf-lua/previewer/codeaction.lua @@ -263,8 +263,8 @@ function M.builtin:populate_preview_buf(entry_str) vim.api.nvim_buf_set_lines(self.tmpbuf, 0, -1, false, lines) vim.bo[self.tmpbuf].filetype = "git" self:set_preview_buf(self.tmpbuf) - self.win:update_title(string.format(" Action #%d ", idx)) - self.win:update_scrollbar() + self.win:update_preview_title(string.format(" Action #%d ", idx)) + self.win:update_preview_scrollbar() end M.native = native.base:extend() diff --git a/lua/fzf-lua/profiles/README.md b/lua/fzf-lua/profiles/README.md index 161567a5..535c483e 100644 --- a/lua/fzf-lua/profiles/README.md +++ b/lua/fzf-lua/profiles/README.md @@ -19,7 +19,7 @@ telescope defaults with `bat` previewer: | 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-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) | @@ -27,7 +27,8 @@ telescope defaults with `bat` previewer: | `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) | +| `borderless-full` | borderless with description in window title (instead of prompt) | +| `border-fused` | single border around both fzf and the previewer | **Custom user settings which make sense and aren't mere duplications with minimal modifications diff --git a/lua/fzf-lua/profiles/border-fused.lua b/lua/fzf-lua/profiles/border-fused.lua new file mode 100644 index 00000000..d79499ed --- /dev/null +++ b/lua/fzf-lua/profiles/border-fused.lua @@ -0,0 +1,65 @@ +local _single = { "┌", "─", "┐", "│", "┘", "─", "└", "│" } +local _rounded = { "╭", "─", "╮", "│", "╯", "─", "╰", "│" } +local _border = true and _rounded or _single +return { + { "default-title" }, -- base profile + desc = "Single border around the UI", + previewers = { bat = { args = "--color=always --style=default" } }, + winopts = { + border = function(_, m) + assert(m.type == "nvim" and m.name == "fzf") + if m.nwin == 1 then + -- No preview, return the border whole + return _border + else + -- has preview `nwim==2` + assert(type(m.layout) == "string") + local b = vim.deepcopy(_border) + if m.layout == "down" then + b[5] = "┤" -- bottom right + b[6] = "" -- remove bottom + b[7] = "├" -- bottom left + elseif m.layout == "up" then + b[1] = "├" --top right + b[3] = "┤" -- top left + elseif m.layout == "left" then + b[1] = "┬" -- top left + b[8] = "" -- remove left + b[7] = "┴" -- bottom right + else -- right + b[3] = "┬" -- top right + b[4] = "" -- remove right + b[5] = "┴" -- bottom right + end + return b + end + end, + preview = { + scrollbar = "border", + border = function(_, m) + if m.type == "fzf" then + -- Always return none, let `bat --style=default` to draw our border + return "none" + else + assert(m.type == "nvim" and m.name == "prev" and type(m.layout) == "string") + local b = vim.deepcopy(_border) + if m.layout == "down" then + b[1] = "├" --top right + b[3] = "┤" -- top left + elseif m.layout == "up" then + b[7] = "├" -- bottom left + b[6] = "" -- remove bottom + b[5] = "┤" -- bottom right + elseif m.layout == "left" then + b[3] = "┬" -- top right + b[5] = "┴" -- bottom right + else -- right + b[1] = "┬" -- top left + b[7] = "┴" -- bottom left + end + return b + end + end, + }, + }, +} diff --git a/lua/fzf-lua/profiles/borderless_full.lua b/lua/fzf-lua/profiles/borderless-full.lua similarity index 83% rename from lua/fzf-lua/profiles/borderless_full.lua rename to lua/fzf-lua/profiles/borderless-full.lua index 6b2f2135..7e33f69e 100644 --- a/lua/fzf-lua/profiles/borderless_full.lua +++ b/lua/fzf-lua/profiles/borderless-full.lua @@ -7,10 +7,11 @@ return { { "default-title" }, -- base profile desc = "borderless and not so minimalistic", winopts = { - border = "empty", + border = { " ", " ", " ", " ", "", "", "", " " }, -- "solid-top" (+side margins) preview = { + border = "solid", scrollbar = "float", - scrolloff = "-2", + scrolloff = "-1", title_pos = "center", }, }, diff --git a/lua/fzf-lua/profiles/borderless.lua b/lua/fzf-lua/profiles/borderless.lua index 2949974a..7aa2af76 100644 --- a/lua/fzf-lua/profiles/borderless.lua +++ b/lua/fzf-lua/profiles/borderless.lua @@ -8,19 +8,16 @@ return { winopts = { border = "none", preview = { - scrollbar = "float", - scrolloff = "-2", - title_pos = "center", + border = "none", + scrollbar = "border", }, }, hls = { border = hls.bg, preview_border = hls.bg, preview_title = hls.sel, - scrollfloat_e = "", scrollfloat_f = hls.sel, - -- TODO: not working with `scrollbar = "border"` when `border = "none" - -- scrollborder_f = "@function", + scrollborder_f = hls.bg, }, fzf_colors = { ["gutter"] = { "bg", hls.bg }, diff --git a/lua/fzf-lua/utils.lua b/lua/fzf-lua/utils.lua index 0cb71570..f9867a29 100644 --- a/lua/fzf-lua/utils.lua +++ b/lua/fzf-lua/utils.lua @@ -10,8 +10,6 @@ local uv = vim.uv or vim.loop local M = {} -M.__HAS_NVIM_06 = vim.fn.has("nvim-0.6") == 1 -M.__HAS_NVIM_07 = vim.fn.has("nvim-0.7") == 1 M.__HAS_NVIM_08 = vim.fn.has("nvim-0.8") == 1 M.__HAS_NVIM_09 = vim.fn.has("nvim-0.9") == 1 M.__HAS_NVIM_010 = vim.fn.has("nvim-0.10") == 1 @@ -843,9 +841,9 @@ end ---@param fname string ---@param name string|nil ----@param silent boolean +---@param silent boolean|number function M.load_profile_fname(fname, name, silent) - local profile = name or fname:match("([^%p]+)%.lua$") or "" + local profile = name or vim.fn.fnamemodify(fname, ":t:r") or "" local ok, res = pcall(dofile, fname) if ok and type(res) == "table" then -- success @@ -853,10 +851,10 @@ function M.load_profile_fname(fname, name, silent) M.info(string.format("Successfully loaded profile '%s'", profile)) end return res - elseif silent then - return end - if not ok then + -- If called from `setup` we set `silent=1` so we can alert the user on + -- errors loading the requested profiles + if silent ~= true and not ok then M.warn(string.format("Unable to load profile '%s': %s", profile, res:match("[^\n]+"))) elseif type(res) ~= "table" then M.warn(string.format("Unable to load profile '%s': wrong type %s", profile, type(res))) diff --git a/lua/fzf-lua/win.lua b/lua/fzf-lua/win.lua index 72e9fcda..58f07b87 100644 --- a/lua/fzf-lua/win.lua +++ b/lua/fzf-lua/win.lua @@ -167,6 +167,45 @@ function FzfWin:setup_keybinds() end function FzfWin:generate_layout(winopts) + winopts = winopts or self.winopts + -- If previewer is hidden we use full fzf layout, when previewer toggle behavior + -- is "extend" we still reduce fzf main layout as if the previewer is displayed + if not self.previewer_is_builtin + or (self.preview_hidden and self._previewer.toggle_behavior ~= "extend") + then + self.layout = { + fzf = self:normalize_border({ + row = self.winopts.row, + col = self.winopts.col, + width = self.winopts.width, + height = self.winopts.height, + border = self._o.winopts.border, + style = "minimal", + relative = self.winopts.relative or "editor", + zindex = self.winopts.zindex, + }, { type = "nvim", name = "fzf", nwin = 1 }) + } + return + end + + if self.previewer_is_builtin and self.winopts.split then + local wininfo = utils.getwininfo(self.fzf_winid) + -- unlike floating win popups, split windows inherit the global + -- 'signcolumn' setting which affects the available width for fzf + -- 'generate_layout' will then use the sign column available width + -- to assure a perfect alignment of the builtin previewer window + -- and the dummy native fzf previewer window border underneath it + local signcol_width = vim.wo[self.fzf_winid].signcolumn == "yes" and 1 or 0 + winopts = { + row = wininfo.winrow, + col = wininfo.wincol + signcol_width, + height = wininfo.height, + width = api.nvim_win_get_width(self.fzf_winid) - signcol_width, + signcol_width = signcol_width, + split = self.winopts.split, + } + end + local pwopts local row, col = winopts.row, winopts.col local height, width = winopts.height, winopts.width @@ -188,12 +227,12 @@ function FzfWin:generate_layout(winopts) end)() if winopts.split then -- Custom "split" - pwopts = { relative = "win", anchor = "NW", row = 1, col = 1 } + pwopts = { relative = "win", anchor = "NW", row = 0, col = 0 } if preview_pos == "down" or preview_pos == "up" then pwopts.width = width - 2 pwopts.height = utils.round((height) * preview_size / 100, math.huge) - 2 if preview_pos == "down" then - pwopts.row = height - pwopts.height - 1 + pwopts.row = height - pwopts.height - 2 end else -- left|right pwopts.height = height - 2 @@ -207,65 +246,49 @@ function FzfWin:generate_layout(winopts) pwopts = { relative = "editor" } if preview_pos == "down" or preview_pos == "up" then height = height - 2 - pwopts.col = col + 1 -- +border + pwopts.col = col pwopts.width = width pwopts.height = utils.round((height) * preview_size / 100, 0.5) height = height - pwopts.height if preview_pos == "down" then - -- next row +2xborder - pwopts.row = row + 1 + height + 2 - else -- up - pwopts.row = row + 1 -- +border - row = pwopts.row + 1 + pwopts.height + -- next row + pwopts.row = row + 2 + height + else -- up + pwopts.row = row + row = pwopts.row + 2 + pwopts.height end - else -- left|right + else -- left|right width = width - 2 - pwopts.row = row + 1 -- +border + pwopts.row = row pwopts.height = height pwopts.width = utils.round(width * preview_size / 100, 0.5) width = width - pwopts.width if preview_pos == "right" then - -- next col +2xborder - pwopts.col = col + 1 + width + 2 - else -- left - pwopts.col = col + 1 -- +border - col = pwopts.col + 1 + pwopts.width + -- next col + pwopts.col = col + 2 + width + else -- left + pwopts.col = col + col = pwopts.col + 2 + pwopts.width end end end - return { - fzf = { row = row, col = col, height = height, width = width }, - preview = pwopts, + self.layout = { + fzf = self:normalize_border( + vim.tbl_extend("force", { row = row, col = col, height = height, width = width }, { + style = "minimal", + border = self._o.winopts.border, + relative = self.winopts.relative or "editor", + zindex = self.winopts.zindex, + }), { type = "nvim", name = "fzf", nwin = 2, layout = preview_pos }), + preview = self:normalize_border(vim.tbl_extend("force", pwopts, { + style = "minimal", + zindex = self.winopts.zindex, + border = self._o.winopts.preview.border, + focusable = true, + }), { type = "nvim", name = "prev", nwin = 2, layout = preview_pos }) } end -local strip_borderchars_hl = function(border) - local default = nil - if type(border) == "string" then - default = config.globals.__WINOPTS.borderchars[border] - end - if not default then - default = config.globals.__WINOPTS.borderchars["rounded"] - end - if not border or type(border) ~= "table" or #border < 8 then - return default - end - local borderchars = {} - for i = 1, 8 do - if type(border[i]) == "string" then - table.insert(borderchars, #border[i] > 0 and border[i] or " ") - elseif type(border[i]) == "table" and type(border[i][1]) == "string" then - -- can happen when border chars contains a highlight, i.e: - -- border = { {'╭', 'NormalFloat'}, {'─', 'NormalFloat'}, ... } - table.insert(borderchars, #border[i][1] > 0 and border[i][1] or " ") - else - table.insert(borderchars, default[i]) - end - end - -- assert(#borderchars == 8) - return borderchars -end - function FzfWin:tmux_columns() local is_popup, is_hsplit, opt_val = (function() -- Backward compat using "fzf-tmux" script @@ -321,11 +344,95 @@ function FzfWin:fzf_preview_layout_str() return is_hsplit and self._o.winopts.preview.horizontal or self._o.winopts.preview.vertical end +--- @param winopts table +--- @return table winopts, number? scrolloff +function FzfWin:normalize_border(winopts, metadata) + local border = winopts.border + if type(border) == "function" then + border = border(winopts, metadata) + end + -- Convert boolean types + if not border then border = "none" end + if border == true then border = "rounded" end + -- nvim_open_win valid border + local valid_borders = { + none = "none", + single = "single", + double = "double", + rounded = "rounded", + solid = "solid", + empty = "solid", + shadow = "shadow", + bold = { "┏", "━", "┓", "┃", "┛", "━", "┗", "┃" }, + block = { "▛", "▀", "▜", "▐", "▟", "▄", "▙", "▌" }, + solidblock = { "█", "█", "█", "█", "█", "█", "█", "█" }, + thicc = { "┏", "━", "┓", "┃", "┛", "━", "┗", "┃" }, -- bold + thiccc = { "▛", "▀", "▜", "▐", "▟", "▄", "▙", "▌" }, -- block + thicccc = { "█", "█", "█", "█", "█", "█", "█", "█" }, -- solidblock + -- empty = { " ", " ", " ", " ", " ", " ", " ", " " }, + -- fzf preview border styles conversion of `winopts.preview.border` + ["border"] = "rounded", + ["noborder"] = "none", + ["border-none"] = "none", + ["border-rounded"] = "rounded", + ["border-sharp"] = "single", + ["border-bold"] = { "┏", "━", "┓", "┃", "┛", "━", "┗", "┃" }, + ["border-double"] = "double", + ["border-block"] = { "▛", "▀", "▜", "▐", "▟", "▄", "▙", "▌" }, + ["border-thinblock"] = { "🭽", "▔", "🭾", "▕", "🭿", "▁", "🭼", "▏" }, + ["border-horizontal"] = { "─", "─", "─", "", "─", "─", "─", "" }, + ["border-top"] = { "─", "─", "─", "", "", "", "", "" }, + ["border-bottom"] = { "", "", "", "", "─", "─", "─", "" }, + } + if type(border) == "string" then + if not valid_borders[border] then + utils.warn(string.format("Invalid border style '%s', will use 'rounded'.", border)) + border = "rounded" + else + border = valid_borders[border] + end + elseif type(border) ~= "table" then + utils.warn(string.format("Invalid border type '%s', will use 'rounded'.", type(border))) + border = "rounded" + end + if vim.o.ambiwidth == "double" and type(border) ~= "string" then + -- when ambiwdith="double" `nvim_open_win` with border chars fails: + -- with "border chars must be one cell", force string border (#874) + utils.warn(string.format( + "Invalid border type for 'ambiwidth=double', will use 'rounded'.", border)) + border = "rounded" + end + local w, h, scrolloff = 0, 0, nil + if border == "none" then + w, h, scrolloff = 2, 2, -1 + elseif type(border) == "table" then + if not border[2] or #border[2] == 0 then + h = h + 1 + end + if not border[4] or #border[4] == 0 then + w, scrolloff = w + 1, -1 + end + if not border[6] or #border[6] == 0 then + h = h + 1 + end + if not border[8] or #border[8] == 0 then + w, scrolloff = w + 1, -1 + end + end + winopts.border = border + winopts.width = tonumber(winopts.width) and (winopts.width + w) + winopts.height = tonumber(winopts.height) and (winopts.height + h) + return winopts, scrolloff +end + function FzfWin:normalize_winopts(fullscreen) -- make a local copy of winopts so we don't pollute the user's options local o, winopts = self._o, utils.tbl_deep_clone(self._o.winopts) if fullscreen then + -- NOTE: we set `winopts.relative=editor` so fullscreen + -- works even when the user set `winopts.relative=cursor` + winopts.relative = "editor" winopts.row = 1 winopts.col = 1 winopts.width = 1 @@ -347,12 +454,6 @@ function FzfWin:normalize_winopts(fullscreen) { "CursorLine", o.hls.cursorline }, { "CursorLineNr", o.hls.cursorlinenr }, }, - -- our border is manually drawn so we need - -- to replace Normal with the border color - prev_border = { - { "Normal", o.hls.preview_border }, - { "NormalFloat", o.hls.preview_border } - }, } -- add title hl if wasn't provided by the user @@ -373,8 +474,10 @@ function FzfWin:normalize_winopts(fullscreen) if winopts.relative == "cursor" then -- convert cursor relative to absolute ('editor'), -- this solves the preview positioning seamlessly - local pos = vim.api.nvim_win_get_cursor(0) - local screenpos = vim.fn.screenpos(0, pos[1], pos[2]) + -- use the calling window context for correct pos + local winid = utils.CTX().winid + local pos = vim.api.nvim_win_get_cursor(winid) + local screenpos = vim.fn.screenpos(winid, pos[1], pos[2]) winopts.row = math.floor((winopts.row or 0) + screenpos.row - 1) winopts.col = math.floor((winopts.col or 0) + screenpos.col - 1) winopts.relative = nil @@ -389,31 +492,6 @@ function FzfWin:normalize_winopts(fullscreen) winopts.row = math.min(winopts.row, max_height - winopts.height) end - -- normalize border option for nvim_open_win() - if winopts.border == false then - winopts.border = "none" - elseif not winopts.border or winopts.border == true then - winopts.border = "rounded" - end - - -- when ambiwdith="double" `nvim_open_win` with border chars fails: - -- with "border chars must be one cell", force string border (#874) - if vim.o.ambiwidth == "double" then - if type(winopts.border) == "table" then - local topleft = winopts.border[1] - winopts.border = topleft and config.globals.__WINOPTS.border2string[topleft] or "rounded" - end - winopts._border = winopts.border - elseif type(winopts.border) == "string" then - -- We only allow 'none|empty|single|double|rounded|thicc|thiccc|thiccc' - winopts.border = config.globals.__WINOPTS.borderchars[winopts.border] or - config.globals.__WINOPTS.borderchars["rounded"] - end - - -- Store a version of borderchars with no highlights - -- to be used in the border drawing functions - winopts.nohl_borderchars = strip_borderchars_hl(winopts.border) - return winopts end @@ -422,8 +500,6 @@ function FzfWin:reset_win_highlights(win) local key = "main" if win == self.preview_winid then key = "prev" - elseif win == self.border_winid then - key = "prev_border" end local hl for _, h in ipairs(self.winopts.__winhls[key]) do @@ -530,11 +606,6 @@ function FzfWin:close_backdrop() -- vim.cmd("redraw") end -local function opt_matches(opts, key, str) - local opt = opts.winopts.preview[key] or config.globals.winopts.preview[key] - return opt and opt:match(str) -end - ---@alias FzfWin table ---@param o table ---@return FzfWin @@ -563,18 +634,14 @@ function FzfWin:new(o) self.actions = o.actions self.fullscreen = o.winopts.fullscreen self.winopts = self:normalize_winopts(self.fullscreen) - self.preview_wrap = not opt_matches(o, "wrap", "nowrap") - self.preview_hidden = not opt_matches(o, "hidden", "nohidden") - self.preview_border = not opt_matches(o, "border", "noborder") + self.preview_wrap = not o.winopts.preview.wrap:match("nowrap") + self.preview_hidden = not o.winopts.preview.hidden:match("nohidden") self.keymap = o.keymap self.previewer = o.previewer self.prompt = o.prompt or o.fzf_opts["--prompt"] self:_set_autoclose(o.autoclose) -- Backward compat since removal of "border" scrollbar if self.winopts.preview.scrollbar == "border" then - self.winopts.preview.scrollbar = "float" - self.winopts.preview.scrolloff = -1 - self.winopts.preview._scroll_hide_empty = true self.hls.scrollfloat_f = false -- Reverse "FzfLuaScrollBorderFull" color if type(self.hls.scrollborder_f) == "string" then @@ -583,19 +650,9 @@ function FzfWin:new(o) if fg and #fg > 0 then local hlgroup = "FzfLuaScrollBorderBackCompat" self.hls.scrollfloat_f = hlgroup - if utils.__HAS_NVIM_07 then - vim.api.nvim_set_hl(0, hlgroup, - vim.o.termguicolors and { default = false, fg = bg, bg = fg } - or { default = false, ctermfg = tonumber(bg), ctermbg = tonumber(fg) }) - else - if vim.o.termguicolors then - vim.cmd(string.format("hi! %s guifg=%s guibg=%s", hlgroup, bg, fg)) - else - vim.cmd(string.format("hi! %s %s %s", hlgroup, - tonumber(bg) and "ctermfg=" .. tostring(bg), - tonumber(fg) and "ctermbg=" .. tostring(fg))) - end - end + vim.api.nvim_set_hl(0, hlgroup, + vim.o.termguicolors and { default = false, fg = bg, bg = fg } + or { default = false, ctermfg = tonumber(bg), ctermbg = tonumber(fg) }) end end end @@ -614,8 +671,15 @@ function FzfWin:get_winopts(win, opts) return ret end -function FzfWin:set_winopts(win, opts) +function FzfWin:set_winopts(win, opts, ignore_events) if not win or not api.nvim_win_is_valid(win) then return end + -- NOTE: Do not trigger "OptionSet" as this will trigger treesitter-context's + -- `update_single_context` which will in turn close our treesitter-context + local save_ei + if ignore_events then + save_ei = vim.o.eventignore + vim.o.eventignore = "all" + end for opt, value in pairs(opts) do if utils.nvim_has_option(opt) then -- PROBABLY DOESN'T MATTER (WHO USES 0.5?) BUT WHY NOT LOL @@ -627,6 +691,9 @@ function FzfWin:set_winopts(win, opts) pcall(function() vim.wo[win][opt] = value end) end end + if save_ei then + vim.o.eventignore = save_ei + end end function FzfWin:attach_previewer(previewer) @@ -648,133 +715,41 @@ function FzfWin:attach_previewer(previewer) self.previewer_is_builtin = previewer and type(previewer.display_entry) == "function" end -function FzfWin:preview_layout() - if self.winopts.split and self.previewer_is_builtin then - local wininfo = utils.getwininfo(self.fzf_winid) - -- unlike floating win popups, split windows inherit the global - -- 'signcolumn' setting which affects the available width for fzf - -- 'generate_layout' will then use the sign column available width - -- to assure a perfect alignment of the builtin previewer window - -- and the dummy native fzf previewer window border underneath it - local signcol_width = vim.wo[self.fzf_winid].signcolumn == "yes" and 1 or 0 - self.layout = self:generate_layout({ - row = wininfo.winrow, - col = wininfo.wincol + signcol_width, - height = wininfo.height, - width = api.nvim_win_get_width(self.fzf_winid) - signcol_width, - signcol_width = signcol_width, - split = self.winopts.split, - }) - end - if not self.layout then return {}, {} end - - local preview_opts = vim.tbl_extend("force", self.layout.preview, { - zindex = self.winopts.zindex, - style = "minimal", - focusable = true, - }) - local border_winopts = { - zindex = self.winopts.zindex - 1, - style = "minimal", - focusable = false, - relative = self.layout.preview.relative, - anchor = self.layout.preview.anchor, - width = self.layout.preview.width + 2, - height = self.layout.preview.height + 2, - col = self.layout.preview.col - 1, - row = self.layout.preview.row - 1, - } - return preview_opts, border_winopts -end - function FzfWin:validate_preview() return not self.closing - and self.preview_winid and self.preview_winid > 0 + and tonumber(self.preview_winid) + and self.preview_winid > 0 and api.nvim_win_is_valid(self.preview_winid) - and self.border_winid and self.border_winid > 0 - and api.nvim_win_is_valid(self.border_winid) -end - -function FzfWin:preview_winids() - return self.preview_winid, self.border_winid -end - -function FzfWin:redraw_preview_border() - local border_buf = self.border_buf - local border_winopts = self.border_winopts - local borderchars = self.winopts.nohl_borderchars - local width, height = border_winopts.width, border_winopts.height - local top = borderchars[1] .. borderchars[2]:rep(width - 2) .. borderchars[3] - local mid = borderchars[8] .. (" "):rep(width - 2) .. borderchars[4] - local bot = borderchars[7] .. borderchars[6]:rep(width - 2) .. borderchars[5] - local lines = { top } - for _ = 1, height - 2 do - table.insert(lines, mid) - end - table.insert(lines, bot) - if not border_buf then - border_buf = api.nvim_create_buf(false, true) - -- run nvim with `-M` will reset modifiable's default value to false - vim.bo[border_buf].modifiable = true - vim.bo[border_buf].bufhidden = "wipe" - end - api.nvim_buf_set_lines(border_buf, 0, -1, true, lines) - -- reset botder window highlights - if self.border_winid and vim.api.nvim_win_is_valid(self.border_winid) then - vim.fn.clearmatches(self.border_winid) - end - return border_buf end function FzfWin:redraw_preview() - if not self.previewer_is_builtin or self.preview_hidden then return end - - self.prev_winopts, self.border_winopts = self:preview_layout() - if utils.tbl_isempty(self.prev_winopts) or utils.tbl_isempty(self.border_winopts) then - return -1, -1 + if not self.previewer_is_builtin or self.preview_hidden then + return end - -- manual border chars looks horrible with ambiwdith="double", override border - -- window with preview window dimensions and use builtin `nvim_open_win` border - -- NOTES: - -- (1) there will be no border scroll - -- (2) preview title only when nvim >= 0.9 - if vim.o.ambiwidth == "double" then - assert(type(self.winopts._border) == "string") - self.prev_winopts = vim.tbl_extend("force", self.prev_winopts, { - col = self.border_winopts.col, - row = self.border_winopts.row, - border = self.winopts._border, - }) - self.prev_single_win = true - end + -- Close the exisiting scrollbar + self:close_preview_scrollbar() + + -- Generate the preview layout + self:generate_layout() + assert(type(self.layout.preview) == "table") if self:validate_preview() then - self.border_buf = api.nvim_win_get_buf(self.border_winid) - self:redraw_preview_border() - api.nvim_win_set_config(self.border_winid, self.border_winopts) -- since `nvim_win_set_config` removes all styling, save backup -- of the current options and restore after the call (#813) local style = self:get_winopts(self.preview_winid, self._previewer:gen_winopts()) - api.nvim_win_set_config(self.preview_winid, self.prev_winopts) + vim.api.nvim_win_set_config(self.preview_winid, self.layout.preview) self:set_winopts(self.preview_winid, style) else - local tmp_buf = api.nvim_create_buf(false, true) + local tmp_buf = self._previewer:get_tmp_buffer() -- No autocmds, can only be sent with 'nvim_open_win' - self.prev_winopts.noautocmd = true - self.border_winopts.noautocmd = true - vim.bo[tmp_buf].bufhidden = "wipe" - self.border_buf = self:redraw_preview_border() - self.preview_winid = api.nvim_open_win(tmp_buf, false, self.prev_winopts) - self.border_winid = api.nvim_open_win(self.border_buf, false, self.border_winopts) + self.preview_winid = api.nvim_open_win(tmp_buf, false, + vim.tbl_extend("force", self.layout.preview, { noautocmd = true })) -- Add win local var for the preview|border windows api.nvim_win_set_var(self.preview_winid, "fzf_lua_preview", true) - api.nvim_win_set_var(self.border_winid, "fzf_lua_preview", true) end - self:reset_win_highlights(self.border_winid) self:reset_win_highlights(self.preview_winid) self._previewer:display_last_entry() - return self.preview_winid, self.border_winid end function FzfWin:validate() @@ -784,11 +759,7 @@ end function FzfWin:redraw() self.winopts = self:normalize_winopts(self.fullscreen) - if not self.winopts.split and self.previewer_is_builtin then - self.layout = self:generate_layout(self.winopts) - end self:set_backdrop() - self:hide_scrollbar() if self:validate() then self:redraw_main() end @@ -799,54 +770,14 @@ end function FzfWin:redraw_main() if self.winopts.split then return end - local hidden = self._previewer - and self.preview_hidden - and self._previewer.toggle_behavior ~= "extend" - local relative = self.winopts.relative or "editor" - local columns, lines = vim.o.columns, vim.o.lines - if relative == "win" then - columns, lines = vim.api.nvim_win_get_width(0), vim.api.nvim_win_get_height(0) - end - -- must use clone or fullscreen overrides our values - local winopts = utils.tbl_deep_clone(self.winopts) - if self.layout and not hidden then - winopts = utils.tbl_deep_clone(self.layout.fzf) - end + self:generate_layout() - local win_opts = { - width = winopts.width or math.min(columns - 4, math.max(80, columns - 20)), - height = winopts.height or math.min(lines - 4, math.max(20, lines - 10)), - style = "minimal", - relative = relative, + local winopts = vim.tbl_extend("keep", {}, self.layout.fzf, { border = self.winopts.border, - zindex = self.winopts.zindex, title = utils.__HAS_NVIM_09 and self.winopts.title or nil, title_pos = utils.__HAS_NVIM_09 and self.winopts.title_pos or nil, - } - win_opts.row = winopts.row or math.floor(((lines - win_opts.height) / 2) - 1) - win_opts.col = winopts.col or math.floor((columns - win_opts.width) / 2) - - -- When border chars are empty strings 'nvim_open_win' adjusts - -- the layout to take all available space, we use these to adjust - -- our main window height to use all available lines (#364) - if type(win_opts.border) == "table" then - local function is_empty_str(tbl, arr) - for _, i in ipairs(arr) do - if tbl[i] and #tbl[i] > 0 then - return false - end - end - return true - end - - win_opts.height = win_opts.height - + (is_empty_str(win_opts.border, { 2 }) and 1 or 0) -- top border - + (is_empty_str(win_opts.border, { 6 }) and 1 or 0) -- bottom border - win_opts.width = win_opts.width - + (is_empty_str(win_opts.border, { 4 }) and 1 or 0) -- right border - + (is_empty_str(win_opts.border, { 8 }) and 1 or 0) -- left border - end + }) if self:validate() then if self._previewer @@ -855,12 +786,12 @@ function FzfWin:redraw_main() self._previewer:clear_preview_buf(true) self._previewer:clear_cached_buffers() end - api.nvim_win_set_config(self.fzf_winid, win_opts) + api.nvim_win_set_config(self.fzf_winid, winopts) else -- save 'cursorline' setting prior to opening the popup local cursorline = vim.o.cursorline self.fzf_bufnr = self.fzf_bufnr or vim.api.nvim_create_buf(false, true) - self.fzf_winid = utils.nvim_open_win(self.fzf_bufnr, true, win_opts) + self.fzf_winid = utils.nvim_open_win(self.fzf_bufnr, true, winopts) -- disable search highlights as they interfere with fzf's highlights if vim.o.hlsearch and vim.v.hlsearch == 1 then self.hls_on_close = true @@ -877,30 +808,20 @@ function FzfWin:redraw_main() end end -function FzfWin:_nvim_create_autocmd(e, callback, vimL) - local augroup = "FzfLua" .. e - if utils.__HAS_NVIM_07 then - vim.api.nvim_create_autocmd(e, { - group = vim.api.nvim_create_augroup(augroup, { clear = true }), - buffer = self.fzf_bufnr, - callback = callback, - }) - else - vim.cmd("augroup " .. augroup) - vim.cmd("au!") - vim.cmd(string.format([[au %s lua %s]], e, self.fzf_bufnr, vimL)) - vim.cmd("augroup END") - end +function FzfWin:_nvim_create_autocmd(e, callback) + vim.api.nvim_create_autocmd(e, { + group = vim.api.nvim_create_augroup("FzfLua" .. e, { clear = true }), + buffer = self.fzf_bufnr, + callback = callback, + }) end function FzfWin:set_redraw_autocmd() - self:_nvim_create_autocmd("VimResized", - function() self:redraw() end, - [[require("fzf-lua").redraw()]]) + self:_nvim_create_autocmd("VimResized", function() self:redraw() end) end function FzfWin:set_winleave_autocmd() - self:_nvim_create_autocmd("WinClosed", self.win_leave, [[require('fzf-lua.win').win_leave()]]) + self:_nvim_create_autocmd("WinClosed", self.win_leave) end function FzfWin:treesitter_detach(buf, noassert) @@ -1073,9 +994,6 @@ function FzfWin:create() -- Set backdrop self:set_backdrop() - if not self.winopts.split and self.previewer_is_builtin then - self.layout = self:generate_layout(self.winopts) - end -- save sending bufnr/winid self.src_bufnr = vim.api.nvim_get_current_buf() self.src_winid = vim.api.nvim_get_current_win() @@ -1084,7 +1002,13 @@ function FzfWin:create() self.cmdheight = vim.o.cmdheight if self.winopts.split then - vim.cmd(self.winopts.split) + if type(self.winopts.split) == "function" then + local curwin = vim.api.nvim_get_current_win() + self.winopts.split() + assert(curwin ~= vim.api.nvim_get_current_win(), "split function should return a new win") + else + vim.cmd(tostring(self.winopts.split)) + end local split_bufnr = vim.api.nvim_get_current_buf() self.fzf_winid = vim.api.nvim_get_current_win() if tonumber(self.fzf_bufnr) and vim.api.nvim_buf_is_valid(self.fzf_bufnr) then @@ -1131,33 +1055,13 @@ function FzfWin:create() end function FzfWin:close_preview(do_not_clear_cache) + self:close_preview_scrollbar() if self._previewer and self._previewer.close then self._previewer:close(do_not_clear_cache) end - if self.border_winid and vim.api.nvim_win_is_valid(self.border_winid) then - utils.nvim_win_close(self.border_winid, true) - end - if self.border_buf and vim.api.nvim_buf_is_valid(self.border_buf) then - vim.api.nvim_buf_delete(self.border_buf, { force = true }) - end if self.preview_winid and vim.api.nvim_win_is_valid(self.preview_winid) then utils.nvim_win_close(self.preview_winid, true) end - if self._sbuf1 and vim.api.nvim_buf_is_valid(self._sbuf1) then - vim.api.nvim_buf_delete(self._sbuf1, { force = true }) - end - if self._swin1 and vim.api.nvim_win_is_valid(self._swin1) then - utils.nvim_win_close(self._swin1, true) - end - if self._sbuf2 and vim.api.nvim_buf_is_valid(self._sbuf2) then - vim.api.nvim_buf_delete(self._sbuf2, { force = true }) - end - if self._swin2 and vim.api.nvim_win_is_valid(self._swin2) then - utils.nvim_win_close(self._swin2, true) - end - self._sbuf1, self._sbuf2, self._swin1, self._swin2 = nil, nil, nil, nil - self.border_buf = nil - self.border_winid = nil self.preview_winid = nil end @@ -1302,32 +1206,34 @@ local function ensure_tmp_buf(bufnr) return bufnr end -function FzfWin:hide_scrollbar() +function FzfWin:close_preview_scrollbar() + if self._sbuf1 and vim.api.nvim_buf_is_valid(self._sbuf1) then + vim.api.nvim_buf_delete(self._sbuf1, { force = true }) + end if self._swin1 and vim.api.nvim_win_is_valid(self._swin1) then - vim.api.nvim_win_hide(self._swin1) - self._swin1 = nil + utils.nvim_win_close(self._swin1, true) + end + if self._sbuf2 and vim.api.nvim_buf_is_valid(self._sbuf2) then + vim.api.nvim_buf_delete(self._sbuf2, { force = true }) end if self._swin2 and vim.api.nvim_win_is_valid(self._swin2) then - vim.api.nvim_win_hide(self._swin2) - self._swin2 = nil + utils.nvim_win_close(self._swin2, true) end + self._sbuf1 = nil + self._sbuf2 = nil + self._swin1 = nil + self._swin2 = nil end -function FzfWin:update_scrollbar(hide) +function FzfWin:update_preview_scrollbar() if not self.winopts.preview.scrollbar or self.winopts.preview.scrollbar == "none" or not self:validate_preview() then return end - if hide then - self:hide_scrollbar() - return - end - - local buf = api.nvim_win_get_buf(self.preview_winid) - local o = {} + local buf = api.nvim_win_get_buf(self.preview_winid) o.wininfo = utils.getwininfo(self.preview_winid) o.line_count = api.nvim_buf_line_count(buf) @@ -1337,97 +1243,71 @@ function FzfWin:update_scrollbar(hide) -- do not display on files that are fully contained if o.bar_height >= o.line_count then - self:hide_scrollbar() + self:close_preview_scrollbar() return end - local offset = self.prev_single_win and 1 or 0 - local info = o.wininfo - local style1 = {} - style1.relative = "editor" - style1.style = "minimal" - style1.focusable = false - style1.width = 1 - style1.height = info.height - style1.row = info.winrow - 1 + offset - style1.col = info.wincol + info.width + offset + - (tonumber(self.winopts.preview.scrolloff) or -2) - style1.zindex = self.winopts.zindex + 1 - -- We hide the "empty" win in `scrollbar="botder"` back compat - if not self.winopts.preview._scroll_hide_empty then + local scrolloff = self.winopts.preview.scrollbar == "border" and 0 + or tonumber(self.winopts.preview.scrolloff) or -1 + + local empty = { + style = "minimal", + focusable = false, + relative = "win", + anchor = "NW", + win = self.preview_winid, + width = 1, + height = o.wininfo.height, + zindex = self.winopts.zindex + 1, + row = 0, + col = o.wininfo.width + scrolloff + } + local full = vim.tbl_extend("keep", { + zindex = empty.zindex + 1, + height = o.bar_height, + row = empty.row + o.bar_offset, + }, empty) + -- We hide the "empty" win in `scrollbar="border"` back compat + if self.winopts.preview.scrollbar ~= "border" then if self._swin1 and vim.api.nvim_win_is_valid(self._swin1) then - vim.api.nvim_win_set_config(self._swin1, style1) + vim.api.nvim_win_set_config(self._swin1, empty) else - style1.noautocmd = true + empty.noautocmd = true self._sbuf1 = ensure_tmp_buf(self._sbuf1) - self._swin1 = vim.api.nvim_open_win(self._sbuf1, false, style1) + self._swin1 = vim.api.nvim_open_win(self._sbuf1, false, empty) local hl = self.hls.scrollfloat_e or "PmenuSbar" vim.wo[self._swin1].winhighlight = ("Normal:%s,NormalNC:%s,NormalFloat:%s,EndOfBuffer:%s"):format(hl, hl, hl, hl) end end - local style2 = utils.tbl_deep_clone(style1) - style2.height = o.bar_height - style2.row = style1.row + o.bar_offset - style2.zindex = style1.zindex + 1 if self._swin2 and vim.api.nvim_win_is_valid(self._swin2) then - vim.api.nvim_win_set_config(self._swin2, style2) + vim.api.nvim_win_set_config(self._swin2, full) else - style2.noautocmd = true + full.noautocmd = true self._sbuf2 = ensure_tmp_buf(self._sbuf2) - self._swin2 = vim.api.nvim_open_win(self._sbuf2, false, style2) + self._swin2 = vim.api.nvim_open_win(self._sbuf2, false, full) local hl = self.hls.scrollfloat_f or "PmenuThumb" vim.wo[self._swin2].winhighlight = ("Normal:%s,NormalNC:%s,NormalFloat:%s,EndOfBuffer:%s"):format(hl, hl, hl, hl) end end -function FzfWin:update_title(title) - if self.prev_single_win then - -- we are using a single window, the border window is hidden - -- under the preview window and thus meaningless to update - -- if neovim >= 0.9 we can use the builtin title params instead - if utils.__HAS_NVIM_09 then - -- since `nvim_win_set_config` removes all styling, save backup - -- of the current options and restore after the call (#813) - local style = self:get_winopts(self.preview_winid, self._previewer:gen_winopts()) - -- `nvim_win_set_config`: Invalid key: 'noautocmd' - self.prev_winopts.noautocmd = nil - api.nvim_win_set_config(self.preview_winid, vim.tbl_extend("keep", { - title = type(self.hls.preview_title) == "string" - and { { title, self.hls.preview_title } } - or title, - title_pos = self.winopts.preview.title_pos, - }, - self.prev_winopts)) - self:set_winopts(self.preview_winid, style) - end - return - end - local right_pad = 7 - local border_buf = api.nvim_win_get_buf(self.border_winid) - local top = api.nvim_buf_get_lines(border_buf, 0, 1, false)[1] - local width = fn.strwidth(top) - if #title > width - right_pad then - title = title:sub(1, width - right_pad) .. " " - end - local width_title = fn.strwidth(title) - local prefix = fn.strcharpart(top, 0, 3) - if self.winopts.preview.title_pos == "center" then - prefix = fn.strcharpart(top, 0, utils.round((width - width_title) / 2)) - elseif self.winopts.preview.title_pos == "right" then - prefix = fn.strcharpart(top, 0, width - (width_title + 3)) - end - - local suffix = fn.strcharpart(top, width_title + fn.strwidth(prefix), width) - local line = ("%s%s%s"):format(prefix, title, suffix) - pcall(api.nvim_buf_set_lines, border_buf, 0, 1, true, { line }) - - if self.hls.preview_title and #title > 0 then - pcall(vim.api.nvim_win_call, self.border_winid, function() - fn.matchaddpos(self.hls.preview_title, { { 1, #prefix + 1, #title } }, 11) - end) - end +function FzfWin:update_preview_title(title) + -- neovim >= 0.9 added window title + if not utils.__HAS_NVIM_09 or not self.layout.preview.border then return end + -- since `nvim_win_set_config` removes all styling, save backup + -- of the current options and restore after the call (#813) + local style = self:get_winopts(self.preview_winid, self._previewer:gen_winopts()) + -- `noautocmd` can only be set within `nvim_open_win` + vim.api.nvim_win_set_config(self.preview_winid, + vim.tbl_extend("force", self.layout.preview, { + title = type(self.hls.preview_title) == "string" + and { { title, self.hls.preview_title } } + or title, + title_pos = self.winopts.preview.title_pos, + })) + -- NOTE: `true` to ignore events for TSContext.update after selection change + self:set_winopts(self.preview_winid, style, true) end -- keybind methods below diff --git a/plugin/fzf-lua.lua b/plugin/fzf-lua.lua index 6f9263fe..a9a51c9e 100644 --- a/plugin/fzf-lua.lua +++ b/plugin/fzf-lua.lua @@ -4,7 +4,7 @@ vim.g.loaded_fzf_lua = 1 -- Should never be called, below nvim 0.7 "plugin/fzf-lua.vim" -- sets `vim.g.loaded_fzf_lua=1` if vim.fn.has("nvim-0.7") ~= 1 then - vim.api.nvim_err_writeln("Fzf-lua minimum requirement is Neovim versions 0.5") + vim.api.nvim_err_writeln("Fzf-lua minimum requirement is Neovim versions 0.7") return end diff --git a/plugin/fzf-lua.vim b/plugin/fzf-lua.vim deleted file mode 100644 index 3a266c3f..00000000 --- a/plugin/fzf-lua.vim +++ /dev/null @@ -1,25 +0,0 @@ -" Neovim >= v0.7 uses 'plugin/fzf-lua.lua' -if has('nvim-0.7') - finish -end - -if !has('nvim-0.5') - echohl Error - echomsg "Fzf-lua is only available for Neovim versions 0.5 and above" - echohl clear - finish -endif - -if exists('g:loaded_fzf_lua') | finish | endif -let g:loaded_fzf_lua = 1 - -" FzfLua builtin lists -function! s:fzflua_complete(arg, line, pos) abort - " Should we use `a:line[:a:pos-1]`? - let l:candidates = luaeval('require("fzf-lua.cmd")._candidates("'.a:line.'")') - return join(candidates,"\n") -endfunction - -" FzfLua commands with auto-complete -command! -nargs=* -complete=custom,s:fzflua_complete FzfLua - \ lua require("fzf-lua.cmd").run_command()