diff --git a/OPTIONS.md b/OPTIONS.md index b5f3ef63..9420f4ff 100644 --- a/OPTIONS.md +++ b/OPTIONS.md @@ -554,25 +554,37 @@ Interactive headers description highlight group, e.g. ` to Disable .giti Type: `string`, Default: `FzfLuaPathLineNr` -Highlight group for the line part of paths, e.g. `file:::`, used in pickers such as `buffers`, `lines`, `quickfix`, `lsp`, `diagnostics`, etc. +Highlight group for the line part of paths, e.g. `file:::`, used in pickers such as `buffers`, `quickfix`, `lsp`, `diagnostics`, etc. #### globals.hls.path_colnr Type: `string`, Default: `FzfLuaPathColNr` -Highlight group for the column part of paths, e.g. `file:::`, used in pickers such as `buffers`, `lines`, `quickfix`, `lsp`, `diagnostics`, etc. +Highlight group for the column part of paths, e.g. `file:::`, used in pickers such as `buffers`, `quickfix`, `lsp`, `diagnostics`, etc. #### globals.hls.buf_name Type: `string`, Default: `FzfLuaBufName` -Highlight group for buffer name in `lines`. +Highlight group for buffer name (filepath) in `lines`. + +#### globals.hls.buf_id + +Type: `string`, Default: `FzfLuaBufId` + +Highlight group for buffer id (number) in `lines`. #### globals.hls.buf_nr Type: `string`, Default: `FzfLuaBufNr` -Highlight group for buffer number in buffer type pickers, i.e. `buffers`, `tabs`, `lines`. +Highlight group for buffer number in `buffers`, `tabs`. + +#### globals.hls.buf_linenr + +Type: `string`, Default: `FzfLuaBufLineNr` + +Highlight group for buffer line number in `lines`, `blines` and `treesitter`. #### globals.hls.buf_flag_cur diff --git a/README.md b/README.md index 43f1a0dd..975c9f57 100644 --- a/README.md +++ b/README.md @@ -585,6 +585,14 @@ require'fzf-lua'.setup { -- title = "Title", -- title_pos = "center", -- 'left', 'center' or 'right' fullscreen = false, -- start fullscreen? + -- enable treesitter highlighting for the main fzf window will only have + -- effect when grep like results are present, i.e. "file:line:col:text" + -- due to highlight color collisions will also override `fzf_colors` + -- set `fzf_colors=false` or `fzf_colors.hl=...` to override + treesitter = { + enable = false, + fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" } + }, preview = { -- default = 'bat', -- override the default previewer? -- default uses the 'builtin' previewer @@ -1106,45 +1114,25 @@ require'fzf-lua'.setup { ["--with-nth"] = '2..', }, }, + -- `blines` has the same defaults as `lines` aside from prompt and `show_bufname` lines = { - previewer = "builtin", -- set to 'false' to disable prompt = 'Lines❯ ', + file_icons = true, + show_bufname = true, -- display buffer name show_unloaded = true, -- show unloaded buffers show_unlisted = false, -- exclude 'help' buffers no_term_buffers = true, -- exclude 'term' buffers + sort_lastused = true, -- sort by most recent + winopts = { treesitter = true }, -- enable TS highlights fzf_opts = { -- do not include bufnr in fuzzy matching -- tiebreak by line no. - ["--delimiter"] = "[\\]:]", - ["--nth"] = '2..', - ["--tiebreak"] = 'index', - ["--tabstop"] = "1", - }, - -- actions inherit from 'actions.files' and merge - actions = { - ["enter"] = actions.buf_edit_or_qf, - ["alt-q"] = actions.buf_sel_to_qf, - ["alt-l"] = actions.buf_sel_to_ll - }, - }, - blines = { - previewer = "builtin", -- set to 'false' to disable - prompt = 'BLines❯ ', - show_unlisted = true, -- include 'help' buffers - no_term_buffers = false, -- include 'term' buffers - -- start = "cursor" -- start display from cursor? - fzf_opts = { - -- hide filename, tiebreak by line no. - ["--delimiter"] = "[:]", - ["--with-nth"] = '2..', - ["--tiebreak"] = 'index', + ["--multi"] = true, + ["--delimiter"] = "[\t]", ["--tabstop"] = "1", - }, - -- actions inherit from 'actions.files' and merge - actions = { - ["enter"] = actions.buf_edit_or_qf, - ["alt-q"] = actions.buf_sel_to_qf, - ["alt-l"] = actions.buf_sel_to_ll + ["--tiebreak"] = "index", + ["--with-nth"] = "2..", + ["--nth"] = "4..", }, }, tags = { @@ -1418,10 +1406,12 @@ temporarily overridden by its corresponding `winopts` option: |FzfLuaHelpBorder |FzfLuaBorder |`hls.help_border` |Help win border| |FzfLuaHeaderBind |*BlanchedAlmond |`hls.header_bind` |Header keybind| |FzfLuaHeaderText |*Brown1 |`hls.header_text` |Header text| -|FzfLuaPathColNr |*CadetBlue1 |`hls.path_colnr` |Path col nr (`lines,qf,lsp,diag`)| -|FzfLuaPathLineNr |*LightGreen |`hls.path_linenr` |Path line nr (`lines,qf,lsp,diag`)| -|FzfLuaBufName |*LightMagenta |`hls.buf_name` |Buffer name (`lines`)| -|FzfLuaBufNr |*BlanchedAlmond |`hls.buf_nr` |Buffer number (all buffers)| +|FzfLuaPathColNr |*CadetBlue1 |`hls.path_colnr` |Path col nr (`qf,lsp,diag`)| +|FzfLuaPathLineNr |*LightGreen |`hls.path_linenr` |Path line nr (`qf,lsp,diag`)| +|FzfLuaBufName |Directory |`hls.buf_name` |Buffer name (`lines`)| +|FzfLuaBufId |TabLine |`hls.buf_id` |Buffer ID (`lines`)| +|FzfLuaBufNr |*BlanchedAlmond |`hls.buf_nr` |Buffer number (`buffers,tabs`)| +|FzfLuaBufLineNr |LineNr |`hls.buf_linenr` |Buffer line nr (`lines,blines`)| |FzfLuaBufFlagCur |*Brown1 |`hls.buf_flag_cur` |Buffer line (`buffers`)| |FzfLuaBufFlagAlt |*CadetBlue1 |`hls.buf_flag_alt` |Buffer line (`buffers`)| |FzfLuaTabTitle |*LightSkyBlue1 |`hls.tab_title` |Tab title (`tabs`)| diff --git a/doc/fzf-lua-opts.txt b/doc/fzf-lua-opts.txt index 4892d794..a58c0594 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 November 18 +*fzf-lua-opts.txt* For Neovim >= 0.8.0 Last change: 2024 December 10 ============================================================================== Table of Contents *fzf-lua-opts-table-of-contents* @@ -736,7 +736,7 @@ globals.hls.path_linenr *fzf-lua-opts-globals.hls.path_linenr* Type: `string`, Default: `FzfLuaPathLineNr` Highlight group for the line part of paths, e.g. `file:::`, used in -pickers such as `buffers`, `lines`, `quickfix`, `lsp`, `diagnostics`, etc. +pickers such as `buffers`, `quickfix`, `lsp`, `diagnostics`, etc. @@ -745,7 +745,7 @@ globals.hls.path_colnr *fzf-lua-opts-globals.hls.path_colnr* Type: `string`, Default: `FzfLuaPathColNr` Highlight group for the column part of paths, e.g. `file:::`, used -in pickers such as `buffers`, `lines`, `quickfix`, `lsp`, `diagnostics`, etc. +in pickers such as `buffers`, `quickfix`, `lsp`, `diagnostics`, etc. @@ -753,7 +753,15 @@ globals.hls.buf_name *fzf-lua-opts-globals.hls.buf_name* Type: `string`, Default: `FzfLuaBufName` -Highlight group for buffer name in `lines`. +Highlight group for buffer name (filepath) in `lines`. + + + +globals.hls.buf_id *fzf-lua-opts-globals.hls.buf_id* + +Type: `string`, Default: `FzfLuaBufId` + +Highlight group for buffer id (number) in `lines`. @@ -761,8 +769,15 @@ globals.hls.buf_nr *fzf-lua-opts-globals.hls.buf_nr* Type: `string`, Default: `FzfLuaBufNr` -Highlight group for buffer number in buffer type pickers, i.e. `buffers`, -`tabs`, `lines`. +Highlight group for buffer number in `buffers`, `tabs`. + + + +globals.hls.buf_linenr *fzf-lua-opts-globals.hls.buf_linenr* + +Type: `string`, Default: `FzfLuaBufLineNr` + +Highlight group for buffer line number in `lines`, `blines` and `treesitter`. diff --git a/lua/fzf-lua/config.lua b/lua/fzf-lua/config.lua index d978e38d..4e16bd17 100644 --- a/lua/fzf-lua/config.lua +++ b/lua/fzf-lua/config.lua @@ -217,18 +217,53 @@ 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)) + -- Running a command and setting `treesitter` sub-values will imply + -- `enable=true`, e.g: + -- `:FzfLua blines winopts.treesitter.fzf_colors=false` + -- `:FzfLua blines winopts.treesitter.fzf_colors={hl="-1:underline"}` + if opts.winopts + and type(opts.winopts.treesitter) == "table" + and opts.winopts.treesitter.enable ~= false + then + opts.winopts.treesitter.enable = true + end + -- Merge required tables from globals for _, k in ipairs({ - "winopts", "keymap", "fzf_opts", "fzf_tmux_opts", "hls" + "winopts", "keymap", "fzf_opts", "fzf_colors", "fzf_tmux_opts", "hls" }) do opts[k] = vim.tbl_deep_extend("keep", -- must clone or map will be saved as reference -- and then overwritten if found in 'backward_compat' type(opts[k]) == "function" and opts[k]() or opts[k] or {}, - type(M.globals[k]) == "function" and M.globals[k]() or + type(M.globals[k]) == "function" and M.globals[k](opts) or type(M.globals[k]) == "table" and utils.tbl_deep_clone(M.globals[k]) or {}) end + -- Adjust main fzf window treesitter settings + -- Disabled unless the picker is TS enabled with `_treesitter=true` + -- Unless `enable=false` is specifically set `true` is asssumed + if not opts._treesitter then opts.winopts.treesitter = nil end + if opts.winopts.treesitter and type(opts.winopts.treesitter) ~= "table" then + opts.winopts.treesitter = {} + end + if not opts.winopts.treesitter or opts.winopts.treesitter.enable == false then + opts.winopts.treesitter = nil + else + assert(type(opts.winopts.treesitter) == "table") + -- Unless the caller specifically disables `fzf_colors` fuzzy matching + -- colors "hl,hl+" will be set to "-1:reverse" which sets the background + -- color for matches to the corresponding original foreground color + -- NOTE: `fzf_colors` inherited from `defaults.winopts.treesitter` + if opts.winopts.treesitter.fzf_colors ~= false then + opts.fzf_colors = vim.tbl_deep_extend("force", + opts.fzf_colors or {}, + M.defaults.winopts.treesitter.fzf_colors, + type(opts.winopts.treesitter.fzf_colors) == "table" + and opts.winopts.treesitter.fzf_colors or {}) + end + end + -- backward compat: no-value flags should be set to `true`, in the past these -- would be set to an empty string which would now translate into a shell escaped -- string as we automatically shell escape all fzf_opts diff --git a/lua/fzf-lua/core.lua b/lua/fzf-lua/core.lua index 3d47c7ab..d2cb0c0c 100644 --- a/lua/fzf-lua/core.lua +++ b/lua/fzf-lua/core.lua @@ -498,9 +498,6 @@ end -- Create fzf --color arguments from a table of vim highlight groups. M.create_fzf_colors = function(opts) local colors = opts and opts.fzf_colors - if type(colors) == "function" then - colors = colors(opts) - end -- auto create `fzf_colors` based on Neovim's current colorscheme if colors == true then colors = { @@ -622,15 +619,6 @@ end ---@param opts table ---@return string[] M.build_fzf_cli = function(opts, fzf_win) - opts.fzf_opts = vim.tbl_extend("force", config.globals.fzf_opts, opts.fzf_opts or {}) - -- copy/merge from globals - for _, o in ipairs({ "fzf_colors", "keymap" }) do - if opts[o] == nil then - opts[o] = config.globals[o] - elseif type(opts[o]) == "table" and type(config.globals[o]) == "table" then - opts[o] = vim.tbl_deep_extend("keep", opts[o], config.globals[o]) - end - end -- below options can be specified directly in opts and will be -- prioritized: opts. is prioritized over fzf_opts["--name"] for _, flag in ipairs({ "query", "prompt", "header", "preview" }) do diff --git a/lua/fzf-lua/defaults.lua b/lua/fzf-lua/defaults.lua index d2e74922..477e6336 100644 --- a/lua/fzf-lua/defaults.lua +++ b/lua/fzf-lua/defaults.lua @@ -49,6 +49,10 @@ M.defaults = { zindex = 50, backdrop = 60, fullscreen = false, + treesitter = { + enable = false, + fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" } + }, preview = { default = "builtin", border = "border", @@ -426,8 +430,11 @@ M.defaults.git = { ["ctrl-t"] = actions.git_buf_tabedit, ["ctrl-y"] = { fn = actions.git_yank_commit, exec_silent = true }, }, + winopts = { treesitter = true }, fzf_opts = { ["--no-multi"] = true }, _multiline = false, + -- `winopts.treesitter==true` line match format + _treesitter = "(%s+)(%d+)%)(.+)$", }, branches = { prompt = "Branches> ", @@ -505,8 +512,20 @@ M.defaults.grep = { -- live_grep_glob options glob_flag = "--iglob", -- for case sensitive globs use '--glob' glob_separator = "%s%-%-", -- query separator pattern (lua): ' --' + _treesitter = true, } +M.defaults.grep_curbuf = vim.tbl_deep_extend("force", M.defaults.grep, { + prompt = "BufRg> ", + rg_glob = false, -- meaningless for single file rg + exec_empty_query = true, -- makes sense to display lines immediately + fzf_opts = { + ["--delimiter"] = "[:]", + ["--with-nth"] = "2..", + ["--nth"] = "2..", + }, +}) + M.defaults.args = { previewer = M._default_previewer_fn, prompt = "Args> ", @@ -542,6 +561,7 @@ M.defaults.quickfix = { fzf_opts = { ["--multi"] = true }, _actions = function() return M.globals.actions.files end, only_valid = false, + _treesitter = true, _cached_hls = { "path_colnr", "path_linenr" }, } @@ -563,6 +583,7 @@ M.defaults.loclist = { fzf_opts = { ["--multi"] = true }, _actions = function() return M.globals.actions.files end, only_valid = false, + _treesitter = true, _cached_hls = { "path_colnr", "path_linenr" }, } @@ -620,51 +641,50 @@ M.defaults.lines = { prompt = "Lines> ", file_icons = true and M._has_devicons, color_icons = true, + show_bufname = 120, show_unloaded = true, show_unlisted = false, no_term_buffers = true, + sort_lastused = true, + winopts = { treesitter = true }, fzf_opts = { ["--multi"] = true, - ["--delimiter"] = "[\\]:]", - ["--nth"] = "2..", + ["--delimiter"] = "[\t]", + ["--tabstop"] = "1", ["--tiebreak"] = "index", + ["--with-nth"] = "2..", + ["--nth"] = "4..", + }, + line_field_index = "{4}", + field_index_expr = "{}", -- For `_fmt.from` to work with `bat_native` + _treesitter = true, + _cached_hls = { "buf_id", "buf_name", "buf_linenr" }, + _fmt = { + -- NOTE: `to` is not needed, we format at the source in `buffer_lines` + to = false, + from = function(s, _) + -- restore the format to something that `path.entry_to_file` can handle + local bufnr, lnum, text = s:match("%[(%d+)%].-(%d+) (.+)$") + if not bufnr then return "" end + return string.format("[%s]%s%s:%s:%s", + bufnr, utils.nbsp, + path.tail(vim.api.nvim_buf_get_name(tonumber(bufnr))), + lnum, text) + end }, - line_field_index = "{3}", _actions = function() return M.globals.actions.buffers or M.globals.actions.files end, - actions = { - ["enter"] = actions.buf_edit_or_qf, - ["alt-q"] = actions.buf_sel_to_qf, - ["alt-l"] = actions.buf_sel_to_ll - }, - _cached_hls = { "buf_name", "buf_nr", "path_linenr" }, } -M.defaults.blines = { - previewer = M._default_previewer_fn, - prompt = "BLines> ", - file_icons = false, - color_icons = false, - show_unlisted = true, - no_term_buffers = false, - fzf_opts = { - ["--multi"] = true, - ["--delimiter"] = "[:]", - ["--with-nth"] = "2..", - ["--tiebreak"] = "index", - }, - line_field_index = "{2}", - _actions = function() - return M.globals.actions.buffers or M.globals.actions.files - end, - actions = { - ["enter"] = actions.buf_edit_or_qf, - ["alt-q"] = actions.buf_sel_to_qf, - ["alt-l"] = actions.buf_sel_to_ll +M.defaults.blines = vim.tbl_deep_extend("force", M.defaults.lines, { + prompt = "BLines> ", + show_bufname = false, + fzf_opts = { + ["--with-nth"] = "4..", + ["--nth"] = "2..", }, - _cached_hls = { "buf_name", "buf_nr", "path_linenr" }, -} +}) M.defaults.treesitter = { previewer = M._default_previewer_fn, @@ -673,6 +693,7 @@ M.defaults.treesitter = { color_icons = false, fzf_opts = { ["--multi"] = true, + ["--tabstop"] = "4", ["--delimiter"] = "[:]", ["--with-nth"] = "2..", }, @@ -680,7 +701,13 @@ M.defaults.treesitter = { _actions = function() return M.globals.actions.buffers or M.globals.actions.files end, - _cached_hls = { "buf_name", "buf_nr", "path_linenr", "path_colnr" }, + _cached_hls = { "buf_name", "buf_nr", "buf_linenr", "path_colnr" }, + _fmt = { + to = false, + from = function(s, _) + return s:gsub("\t\t", ": ") + end + }, } M.defaults.tags = { @@ -735,9 +762,10 @@ M.defaults.colorschemes = { } M.defaults.highlights = { - prompt = "Highlights> ", - fzf_opts = { ["--no-multi"] = true }, - previewer = { _ctor = previewers.builtin.highlights, }, + prompt = "Highlights> ", + fzf_opts = { ["--no-multi"] = true }, + fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" }, + previewer = { _ctor = previewers.builtin.highlights, }, } M.defaults.awesome_colorschemes = { @@ -806,6 +834,7 @@ M.defaults.lsp = { fzf_opts = { ["--multi"] = true }, _actions = function() return M.globals.actions.files end, _cached_hls = { "path_colnr", "path_linenr" }, + _treesitter = true, -- Signals actions to use uri triggering the use of `lsp.util.show_document` _uri = true, } @@ -912,6 +941,7 @@ M.defaults.lsp.finder = { { "outgoing_calls", prefix = utils.ansi_codes.yellow("out ") }, }, fzf_opts = { ["--multi"] = true }, + _treesitter = true, _cached_hls = { "path_colnr", "path_linenr" }, _uri = true, } @@ -964,6 +994,7 @@ M.defaults.profiles = { fzf_opts = { ["--delimiter"] = "[:]", ["--with-nth"] = "-1..", + ["--tiebreak"] = "begin", ["--no-multi"] = true, }, actions = { ["enter"] = actions.apply_profile }, @@ -1189,7 +1220,9 @@ M.defaults.__HLS = { path_colnr = "FzfLuaPathColNr", path_linenr = "FzfLuaPathLineNr", buf_name = "FzfLuaBufName", + buf_id = "FzfLuaBufId", buf_nr = "FzfLuaBufNr", + buf_linenr = "FzfLuaBufLineNr", buf_flag_cur = "FzfLuaBufFlagCur", buf_flag_alt = "FzfLuaBufFlagAlt", tab_title = "FzfLuaTabTitle", diff --git a/lua/fzf-lua/init.lua b/lua/fzf-lua/init.lua index 69a4dfb7..db0bb73d 100644 --- a/lua/fzf-lua/init.lua +++ b/lua/fzf-lua/init.lua @@ -81,24 +81,26 @@ function M.setup_highlights(override) { default = default, fg = is_light and "MediumSpringGreen" or "BlanchedAlmond" } }, { "FzfLuaHeaderText", "header_text", { default = default, fg = is_light and "Brown4" or "Brown1" } }, - { "FzfLuaPathColNr", "path_colnr", -- lines|blines|qf|diag|lsp + { "FzfLuaPathColNr", "path_colnr", -- qf|diag|lsp { default = default, fg = is_light and "CadetBlue4" or "CadetBlue1" } }, - { "FzfLuaPathLineNr", "path_linenr", -- lines|blines|qf|diag|lsp + { "FzfLuaPathLineNr", "path_linenr", -- qf|diag|lsp { default = default, fg = is_light and "MediumSpringGreen" or "LightGreen" } }, - { "FzfLuaLiveSym", "live_sym", + { "FzfLuaLiveSym", "live_sym", -- lsp_live_workspace_symbols query { default = default, fg = is_light and "Brown4" or "Brown1" } }, - -- Provider specific highlights - { "FzfLuaBufName", "buf_name", -- lines|blines (hidden) - { default = default, fg = is_light and "DarkOrchid3" or "LightMagenta" } }, - { "FzfLuaBufNr", "buf_nr", -- buffers|tabs|lines|blines + -- lines|blines|treesitter + { "FzfLuaBufId", "buf_id", { default = default, link = "TabLine" } }, + { "FzfLuaBufName", "buf_name", { default = default, link = "Directory" } }, + { "FzfLuaBufLineNr", "buf_linenr", { default = default, link = "LineNr" } }, + -- buffers|tabs + { "FzfLuaBufNr", "buf_nr", { default = default, fg = is_light and "AquaMarine3" or "BlanchedAlmond" } }, - { "FzfLuaBufFlagCur", "buf_flag_cur", -- buffers|tabs + { "FzfLuaBufFlagCur", "buf_flag_cur", { default = default, fg = is_light and "Brown4" or "Brown1" } }, - { "FzfLuaBufFlagAlt", "buf_flag_alt", -- buffers|tabs + { "FzfLuaBufFlagAlt", "buf_flag_alt", { default = default, fg = is_light and "CadetBlue4" or "CadetBlue1" } }, - { "FzfLuaTabTitle", "tab_title", -- tabs + { "FzfLuaTabTitle", "tab_title", -- tabs only { default = default, fg = is_light and "CadetBlue4" or "LightSkyBlue1", bold = true } }, - { "FzfLuaTabMarker", "tab_marker", -- tabs + { "FzfLuaTabMarker", "tab_marker", -- tabs only { default = default, fg = is_light and "MediumSpringGreen" or "BlanchedAlmond", bold = true } }, -- highlight groups for `fzf_colors=true` { "FzfLuaFzfNormal", "fzf.normal", { default = default, link = "FzfLuaNormal" } }, diff --git a/lua/fzf-lua/profiles/default-title.lua b/lua/fzf-lua/profiles/default-title.lua index 1fa07c71..ecac1d0f 100644 --- a/lua/fzf-lua/profiles/default-title.lua +++ b/lua/fzf-lua/profiles/default-title.lua @@ -18,6 +18,7 @@ return { blines = title("Buffer Lines"), treesitter = title("Treesitter"), grep = title("Grep", { prompt = "> " }), + grep_curbuf = title("Buffer Grep", { prompt = "> " }), git = { files = title("Git Files"), status = title("Git Status"), @@ -43,7 +44,7 @@ return { lsp = { title_prefix = "LSP", winopts = { title_pos = "center" }, - symbols = { title_prefix = "LSP", winopts = { title_pos = "center" } }, + symbols = { prompt = "> ", title_prefix = "LSP", winopts = { title_pos = "center" } }, finder = title("LSP Finder"), code_actions = title("Code Actions"), }, diff --git a/lua/fzf-lua/profiles/fzf-tmux.lua b/lua/fzf-lua/profiles/fzf-tmux.lua index cd31ffd9..c59b2adf 100644 --- a/lua/fzf-lua/profiles/fzf-tmux.lua +++ b/lua/fzf-lua/profiles/fzf-tmux.lua @@ -9,4 +9,6 @@ return { lsp = { code_actions = { previewer = "codeaction_native" } }, tags = { previewer = "bat" }, btags = { previewer = "bat" }, + lines = { ["winopts.treesitter"] = false }, + blines = { ["winopts.treesitter"] = false }, } diff --git a/lua/fzf-lua/profiles/telescope.lua b/lua/fzf-lua/profiles/telescope.lua index e99e8408..3e641614 100644 --- a/lua/fzf-lua/profiles/telescope.lua +++ b/lua/fzf-lua/profiles/telescope.lua @@ -50,7 +50,7 @@ return { ["hl+"] = { "fg", "TelescopeMatching" }, ["info"] = { "fg", "TelescopeMultiSelection" }, ["border"] = { "fg", "TelescopeBorder" }, - ["gutter"] = { "bg", "TelescopeNormal" }, + ["gutter"] = "-1", ["query"] = { "fg", "TelescopePromptNormal" }, ["prompt"] = { "fg", "TelescopePromptPrefix" }, ["pointer"] = { "fg", "TelescopeSelectionCaret" }, diff --git a/lua/fzf-lua/providers/buffers.lua b/lua/fzf-lua/providers/buffers.lua index e9f7d6a3..71504790 100644 --- a/lua/fzf-lua/providers/buffers.lua +++ b/lua/fzf-lua/providers/buffers.lua @@ -59,49 +59,58 @@ local filter_buffers = function(opts, unfiltered) return bufnrs, excluded, max_bufnr end + +local getbuf = function(buf) + return { + bufnr = buf, + flag = (buf == core.CTX().bufnr and "%") + or (buf == core.CTX().alt_bufnr and "#") or " ", + info = utils.getbufinfo(buf), + readonly = vim.bo[buf].readonly + } +end + +-- switching buffers and opening 'buffers' in quick succession +-- can lead to incorrect sort as 'lastused' isn't updated fast +-- enough (neovim bug?), this makes sure the current buffer is +-- always on top (#646) +-- Hopefully this gets solved before the year 2100 +-- DON'T FORCE ME TO UPDATE THIS HACK NEOVIM LOL +local _FUTURE = os.time({ year = 2100, month = 1, day = 1, hour = 0, minute = 00 }) +local get_unixtime = function(buf) + if tonumber(buf) then + -- When called from `buffer_lines` + buf = getbuf(buf) + end + if buf.flag == "%" then + return _FUTURE + elseif buf.flag == "#" then + return _FUTURE - 1 + else + return buf.info.lastused + end +end + local populate_buffer_entries = function(opts, bufnrs, winid) local buffers = {} for _, bufnr in ipairs(bufnrs) do - local flag = (bufnr == core.CTX().bufnr and "%") - or (bufnr == core.CTX().alt_bufnr and "#") or " " - - local element = { - bufnr = bufnr, - flag = flag, - info = utils.getbufinfo(bufnr), - readonly = vim.bo[bufnr].readonly - } + local buf = getbuf(bufnr) -- Get the name for missing/quickfix/location list buffers -- NOTE: we get it here due to `gen_buffer_entry` called within a fast event - if not element.info.name or #element.info.name == 0 then - element.info.name = utils.nvim_buf_get_name(element.bufnr, element.info) + if not buf.info.name or #buf.info.name == 0 then + buf.info.name = utils.nvim_buf_get_name(buf.bufnr, buf.info) end -- get the correct lnum for tabbed buffers if winid then - element.info.lnum = vim.api.nvim_win_get_cursor(winid)[1] + buf.info.lnum = vim.api.nvim_win_get_cursor(winid)[1] end - table.insert(buffers, element) + table.insert(buffers, buf) end + if opts.sort_lastused then - -- switching buffers and opening 'buffers' in quick succession - -- can lead to incorrect sort as 'lastused' isn't updated fast - -- enough (neovim bug?), this makes sure the current buffer is - -- always on top (#646) - -- Hopefully this gets solved before the year 2100 - -- DON'T FORCE ME TO UPDATE THIS HACK NEOVIM LOL - local future = os.time({ year = 2100, month = 1, day = 1, hour = 0, minute = 00 }) - local get_unixtime = function(buf) - if buf.flag == "%" then - return future - elseif buf.flag == "#" then - return future - 1 - else - return buf.info.lastused - end - end table.sort(buffers, function(a, b) return get_unixtime(a) > get_unixtime(b) end) @@ -221,9 +230,6 @@ end M.buffer_lines = function(opts) if not opts then return end - -- formatter doesn't work with lines|blines as only filename is displayed - opts._fmt = false - opts.fn_pre_fzf = function() core.CTX(true) end opts.fn_pre_fzf() @@ -242,10 +248,28 @@ M.buffer_lines = function(opts) local buffers = filter_buffers(opts, opts.current_buffer_only and { core.CTX().bufnr } or core.CTX().buflist) + if opts.sort_lastused and utils.tbl_count(buffers) > 1 then + table.sort(buffers, function(a, b) + return get_unixtime(a) > get_unixtime(b) + end) + end + + local bnames = {} + local longest_bname = 0 + for _, b in ipairs(buffers) do + local bname = utils.nvim_buf_get_name(b) + if not bname:match("^%[") then + bname = path.shorten(vim.fn.fnamemodify(bname, ":~:.")) + end + longest_bname = math.max(longest_bname, #bname) + bnames[tostring(b)] = bname + end + local len_bufnames = math.min(15, longest_bname) + for _, bufnr in ipairs(buffers) do local data = {} - local bufname, buficon, hl - -- use vim.schedule to avoid + + -- Use vim.schedule to avoid -- E5560: vimL function must not be called in a lua loop callback vim.schedule(function() local filepath = vim.api.nvim_buf_get_name(bufnr) @@ -254,22 +278,35 @@ M.buffer_lines = function(opts) elseif vim.fn.filereadable(filepath) ~= 0 then data = vim.fn.readfile(filepath, "") end - bufname = path.basename(filepath) - if opts.file_icons then - buficon, hl = devicons.get_devicon(bufname) - if hl and opts.color_icons then - buficon = utils.ansi_from_rgb(hl, buficon) - end - end - if not bufname or #bufname == 0 then - bufname = utils.nvim_buf_get_name(bufnr) - end coroutine.resume(co) end) -- wait for vim.schedule coroutine.yield() + local bname, bicon = (function() + if not opts.show_bufname + or tonumber(opts.show_bufname) and tonumber(opts.show_bufname) > vim.o.columns + then + return + end + local bicon, hl = "", nil + local bname = bnames[tostring(bufnr)] + assert(bname) + + if #bname > len_bufnames + 1 then + bname = "…" .. bname:sub(#bname - len_bufnames + 2) + end + + if opts.file_icons then + bicon, hl = devicons.get_devicon(bname) + if hl and opts.color_icons then + bicon = utils.ansi_from_rgb(hl, bicon) + end + end + return bname, bicon and bicon .. utils.nbsp or nil + end)() + local offset, lines = 0, #data if opts.current_buffer_only and opts.start == "cursor" then -- start display from current line and wrap from bottom (#822) @@ -281,14 +318,20 @@ M.buffer_lines = function(opts) if lnum > lines then lnum = lnum % lines end - add_entry(string.format("[%s]%s%s%s%s:%s: %s", - utils.ansi_codes[opts.hls.buf_nr](tostring(bufnr)), - utils.nbsp, - buficon or "", - buficon and utils.nbsp or "", - utils.ansi_codes[opts.hls.buf_name](bufname), - utils.ansi_codes[opts.hls.path_linenr](tostring(lnum)), - data[lnum]), co) + + -- NOTE: Space after `lnum` is U+00A0 (decimal: 160) + add_entry(string.format("[%s]\t%s\t%s%s\t%s \t%s", + tostring(bufnr), + utils.ansi_codes[opts.hls.buf_id](string.format("%3d", bufnr)), + bicon or "", + not bname and "" or utils.ansi_codes[opts.hls.buf_name](string.format( + "%" + .. (opts.file_icons and "-" or "") + .. tostring(len_bufnames) .. "s", + bname)), + utils.ansi_codes[opts.hls.buf_linenr](string.format("%5d", lnum)), + data[lnum] + ), co) end end cb(nil) @@ -450,11 +493,11 @@ M.treesitter = function(opts) local lnum, col, _, _ = vim.treesitter.get_node_range(node.node) local node_text = vim.treesitter.get_node_text(node.node, opts.bufnr) local node_kind = node.kind and utils.ansi_from_hl(kind2hl(node.kind), node.kind) - local entry = string.format("[%s]%s%s:%s:%s:\t[%s] %s", + local entry = string.format("[%s]%s%s:%s:%s\t\t[%s] %s", utils.ansi_codes[opts.hls.buf_nr](tostring(opts.bufnr)), utils.nbsp, utils.ansi_codes[opts.hls.buf_name](opts._bufname), - utils.ansi_codes[opts.hls.path_linenr](tostring(lnum + 1)), + utils.ansi_codes[opts.hls.buf_linenr](tostring(lnum + 1)), utils.ansi_codes[opts.hls.path_colnr](tostring(col + 1)), node_kind or "", node_text) diff --git a/lua/fzf-lua/providers/grep.lua b/lua/fzf-lua/providers/grep.lua index 4ed1fa33..17748a52 100644 --- a/lua/fzf-lua/providers/grep.lua +++ b/lua/fzf-lua/providers/grep.lua @@ -163,6 +163,10 @@ M.grep = function(opts) end local function normalize_live_grep_opts(opts) + -- disable treesitter as it collides with cmd regex highlighting + opts = opts or {} + opts._treesitter = false + opts = config.normalize_opts(opts, "grep") if not opts then return end @@ -407,27 +411,25 @@ M.grep_project = function(opts) end M.grep_curbuf = function(opts, lgrep) - if type(opts) == "function" then - opts = opts() - elseif not opts then - opts = {} - end - opts.filename = vim.api.nvim_buf_get_name(0) + -- call `normalize_opts` here as we want to store all previous + -- options in the resume data store under the key "bgrep" + -- 3rd arg is an override for resume data store lookup key + opts = config.normalize_opts(opts, "grep_curbuf", "bgrep") + if not opts then return end + + opts.filename = vim.api.nvim_buf_get_name(core.CTX().bufnr) if #opts.filename == 0 or not uv.fs_stat(opts.filename) then utils.info("Rg current buffer requires file on disk") return else opts.filename = path.relative_to(opts.filename, uv.cwd()) end - -- rg globs are meaningless here since we searching a single file - opts.rg_glob = false - opts.exec_empty_query = opts.exec_empty_query == nil and true - opts.fzf_opts = vim.tbl_extend("keep", opts.fzf_opts or {}, config.globals.blines.fzf_opts) - -- call `normalize_opts` here as we want to store all previous - -- options in the resume data store under the key "bgrep" - -- 3rd arg is an override for resume data store lookup key - opts = config.normalize_opts(opts, "grep", "bgrep") - if not opts then return end + + -- Persist call options so we don't revert to global grep on `grep_lgrep` + opts.__call_opts = vim.tbl_deep_extend("keep", + opts.__call_opts or {}, config.globals.grep_curbuf) + opts.__call_opts.filename = opts.filename + if lgrep then return M.live_grep(opts) else diff --git a/lua/fzf-lua/providers/helptags.lua b/lua/fzf-lua/providers/helptags.lua index 12f2a89a..3f30f26e 100644 --- a/lua/fzf-lua/providers/helptags.lua +++ b/lua/fzf-lua/providers/helptags.lua @@ -3,104 +3,101 @@ local core = require "fzf-lua.core" local utils = require "fzf-lua.utils" local config = require "fzf-lua.config" - local M = {} -local fzf_fn = function(cb) - local opts = {} - opts.lang = config.globals.helptags.lang or vim.o.helplang - opts.fallback = config.globals.helptags.fallback == nil and true - or config.globals.helptags.fallback +M.helptags = function(opts) + opts = config.normalize_opts(opts, "helptags") + if not opts then return end - local langs = vim.split(opts.lang, ",") - if opts.fallback and not utils.tbl_contains(langs, "en") then - table.insert(langs, "en") - end - local langs_map = {} - for _, lang in ipairs(langs) do - langs_map[lang] = true - end + local contents = function(cb) + opts.lang = opts.lang or vim.o.helplang + opts.fallback = opts.fallback ~= false and true - local tag_files = {} - local function add_tag_file(lang, file) - if langs_map[lang] then - if tag_files[lang] then - table.insert(tag_files[lang], file) - else - tag_files[lang] = { file } + local langs = vim.split(opts.lang, ",") + if opts.fallback and not utils.tbl_contains(langs, "en") then + table.insert(langs, "en") + end + local langs_map = {} + for _, lang in ipairs(langs) do + langs_map[lang] = true + end + + local tag_files = {} + local function add_tag_file(lang, file) + if langs_map[lang] then + if tag_files[lang] then + table.insert(tag_files[lang], file) + else + tag_files[lang] = { file } + end end end - end - local help_files = {} - local rtp = vim.o.runtimepath - -- If using lazy.nvim, get all the lazy loaded plugin paths (#1296) - local lazy = package.loaded["lazy.core.util"] - if lazy and lazy.get_unloaded_rtp then - local paths = lazy.get_unloaded_rtp("") - rtp = rtp .. "," .. table.concat(paths, ",") - end - local all_files = vim.fn.globpath(rtp, "doc/*", 1, 1) - for _, fullpath in ipairs(all_files) do - local file = path.tail(fullpath) - if file == "tags" then - add_tag_file("en", fullpath) - elseif file:match("^tags%-..$") then - local lang = file:sub(-2) - add_tag_file(lang, fullpath) - else - help_files[file] = fullpath + local help_files = {} + local rtp = vim.o.runtimepath + -- If using lazy.nvim, get all the lazy loaded plugin paths (#1296) + local lazy = package.loaded["lazy.core.util"] + if lazy and lazy.get_unloaded_rtp then + local paths = lazy.get_unloaded_rtp("") + rtp = rtp .. "," .. table.concat(paths, ",") + end + local all_files = vim.fn.globpath(rtp, "doc/*", 1, 1) + for _, fullpath in ipairs(all_files) do + local file = path.tail(fullpath) + if file == "tags" then + add_tag_file("en", fullpath) + elseif file:match("^tags%-..$") then + local lang = file:sub(-2) + add_tag_file(lang, fullpath) + else + help_files[file] = fullpath + end end - end - local hl = (function() - local _, _, fn = utils.ansi_from_hl("Label", "foo") - return function(s) return fn(s) end - end)() + local hl = (function() + local _, _, fn = utils.ansi_from_hl("Label", "foo") + return function(s) return fn(s) end + end)() - local add_tag = function(t, fzf_cb, co) - local tag = string.format("%-80s %s%s%s", hl(t.tag), t.filename, utils.nbsp, t.filepath) - fzf_cb(tag, function() - coroutine.resume(co) - end) - end + local add_tag = function(t, fzf_cb, co) + local tag = string.format("%-80s %s%s%s", hl(t.tag), t.filename, utils.nbsp, t.filepath) + fzf_cb(tag, function() + coroutine.resume(co) + end) + end - coroutine.wrap(function() - local co = coroutine.running() - local tags_map = {} - local delimiter = string.char(9) - for _, lang in ipairs(langs) do - for _, file in ipairs(tag_files[lang] or {}) do - local lines = vim.split(utils.read_file(file), "\n") - for _, line in ipairs(lines) do - -- TODO: also ignore tagComment starting with ';' - if not line:match "^!_TAG_" then - local fields = vim.split(line, delimiter) - if #fields == 3 and not tags_map[fields[1]] then - add_tag({ - tag = fields[1], - filename = fields[2], - filepath = help_files[fields[2]], - cmd = fields[3], - lang = lang, - }, cb, co) - tags_map[fields[1]] = true - -- pause here until we call coroutine.resume() - coroutine.yield() + coroutine.wrap(function() + local co = coroutine.running() + local tags_map = {} + local delimiter = string.char(9) + for _, lang in ipairs(langs) do + for _, file in ipairs(tag_files[lang] or {}) do + local lines = vim.split(utils.read_file(file), "\n") + for _, line in ipairs(lines) do + -- TODO: also ignore tagComment starting with ';' + if not line:match "^!_TAG_" then + local fields = vim.split(line, delimiter) + if #fields == 3 and not tags_map[fields[1]] then + add_tag({ + tag = fields[1], + filename = fields[2], + filepath = help_files[fields[2]], + cmd = fields[3], + lang = lang, + }, cb, co) + tags_map[fields[1]] = true + -- pause here until we call coroutine.resume() + coroutine.yield() + end end end end end - end - cb(nil) - end)() -end - + cb(nil) + end)() + end -M.helptags = function(opts) - opts = config.normalize_opts(opts, "helptags") - if not opts then return end - core.fzf_exec(fzf_fn, opts) + core.fzf_exec(contents, opts) end return M diff --git a/lua/fzf-lua/win.lua b/lua/fzf-lua/win.lua index 2842ca7d..0a20fb0e 100644 --- a/lua/fzf-lua/win.lua +++ b/lua/fzf-lua/win.lua @@ -51,6 +51,7 @@ function TSInjector.clear_cache(buf, noassert) -- If called from fzf-tmux buf will be `nil` (#1556) if not buf then return end TSInjector.cache[buf] = nil + -- If called from `FzfWin.hide` cache will not be empty assert(noassert or utils.tbl_isempty(TSInjector.cache)) end @@ -121,20 +122,26 @@ local _preview_keymaps = { function FzfWin:setup_keybinds() if not self:validate() then return end - if not self.keymap or not self.keymap.builtin then return end - -- find the toggle_preview - if self.keymap.fzf then + self.keymap = type(self.keymap) == "table" and self.keymap or {} + self.keymap.fzf = type(self.keymap.fzf) == "table" and self.keymap.fzf or {} + self.keymap.builtin = type(self.keymap.builtin) == "table" and self.keymap.builtin or {} + local keymap_tbl = { + ["hide"] = { module = "win", fnc = "hide()" }, + ["toggle-help"] = { module = "win", fnc = "toggle_help()" }, + ["toggle-fullscreen"] = { module = "win", fnc = "toggle_fullscreen()" }, + } + -- find the toggle_preview keybind, to be sent when using a split for the native + -- pseudo fzf preview window or when using native and treesitter is enabled + if self.winopts.split or not self.previewer_is_builtin and self.winopts.treesitter then for k, v in pairs(self.keymap.fzf) do if v == "toggle-preview" then self._fzf_toggle_prev_bind = utils.fzf_bind_to_neovim(k) + keymap_tbl = vim.tbl_deep_extend("keep", keymap_tbl, { + ["toggle-preview"] = { module = "win", fnc = "toggle_preview()" }, + }) end end end - local keymap_tbl = { - ["hide"] = { module = "win", fnc = "hide()" }, - ["toggle-help"] = { module = "win", fnc = "toggle_help()" }, - ["toggle-fullscreen"] = { module = "win", fnc = "toggle_fullscreen()" }, - } if self.previewer_is_builtin then -- These maps are only valid for the builtin previewer keymap_tbl = vim.tbl_deep_extend("keep", keymap_tbl, _preview_keymaps) @@ -497,6 +504,8 @@ function FzfWin:new(o) if _self and not _self:hidden() then -- utils.warn("Please close fzf-lua before starting a new instance") _self._reuse = true + -- refersh treesitter settings as new picker might have it disabled + _self._o.winopts.treesitter = o.winopts.treesitter return _self elseif _self and _self:hidden() then -- Clear the hidden buffers @@ -821,27 +830,72 @@ function FzfWin:set_winleave_autocmd() self:_nvim_create_autocmd("WinLeave", self.win_leave, [[require('fzf-lua.win').win_leave()]]) end +function FzfWin:treesitter_detach(buf, noassert) + TSInjector.clear_cache(buf, noassert) + TSInjector.deregister() +end + function FzfWin:treesitter_attach() if not utils.__HAS_NVIM_09 then return end if not self._o.winopts.treesitter then return end local function trim(s) return (string.gsub(s, "^%s*(.-)%s*$", "%1")) end + local _format = type(self._o._treesitter) == "string" and self._o._treesitter or nil vim.api.nvim_buf_attach(self.fzf_bufnr, false, { - on_lines = function(_, bufnr, _, first_changed, last_changed, last_updated, bc) + -- on_lines = function(_, bufnr, _, first_changed, last_changed, last_updated, bc) + on_lines = function(_, bufnr) local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false) local regions = {} local empty_regions = {} + -- Adjust treesitter region based on the available main window width + -- otherwise the highlights may interfere with the fzf scrollbar or + -- the native fzf preview window + -- "builtin" previewer or "vertical" style layouts (up|down) uses max line width + -- "native previewers with "horizontal" (left|right) need are adjusted accordingly + local min_col, max_col = (function() + local win_width = vim.api.nvim_win_get_width(self.fzf_winid) + local min, max = 0, win_width + -- TODO: use `is_hidden` to determine if the native fzf previewer is visible + local is_hidden = self.preview_hidden + local layout = self:fzf_preview_layout_str() + local percent = layout:match("(%d+)%%") or 50 + local is_right, is_left = layout:match("right"), layout:match("left") + if not is_hidden and + (not self.previewer_is_builtin or self.winopts.split) + then + local prev_width = math.floor(win_width * percent / 100) + if is_right then + max = win_width - prev_width + elseif is_left then + min, max = prev_width, win_width + 4 + end + end + return min, max + end)() for i, line in ipairs(lines) do (function() -- Lines with code can be of the following formats: -- file:line:col:text (grep_xxx) -- file:line:text (grep_project or missing "--column" flag) -- line:col:text (grep_curbuf) - -- line:text (blines) - local filepath, _lnum, text = line:match("(.-):?(%d+):(.+)$") + -- linetext (lines|blines) + local filepath, _lnum, text = line:sub(min_col):match(_format or "(.-):?(%d+)[: ](.+)$") if not text or text == 0 then return end - filepath = trim(filepath) - local ft = #filepath == 0 and vim.bo[utils.CTX().bufnr].ft + text = text:gsub("^%d+:", "") -- remove col nr if exists + filepath = trim(filepath) -- trim spaces + + local ft_bufnr = (function() + -- blines|lines: U+00A0 (decimal: 160) follows the lnum + -- grep_curbuf: formats as line:col:text` thus `#filepath == 0` + if #filepath == 0 or string.byte(text, 1) == 160 then + if string.byte(text, 1) == 160 then text = text:sub(2) end -- remove A0+SPACE + if string.byte(text, 1) == 32 then text = text:sub(2) end -- remove leading SPACE + local b = filepath:match("^%d+") or utils.CTX().bufnr + return vim.api.nvim_buf_is_valid(tonumber(b)) and b or nil + end + end)() + + local ft = ft_bufnr and vim.bo[tonumber(ft_bufnr)].ft or vim.filetype.match({ filename = path.tail(filepath) }) if not ft then return end @@ -849,14 +903,15 @@ function FzfWin:treesitter_attach() local loaded = lang and utils.has_ts_parser(lang) if not loaded then return end - -- With the above line match text can start with "%d+:", remove it - text = text:gsub("^%d+:", "") - - local line_idx, text_pos = i - 1, #line - #text + local line_idx = i - 1 + local line_len = #line + local start_col = math.max(min_col, line_len - #text) + local end_col = math.min(max_col, line_len) regions[lang] = regions[lang] or {} empty_regions[lang] = empty_regions[lang] or {} - table.insert(regions[lang], { { line_idx, text_pos, line_idx, line:len() } }) - -- print(lang, string.format("[%d]%d:%s", line_idx, _lnum, line:sub(text_pos + 1))) + table.insert(regions[lang], { { line_idx, start_col, line_idx, end_col } }) + -- print(lang, string.format("%d:%d [%d] %d:%s", + -- start_col, end_col, line_idx, _lnum, line:sub(start_col + 1, end_col))) end)() end TSInjector.attach(bufnr, empty_regions) @@ -924,6 +979,12 @@ function FzfWin:create() -- create a new tmp buffer for the fzf win self:set_tmp_buffer() self:setup_keybinds() + -- attach/detach treesitter (e.g. `grep_lgrep`) + if self._o.winopts.treesitter then + self:treesitter_attach() + else + self:treesitter_detach(self.fzf_bufnr) + end -- also recall the user's 'on_create' (#394) if self.winopts.on_create and type(self.winopts.on_create) == "function" then @@ -1051,8 +1112,7 @@ function FzfWin:close(fzf_bufnr) vim.api.nvim_buf_delete(self.fzf_bufnr, { force = true }) end -- Clear treesitter buffer cache and deregister decoration callbacks - TSInjector.clear_cache(self.fzf_bufnr, self._hidden_fzf_bufnr) - TSInjector.deregister() + self:treesitter_detach(self.fzf_bufnr, self._hidden_fzf_bufnr) -- when using `split = "belowright new"` closing the fzf -- window may not always return to the correct source win -- depending on the user's split configuration (#397) @@ -1375,9 +1435,14 @@ function FzfWin.toggle_preview() if not _self then return end local self = _self self.preview_hidden = not self.preview_hidden - if self.winopts.split and self._fzf_toggle_prev_bind then + if self._fzf_toggle_prev_bind then -- Toggle the empty preview window (under the neovim preview buffer) utils.feed_keys_termcodes(self._fzf_toggle_prev_bind) + -- This is just a proxy to toggle the native fzf preview when treesitter + -- is enabled, no need to redraw, stop here + if not self.previewer_is_builtin then + return + end end if self.preview_hidden and self:validate_preview() then self:close_preview(true)