diff --git a/.github/workflows/stylua.yaml b/.github/workflows/stylua.yaml new file mode 100644 index 000000000..38adc3b9a --- /dev/null +++ b/.github/workflows/stylua.yaml @@ -0,0 +1,20 @@ +name: Format with stylua + +on: + push: + branches: [main] + pull_request: + branches: "*" + +jobs: + stylua: + name: stylua + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: JohnnyMorganz/stylua-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --check lua/ + version: latest + diff --git a/lua/fzf-lua/_health.lua b/lua/fzf-lua/_health.lua index 870675baf..5ee88da0f 100644 --- a/lua/fzf-lua/_health.lua +++ b/lua/fzf-lua/_health.lua @@ -56,8 +56,8 @@ function M.check() if not uv.fs_access(run, "rwx") then error( "Your 'run' directory is invalid `" - .. run - .. "`.\nPlease make sure `XDG_RUNTIME_DIR` is set correctly." + .. run + .. "`.\nPlease make sure `XDG_RUNTIME_DIR` is set correctly." ) end @@ -65,11 +65,13 @@ function M.check() if srv_ok then vim.fn.delete(srv_pipe) else - error(string.format( - "`vim.fn.serverstart()` failed with '%s'\n%s", - srv_ok, - "Please make sure `XDG_RUNTIME_DIR` is writeable." - )) + error( + string.format( + "`vim.fn.serverstart()` failed with '%s'\n%s", + srv_ok, + "Please make sure `XDG_RUNTIME_DIR` is writeable." + ) + ) end if vim.fn.executable("fzf") == 1 then diff --git a/lua/fzf-lua/actions.lua b/lua/fzf-lua/actions.lua index 15bed8a63..c8cd973a1 100644 --- a/lua/fzf-lua/actions.lua +++ b/lua/fzf-lua/actions.lua @@ -1,7 +1,7 @@ local uv = vim.uv or vim.loop -local utils = require "fzf-lua.utils" -local path = require "fzf-lua.path" -local libuv = require "fzf-lua.libuv" +local utils = require("fzf-lua.utils") +local path = require("fzf-lua.path") +local libuv = require("fzf-lua.libuv") local M = {} @@ -9,7 +9,9 @@ local M = {} -- on fzf >= 0.53 add the `prefix` key to the bind flags -- https://github.com/junegunn/fzf/issues/3829#issuecomment-2143235993 M.expect = function(actions, opts) - if not actions then return nil end + if not actions then + return nil + end local expect = {} local binds = {} for k, v in pairs(actions) do @@ -20,19 +22,25 @@ M.expect = function(actions, opts) (function() -- Lua 5.1 goto compatiblity hack (function wrap) -- Ignore `false` actions and execute-silent/reload actions - if not v or type(v) == "table" and v._ignore or k:match("^_") then return end + if not v or type(v) == "table" and v._ignore or k:match("^_") then + return + end k = k == "default" and "enter" or k v = type(v) == "table" and v or { fn = v } if utils.has(opts, "fzf", { 0, 53 }) then -- `print(...)` action was only added with fzf 0.53 -- NOTE: we can no longer combine `--expect` and `--bind` as this will -- print an extra empty line regardless of the pressaed keybind (#1241) - table.insert(binds, string.format("%s:print(%s)%s%s+accept", - k, - k, - v.prefix and "+" or "", - v.prefix and v.prefix:gsub("accept$", ""):gsub("%+$", "") or "" - )) + table.insert( + binds, + string.format( + "%s:print(%s)%s%s+accept", + k, + k, + v.prefix and "+" or "", + v.prefix and v.prefix:gsub("accept$", ""):gsub("%+$", "") or "" + ) + ) elseif utils.has(opts, "sk", { 0, 14 }) then -- sk 0.14 deprecated `--expect`, instead `accept()` should be used -- skim does not yet support case sensitive alt-shift binds, they are ignored @@ -57,10 +65,14 @@ M.normalize_selected = function(selected, opts) -- The below separates the keybind from the item(s) -- and makes sure 'selected' contains only item(s) or {} -- so it can always be enumerated safely - if not selected then return end + if not selected then + return + end local actions = opts.actions -- Backward compat, "default" action trumps "enter" - if actions.default then actions.enter = actions.default end + if actions.default then + actions.enter = actions.default + end if utils.has(opts, "fzf", { 0, 53 }) or utils.has(opts, "sk", { 0, 14 }) then -- Using the new `print` action keybind is expected at `selected[1]` -- NOTE: if `--select-1|-q` was used we'll be missing the keybind @@ -86,7 +98,9 @@ M.normalize_selected = function(selected, opts) -- when `--expect` is present, default (enter) keybind prints an empty string local entries = vim.deepcopy(selected) local keybind = table.remove(entries, 1) - if #keybind == 0 then keybind = "enter" end + if #keybind == 0 then + keybind = "enter" + end return keybind, entries else -- Only default (enter) action exists, no `--expect` was specified @@ -97,11 +111,15 @@ M.normalize_selected = function(selected, opts) end M.act = function(selected, opts) - if not selected then return end + if not selected then + return + end local actions = opts.actions local keybind, entries = M.normalize_selected(selected, opts) -- fzf >= 0.53 and `--exit-0` - if not keybind then return end + if not keybind then + return + end local action = actions[keybind] -- Backward compat, was action defined as "default" if not action and keybind == "enter" then @@ -131,7 +149,7 @@ end M.dummy_abort = function(_, o) -- try to resume mode if `complete` is set if o.complete and o.__CTX.mode == "i" then - vim.cmd [[noautocmd lua vim.api.nvim_feedkeys('i', 'n', true)]] + vim.cmd([[noautocmd lua vim.api.nvim_feedkeys('i', 'n', true)]]) end end @@ -149,10 +167,14 @@ M.vimcmd_entry = function(_vimcmd, selected, opts, pcall_vimcmd) local lnum = opts.line_query and tonumber(opts.last_query:match(":(%d+)$")) entry.line = lnum or entry.line -- "" could be set by `autocmds` - if entry.path == "" then return end + if entry.path == "" then + return + end local fullpath = entry.bufname or entry.uri and entry.uri:match("^%a+://(.*)") or entry.path -- Something is not right, goto next entry - if not fullpath then return end + if not fullpath then + return + end if not path.is_absolute(fullpath) then -- cwd priority is first user supplied, then original call cwd -- technically we should never get to the `uv.cwd()` fallback @@ -162,10 +184,11 @@ M.vimcmd_entry = function(_vimcmd, selected, opts, pcall_vimcmd) local relpath = path.relative_to(fullpath, uv.cwd()) -- opts.__CTX isn't guaranteed by API users (#1414) local CTX = opts.__CTX or utils.CTX() - local target_equals_current = - (entry.bufnr and entry.bufnr == CTX.bufnr or path.equals(fullpath, CTX.bname)) - -- we open a new buffer on tabs so target is always different (#1785) - and not _vimcmd:match("^tabnew") + local target_equals_current = ( + entry.bufnr and entry.bufnr == CTX.bufnr or path.equals(fullpath, CTX.bname) + ) + -- we open a new buffer on tabs so target is always different (#1785) + and not _vimcmd:match("^tabnew") local vimcmd = (function() -- Do not execute "edit" commands if we already have the same buffer/file open -- or if we are dealing with a URI as it's open with `vim.lsp.util.show_document` @@ -183,10 +206,12 @@ M.vimcmd_entry = function(_vimcmd, selected, opts, pcall_vimcmd) end)() -- ":b" and ":e" commands replace the current buffer local will_replace_curbuf = vimcmd == "e" or vimcmd == "b" - if will_replace_curbuf - and not vim.o.hidden - and not vim.o.autowriteall - and utils.buffer_is_dirty(nil, false, true) then + if + will_replace_curbuf + and not vim.o.hidden + and not vim.o.autowriteall + and utils.buffer_is_dirty(nil, false, true) + then -- when `:set nohidden`, confirm with the user when trying to switch -- from a dirty buffer, abort if declined, save buffer if requested if utils.save_dialog(nil) then @@ -195,10 +220,7 @@ M.vimcmd_entry = function(_vimcmd, selected, opts, pcall_vimcmd) return end end - if will_replace_curbuf - and vim.fn.exists("&winfixbuf") == 1 - and vim.wo.winfixbuf - then + if will_replace_curbuf and vim.fn.exists("&winfixbuf") == 1 and vim.wo.winfixbuf then utils.warn("'winfixbuf' is set for current window, will open in a split.") vimcmd = "split | " .. vimcmd end @@ -216,20 +238,32 @@ M.vimcmd_entry = function(_vimcmd, selected, opts, pcall_vimcmd) -- URI entries only execute new buffers (new|vnew|tabnew) if not entry.uri and not target_equals_current then -- Force full paths when `autochdir=true` (#882) - vimcmd = string.format("%s %s", vimcmd, (function() - -- `:argdel|:argadd` uses only paths - -- argdel only accepts relative path (#1949) - if vimcmd:match("^arg") then return path.relative_to(entry.path, uv.cwd()) end - if entry.bufnr then return tostring(entry.bufnr) end - -- We normalize the path or Windows will fail with directories starting - -- with special characters, for example "C:\app\(web)" will be translated - -- by neovim to "c:\app(web)" (#1082) - return vim.fn.fnameescape(path.normalize(relpath)) - end)()) + vimcmd = string.format( + "%s %s", + vimcmd, + (function() + -- `:argdel|:argadd` uses only paths + -- argdel only accepts relative path (#1949) + if vimcmd:match("^arg") then + return path.relative_to(entry.path, uv.cwd()) + end + if entry.bufnr then + return tostring(entry.bufnr) + end + -- We normalize the path or Windows will fail with directories starting + -- with special characters, for example "C:\app\(web)" will be translated + -- by neovim to "c:\app(web)" (#1082) + return vim.fn.fnameescape(path.normalize(relpath)) + end)() + ) end if pcall_vimcmd ~= false then - local ok, err = pcall(function() vim.cmd(vimcmd) end) - if not ok then utils.warn(string.format("':%s' failed: %s", vimcmd, err)) end + local ok, err = pcall(function() + vim.cmd(vimcmd) + end) + if not ok then + utils.warn(string.format("':%s' failed: %s", vimcmd, err)) + end else vim.cmd(vimcmd) end @@ -254,7 +288,7 @@ M.vimcmd_entry = function(_vimcmd, selected, opts, pcall_vimcmd) -- e.g. qf lists from files (no line/col), dap_breakpoints pcall(vim.api.nvim_win_set_cursor, 0, { math.max(1, entry.line), - math.max(1, entry.col) - 1 + math.max(1, entry.col) - 1, }) end -- Only "zz" after the last entry is loaded into the origin buffer @@ -316,9 +350,11 @@ local sel_to_qf = function(selected, opts, is_loclist) return a.filename < b.filename end end) - local title = string.format("[FzfLua] %s%s", + local title = string.format( + "[FzfLua] %s%s", opts.__INFO and opts.__INFO.cmd .. ": " or "", - utils.resume_get("query", opts) or "") + utils.resume_get("query", opts) or "" + ) if is_loclist then vim.fn.setloclist(0, {}, " ", { nr = "$", @@ -364,7 +400,9 @@ M.file_edit_or_qf = function(selected, opts) end M.file_switch = function(selected, opts) - if not selected[1] then return false end + if not selected[1] then + return false + end -- If called from `:FzfLua tabs` switch to requested tab/win local tabh, winid = selected[1]:match("(%d+):(%d+)%)") if tabh and winid then @@ -390,18 +428,26 @@ M.file_switch = function(selected, opts) end end -- Entry isn't an existing buffer, abort - if not entry.bufnr then return false end - if not utils.is_term_buffer(0) then vim.cmd("normal! m`") end + if not entry.bufnr then + return false + end + if not utils.is_term_buffer(0) then + vim.cmd("normal! m`") + end winid = utils.winid_from_tabh(0, entry.bufnr) - if not winid then return false end + if not winid then + return false + end vim.api.nvim_set_current_win(winid) if entry.line > 0 or entry.col > 0 then pcall(vim.api.nvim_win_set_cursor, 0, { math.max(1, entry.line), - math.max(1, entry.col) - 1 + math.max(1, entry.col) - 1, }) end - if not utils.is_term_buffer(0) and not opts.no_action_zz then vim.cmd("norm! zvzz") end + if not utils.is_term_buffer(0) and not opts.no_action_zz then + vim.cmd("norm! zvzz") + end return true end @@ -425,10 +471,11 @@ M.buf_del = function(selected, opts) for _, sel in ipairs(selected) do local entry = path.entry_to_file(sel, opts) if entry.bufnr then - if not utils.buffer_is_dirty(entry.bufnr, true, false) - or vim.api.nvim_buf_call(entry.bufnr, function() - return utils.save_dialog(entry.bufnr) - end) + if + not utils.buffer_is_dirty(entry.bufnr, true, false) + or vim.api.nvim_buf_call(entry.bufnr, function() + return utils.save_dialog(entry.bufnr) + end) then vim.api.nvim_buf_delete(entry.bufnr, { force = true }) end @@ -451,13 +498,17 @@ M.arg_del = function(selected, opts) end M.colorscheme = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end local dbkey, idx = selected[1]:match("^(.-):(%d+):") if dbkey then opts._apply_awesome_theme(dbkey, idx, opts) else local colorscheme = selected[1]:match("^[^:]+") - pcall(function() vim.cmd("colorscheme " .. colorscheme) end) + pcall(function() + vim.cmd("colorscheme " .. colorscheme) + end) end end @@ -472,7 +523,9 @@ M.cs_update = function(selected, opts) local dedup = {} for _, s in ipairs(selected) do local dbkey = s:match("^(.-):%d+:") - if dbkey then dedup[dbkey] = true end + if dbkey then + dedup[dbkey] = true + end end for k, _ in pairs(dedup) do opts._adm:update(k) @@ -486,19 +539,25 @@ M.toggle_bg = function(_, _) end M.hi = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end vim.cmd("hi " .. selected[1]) vim.cmd("echo") end M.run_builtin = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end local method = selected[1] pcall(loadstring(string.format("require'fzf-lua'.%s()", method))) end M.ex_run = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end local cmd = selected[1] vim.cmd("stopinsert") vim.fn.feedkeys(string.format(":%s", cmd), "nt") @@ -506,25 +565,29 @@ M.ex_run = function(selected) end M.ex_run_cr = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end local cmd = selected[1] vim.cmd(cmd) vim.fn.histadd("cmd", cmd) end M.exec_menu = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end local cmd = selected[1] vim.cmd("emenu " .. cmd) end - M.search = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end local query = selected[1] vim.cmd("stopinsert") - vim.fn.feedkeys( - string.format("%s%s", opts.reverse_search and "?" or "/", query), "n") + vim.fn.feedkeys(string.format("%s%s", opts.reverse_search and "?" or "/", query), "n") return query end @@ -534,7 +597,9 @@ M.search_cr = function(selected, opts) end M.goto_mark = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end local mark = selected[1] mark = mark:match("[^ ]+") vim.cmd("stopinsert") @@ -547,16 +612,20 @@ M.mark_del = function(selected) local buf = utils.CTX().bufnr vim.api.nvim_win_call(win, function() vim.tbl_map(function(s) - local mark = s:match "[^ ]+" + local mark = s:match("[^ ]+") local ok, res = pcall(vim.api.nvim_buf_del_mark, buf, mark) - if ok and res then return end + if ok and res then + return + end return vim.cmd.delm(mark) end, selected) end) end M.goto_jump = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end if opts.jump_using_norm then local jump, _, _, _ = selected[1]:match("(%d+)%s+(%d+)%s+(%d+)%s+(.*)") if tonumber(jump) then @@ -581,7 +650,9 @@ M.goto_jump = function(selected, opts) end M.keymap_apply = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end -- extract lhs in the keymap. The lhs can't contain a whitespace. local key = selected[1]:match("[│]%s+([^%s]*)%s+[│]") vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, false, true), "t", true) @@ -616,13 +687,17 @@ local nvim_opt_edit = function(selected, opts, scope) end local ok, err = pcall(vim.api.nvim_set_option_value, opt, val, set_opts) - if not ok and err then utils.warn(err) end + if not ok and err then + utils.warn(err) + end end local show_option_value_input = function(option, old, info) - local updated = utils.input( - (scope == "local" and ":setlocal " or ":set ") .. option .. "=", old) - if not updated or updated == old then return end + local updated = + utils.input((scope == "local" and ":setlocal " or ":set ") .. option .. "=", old) + if not updated or updated == old then + return + end if info.type == "number" then updated = tonumber(updated) @@ -656,16 +731,20 @@ M.nvim_opt_edit_global = function(selected, opts) end M.spell_apply = function(selected, opts) - if not selected[1] then return false end + if not selected[1] then + return false + end local word = selected[1] - vim.cmd("normal! \"_ciw" .. word) + vim.cmd('normal! "_ciw' .. word) if opts.__CTX.mode == "i" then vim.api.nvim_feedkeys("a", "n", true) end end M.spell_suggest = function(selected, opts) - if not selected[1] then return false end + if not selected[1] then + return false + end M.file_edit(selected, opts) FzfLua.spell_suggest({ no_resume = true }) end @@ -696,17 +775,23 @@ local function helptags(s, opts) end M.help = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end vim.cmd("help " .. helptags(selected, opts)[1]) end M.help_vert = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end vim.cmd("vert help " .. helptags(selected, opts)[1]) end M.help_tab = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end -- vim.cmd("tab help " .. helptags(selected, opts)[1]) utils.with({ go = { splitkeep = "cursor" } }, function() vim.cmd("tabnew | setlocal bufhidden=wipe | help " .. helptags(selected, opts)[1] .. " | only") @@ -718,24 +803,32 @@ local function mantags(s) end M.man = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end vim.cmd("Man " .. mantags(selected)[1]) end M.man_vert = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end vim.cmd("vert Man " .. mantags(selected)[1]) end M.man_tab = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end utils.with({ go = { splitkeep = "cursor" } }, function() vim.cmd("tabnew | setlocal bufhidden=wipe | Man " .. mantags(selected)[1] .. " | only") end) end M.git_switch = function(selected, opts) - if not selected[1] then return end + if not selected[1] then + return + end local cmd = path.git_cwd({ "git", "checkout" }, opts) local git_ver = utils.git_version() -- git switch was added with git version 2.23 @@ -745,7 +838,9 @@ M.git_switch = function(selected, opts) -- remove anything past space local branch = selected[1]:match("[^ ]+") -- do nothing for active branch - if branch:find("%*") ~= nil then return end + if branch:find("%*") ~= nil then + return + end if branch:find("^remotes/") then if opts.remotes == "detach" then table.insert(cmd, "--detach") @@ -784,7 +879,9 @@ M.git_branch_add = function(selected, opts) end M.git_branch_del = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end local cmd_del_branch = path.git_cwd(opts.cmd_del, opts) local cmd_cur_branch = path.git_cwd({ "git", "rev-parse", "--abbrev-ref", "HEAD" }, opts) local branch = selected[1]:match("[^%s%*]+") @@ -813,26 +910,37 @@ local match_commit_hash = function(line, opts) end M.git_yank_commit = function(selected, opts) - if not selected[1] then return end + if not selected[1] then + return + end local commit_hash = match_commit_hash(selected[1], opts) local regs, cb = {}, vim.o.clipboard - if cb:match("unnamed") then regs[#regs + 1] = [[*]] end - if cb:match("unnamedplus") then regs[#regs + 1] = [[+]] end - if #regs == 0 then regs[#regs + 1] = [["]] end + if cb:match("unnamed") then + regs[#regs + 1] = [[*]] + end + if cb:match("unnamedplus") then + regs[#regs + 1] = [[+]] + end + if #regs == 0 then + regs[#regs + 1] = [["]] + end -- copy to the yank register regardless for _, reg in ipairs(regs) do vim.fn.setreg(reg, commit_hash) end vim.fn.setreg([[0]], commit_hash) - utils.info(string.format("commit hash %s copied to register %s, use 'p' to paste.", - commit_hash, regs[1])) + utils.info( + string.format("commit hash %s copied to register %s, use 'p' to paste.", commit_hash, regs[1]) + ) end M.git_checkout = function(selected, opts) local cmd_cur_commit = path.git_cwd({ "git", "rev-parse", "--short", "HEAD" }, opts) local commit_hash = match_commit_hash(selected[1], opts) local current_commit = utils.io_systemlist(cmd_cur_commit)[1] - if commit_hash == current_commit then return end + if commit_hash == current_commit then + return + end if vim.fn.confirm("Checkout commit " .. commit_hash .. "?", "&Yes\n&No") == 1 then local cmd_checkout = path.git_cwd({ "git", "checkout" }, opts) table.insert(cmd_checkout, commit_hash) @@ -895,9 +1003,8 @@ M.git_reset = function(selected, opts) for _, s in ipairs(selected) do s = utils.strip_ansi_coloring(s) local is_untracked = s:sub(5, 5) == "?" - local cmd = is_untracked - and path.git_cwd({ "git", "clean", "-f" }, opts) - or path.git_cwd({ "git", "checkout", "HEAD", "--" }, opts) + local cmd = is_untracked and path.git_cwd({ "git", "clean", "-f" }, opts) + or path.git_cwd({ "git", "checkout", "HEAD", "--" }, opts) git_exec({ s }, opts, cmd) -- trigger autoread or warn the users buffer(s) was changed vim.cmd("checktime") @@ -931,7 +1038,9 @@ M.git_stash_apply = function(selected, opts) end M.git_buf_edit = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end local cmd = path.git_cwd({ "git", "show" }, opts) local git_root = path.git_root(opts, true) local win = vim.api.nvim_get_current_win() @@ -967,7 +1076,9 @@ M.git_buf_vsplit = function(selected, opts) end M.git_goto_line = function(selected, _) - if #selected == 0 then return end + if #selected == 0 then + return + end local line = selected[1] and selected[1]:match("^.-(%d+)%)") if tonumber(line) then vim.api.nvim_win_set_cursor(0, { tonumber(line), 0 }) @@ -999,7 +1110,7 @@ M.toggle_flag = function(_, opts) -- grep|live_grep sets `opts._cmd` to the original -- command without the search argument cmd = utils.toggle_cmd_flag(opts._cmd or opts.cmd, opts.toggle_flag), - resume = true + resume = true, }, opts.__call_opts) opts.__call_fn(o) end @@ -1024,15 +1135,16 @@ M.toggle_follow = function(_, opts) end M.tmux_buf_set_reg = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end local buf = selected[1]:match("^%[(.-)%]") local data, rc = utils.io_system({ "tmux", "show-buffer", "-b", buf }) if rc == 0 and data and #data > 0 then opts.register = opts.register or [["]] local ok, err = pcall(vim.fn.setreg, opts.register, data) if ok then - utils.info(string.format("%d characters copied into register %s", - #data, opts.register)) + utils.info(string.format("%d characters copied into register %s", #data, opts.register)) else utils.err(string.format("setreg(%s) failed: %s", opts.register, err)) end @@ -1040,7 +1152,9 @@ M.tmux_buf_set_reg = function(selected, opts) end M.paste_register = function(selected) - if #selected == 0 then return end + if #selected == 0 then + return + end local reg = selected[1]:match("%[(.-)%]") local ok, data = pcall(vim.fn.getreg, reg) if ok and #data > 0 then @@ -1049,17 +1163,20 @@ M.paste_register = function(selected) end M.set_qflist = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end local nr = selected[1]:match("[(%d+)]") - vim.cmd(string.format("%d%s", tonumber(nr), - opts._is_loclist and "lhistory" or "chistory")) + vim.cmd(string.format("%d%s", tonumber(nr), opts._is_loclist and "lhistory" or "chistory")) vim.cmd(opts._is_loclist and "lopen" or "copen") end ---@param selected string[] ---@param opts table M.apply_profile = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end local entry = path.entry_to_file(selected[1]) local fname = entry.path local profile = entry.stripped:sub(#fname + 2):match("[^%s]+") @@ -1072,7 +1189,7 @@ end M.complete = function(selected, opts) if #selected == 0 then if opts.__CTX.mode == "i" then - vim.cmd [[noautocmd lua vim.api.nvim_feedkeys('i', 'n', true)]] + vim.cmd([[noautocmd lua vim.api.nvim_feedkeys('i', 'n', true)]]) end return end @@ -1090,7 +1207,7 @@ M.complete = function(selected, opts) vim.api.nvim_set_current_line(newline or opts.__CTX.line) vim.api.nvim_win_set_cursor(0, { opts.__CTX.cursor[1], newcol or col }) if opts.__CTX.mode == "i" then - vim.cmd [[noautocmd lua vim.api.nvim_feedkeys('a', 'n', true)]] + vim.cmd([[noautocmd lua vim.api.nvim_feedkeys('a', 'n', true)]]) end end @@ -1119,7 +1236,9 @@ M.dap_bp_del = function(selected, opts) end M.cd = function(selected, opts) - if #selected == 0 then return end + if #selected == 0 then + return + end local cwd = selected[1]:match("[^\t]+$") or selected[1] if opts.cwd then cwd = path.join({ opts.cwd, cwd }) diff --git a/lua/fzf-lua/class.lua b/lua/fzf-lua/class.lua index 81b12c3fe..1ac948973 100644 --- a/lua/fzf-lua/class.lua +++ b/lua/fzf-lua/class.lua @@ -12,10 +12,8 @@ local Object = {} Object.__index = Object - ---@diagnostic disable-next-line: unused-vararg -function Object:new(...) -end +function Object:new(...) end function Object:extend() local cls = {} diff --git a/lua/fzf-lua/cmd.lua b/lua/fzf-lua/cmd.lua index 5ccba3580..2f9349219 100644 --- a/lua/fzf-lua/cmd.lua +++ b/lua/fzf-lua/cmd.lua @@ -1,8 +1,8 @@ -local builtin = require "fzf-lua" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local defaults = require "fzf-lua.defaults".defaults -local serpent = require "fzf-lua.lib.serpent" +local builtin = require("fzf-lua") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local defaults = require("fzf-lua.defaults").defaults +local serpent = require("fzf-lua.lib.serpent") local M = {} @@ -23,7 +23,9 @@ function M.run_command(cmd, ...) if val and #val > 0 then local ok, loaded = serpent.load(val) -- Parsed string wasn't "nil" but loaded as `nil`, use as is - if val ~= "nil" and loaded == nil then ok = false end + if val ~= "nil" and loaded == nil then + ok = false + end if ok and (type(loaded) ~= "table" or not utils.tbl_isempty(loaded)) then opts[key] = loaded else @@ -38,7 +40,9 @@ end ---@return table function M.options_md() -- Only attempt to load from file once, if failed we ditch the docs - if M._options_md ~= nil then return M._options_md end + if M._options_md ~= nil then + return M._options_md + end M._options_md = {} local filepath = path.join({ vim.g.fzf_lua_root, "OPTIONS.md" }) local lines = vim.split(utils.read_file(filepath), "\n") @@ -96,7 +100,9 @@ function M._candidates(line, cmp_items) local n = #l - 2 -- We can reach here after on :FzfLua+<+Space>+ - if n < 0 then return end + if n < 0 then + return + end if n == 0 then local commands = utils.tbl_flatten({ builtin_list }) @@ -111,26 +117,64 @@ function M._candidates(line, cmp_items) -- Not all commands have their opts under the same key local function cmd2key(cmd) - if not cmd then return end + if not cmd then + return + end local cmd2cfg = { { patterns = { "^git_", "^dap", "^tmux_" }, - transform = function(c) return c:gsub("_", ".") end + transform = function(c) + return c:gsub("_", ".") + end, }, { patterns = { "^lsp_code_actions$" }, - transform = function(_) return "lsp.code_actions" end + transform = function(_) + return "lsp.code_actions" + end, + }, + { + patterns = { "^lsp_.*_symbols$" }, + transform = function(_) + return "lsp.symbols" + end, + }, + { + patterns = { "^lsp_" }, + transform = function(_) + return "lsp" + end, + }, + { + patterns = { "^diagnostics_" }, + transform = function(_) + return "diagnostics" + end, + }, + { + patterns = { "^tags" }, + transform = function(_) + return "tags" + end, + }, + { + patterns = { "grep" }, + transform = function(_) + return "grep" + end, + }, + { + patterns = { "^complete_bline$" }, + transform = function(_) + return "complete_line" + end, }, - { patterns = { "^lsp_.*_symbols$" }, transform = function(_) return "lsp.symbols" end }, - { patterns = { "^lsp_" }, transform = function(_) return "lsp" end }, - { patterns = { "^diagnostics_" }, transform = function(_) return "diagnostics" end }, - { patterns = { "^tags" }, transform = function(_) return "tags" end }, - { patterns = { "grep" }, transform = function(_) return "grep" end }, - { patterns = { "^complete_bline$" }, transform = function(_) return "complete_line" end }, } for _, v in pairs(cmd2cfg) do for _, p in ipairs(v.patterns) do - if cmd:match(p) then return v.transform(cmd) end + if cmd:match(p) then + return v.transform(cmd) + end end end return cmd @@ -146,17 +190,19 @@ function M._candidates(line, cmp_items) -- Add globals recursively, e.g. `winopts.fullscreen` -- will be later retrieved using `utils.map_get(...)` for k, v in pairs({ - winopts = false, - keymap = false, + winopts = false, + keymap = false, fzf_opts = false, - __HLS = "hls", -- rename prefix + __HLS = "hls", -- rename prefix }) do - opts = utils.tbl_flatten({ opts, vim.tbl_filter(function(x) + opts = utils.tbl_flatten({ + opts, + vim.tbl_filter(function(x) -- Exclude global options that can be specified only during `setup`, -- e.g.'`winopts.preview.default` as this might confuse the user return not M.options_md()["setup." .. x] - end, - vim.tbl_keys(utils.map_flatten(defaults[k] or {}, v or k))) }) + end, vim.tbl_keys(utils.map_flatten(defaults[k] or {}, v or k))), + }) end -- Add options from docs, so we also have options defaulting to `nil` diff --git a/lua/fzf-lua/cmp_src.lua b/lua/fzf-lua/cmp_src.lua index 5ab4bc045..4f81b7e7d 100644 --- a/lua/fzf-lua/cmp_src.lua +++ b/lua/fzf-lua/cmp_src.lua @@ -34,7 +34,9 @@ end ---@return lsp.MarkupContent? function Src:_get_documentation(completion_item) local options_md = require("fzf-lua.cmd").options_md() - if not options_md or not next(options_md) then return end + if not options_md or not next(options_md) then + return + end -- Test for `label:lower()` to match both `grep_c{word|WORD}` local markdown = options_md[completion_item.label] or options_md[completion_item.label:lower()] if not markdown and completion_item.data then @@ -63,14 +65,20 @@ end function Src._register_cmdline() local ok, cmp, config ok, cmp = pcall(require, "cmp") - if not ok then return end + if not ok then + return + end -- Using blink.cmp in nvim-cmp compat mode doesn't have config (#1522) ok, config = pcall(require, "cmp.config") - if not ok then return end + if not ok then + return + end cmp.register_source("FzfLua", Src) Src._registered = true local cmdline_cfg = config.cmdline - if not cmdline_cfg or not cmdline_cfg[":"] then return end + if not cmdline_cfg or not cmdline_cfg[":"] then + return + end local has_fzf_lua = false for _, s in ipairs(cmdline_cfg[":"].sources or {}) do if s.name == "FzfLua" then @@ -85,7 +93,7 @@ function Src._register_cmdline() keyword_length = 1, group_index = 1, name = "FzfLua", - option = {} + option = {}, }) end end @@ -97,9 +105,9 @@ function Src._complete() require("cmp").complete({ config = { sources = { - { name = "FzfLua" } - } - } + { name = "FzfLua" }, + }, + }, }) end) end diff --git a/lua/fzf-lua/complete.lua b/lua/fzf-lua/complete.lua index 15e302635..279a81efa 100644 --- a/lua/fzf-lua/complete.lua +++ b/lua/fzf-lua/complete.lua @@ -1,9 +1,9 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local libuv = require "fzf-lua.libuv" +local core = require("fzf-lua.core") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local libuv = require("fzf-lua.libuv") local M = {} @@ -65,33 +65,40 @@ local set_cmp_opts_path = function(opts) -- completion function rebuilds the line with the full path opts.complete = function(selected, o, l, _) -- query fuzzy matching is empty - if #selected == 0 then return end + if #selected == 0 then + return + end local replace_at = col - #before local relpath = path.relative_to(path.entry_to_file(selected[1], o).path, opts.cwd) local before_path = replace_at > 1 and l:sub(1, replace_at - 1) or "" local rest_of_line = #l >= (col + #after) and l:sub(col + #after) or "" local resolved_path = opts._cwd and path.join({ opts._cwd, relpath }) or relpath return before_path .. resolved_path .. rest_of_line, - -- this goes to `nvim_win_set_cursor` which is 0-based - replace_at + #resolved_path - 2 + -- this goes to `nvim_win_set_cursor` which is 0-based + replace_at + + #resolved_path + - 2 end return opts end M.path = function(opts) opts = config.normalize_opts(opts, "complete_path") - if not opts then return end - opts.cmd = opts.cmd or (function() - if vim.fn.executable("fdfind") == 1 then - return "fdfind --strip-cwd-prefix" - elseif vim.fn.executable("fd") == 1 then - return "fd --strip-cwd-prefix" - elseif utils.__IS_WINDOWS then - return "dir /s/b" - else - return [[find ! -path '.' ! -path '*/\.git/*' -printf '%P\n']] - end - end)() + if not opts then + return + end + opts.cmd = opts.cmd + or (function() + if vim.fn.executable("fdfind") == 1 then + return "fdfind --strip-cwd-prefix" + elseif vim.fn.executable("fd") == 1 then + return "fd --strip-cwd-prefix" + elseif utils.__IS_WINDOWS then + return "dir /s/b" + else + return [[find ! -path '.' ! -path '*/\.git/*' -printf '%P\n']] + end + end)() opts = set_cmp_opts_path(opts) local contents = core.mt_cmd_wrapper(opts) return core.fzf_exec(contents, opts) @@ -99,21 +106,24 @@ end M.file = function(opts) opts = config.normalize_opts(opts, "complete_file") - if not opts then return end + if not opts then + return + end opts.cmp_is_file = true - opts.cmd = opts.cmd or (function() - if vim.fn.executable("fdfind") == 1 then - return "fdfind --strip-cwd-prefix --type f --exclude .git" - elseif vim.fn.executable("fd") == 1 then - return "fd --strip-cwd-prefix --type f --exclude .git" - elseif vim.fn.executable("rg") == 1 then - return "rg --files" - elseif utils.__IS_WINDOWS then - return "dir /s/b" - else - return [[find -type f ! -path '*/\.git/*' -printf '%P\n']] - end - end)() + opts.cmd = opts.cmd + or (function() + if vim.fn.executable("fdfind") == 1 then + return "fdfind --strip-cwd-prefix --type f --exclude .git" + elseif vim.fn.executable("fd") == 1 then + return "fd --strip-cwd-prefix --type f --exclude .git" + elseif vim.fn.executable("rg") == 1 then + return "rg --files" + elseif utils.__IS_WINDOWS then + return "dir /s/b" + else + return [[find -type f ! -path '*/\.git/*' -printf '%P\n']] + end + end)() opts = set_cmp_opts_path(opts) local contents = core.mt_cmd_wrapper(opts) return core.fzf_exec(contents, opts) @@ -130,7 +140,7 @@ M.line = function(opts) local newline = selected[1]:match(" (.-)$") return newline, #newline end - return require "fzf-lua.providers.buffers".lines(opts) + return require("fzf-lua.providers.buffers").lines(opts) end M.bline = function(opts) diff --git a/lua/fzf-lua/config.lua b/lua/fzf-lua/config.lua index cda40390c..228a5b363 100644 --- a/lua/fzf-lua/config.lua +++ b/lua/fzf-lua/config.lua @@ -1,9 +1,9 @@ local uv = vim.uv or vim.loop -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local libuv = require "fzf-lua.libuv" -local actions = require "fzf-lua.actions" -local devicons = require "fzf-lua.devicons" +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local libuv = require("fzf-lua.libuv") +local actions = require("fzf-lua.actions") +local devicons = require("fzf-lua.devicons") local M = {} @@ -17,8 +17,7 @@ M.resume_get = function(what, opts) return opts.__resume_get(what, opts) end local fn_key = tostring(opts.__resume_key):match("[^%s]+$") - what = string.format("__resume_map.%s%s", fn_key, - type(what) == "string" and ("." .. what) or "") + what = string.format("__resume_map.%s%s", fn_key, type(what) == "string" and ("." .. what) or "") -- _G.dump("resume_get", what, utils.map_get(M, what)) return utils.map_get(M, what) end @@ -31,8 +30,8 @@ M.resume_set = function(what, val, opts) return opts.__resume_set(what, val, opts) end local fn_key = tostring(opts.__resume_key):match("[^%s]+$") - local key1 = string.format("__resume_map.%s%s", fn_key, - type(what) == "string" and ("." .. what) or "") + local key1 = + string.format("__resume_map.%s%s", fn_key, type(what) == "string" and ("." .. what) or "") utils.map_set(M, key1, val) if type(what) == "string" then local key2 = string.format("__resume_data.opts.%s", what) @@ -82,12 +81,16 @@ M.globals = setmetatable({}, { -- exclude case-sensitive alt-binds from being lowercased local exclude_case_sensitive_alt = "^alt%-%a$" for _, k in ipairs(keys) do - ret[k] = setup_value and type(setup_value[k]) == "table" - and vim.tbl_deep_extend("keep", + ret[k] = setup_value + and type(setup_value[k]) == "table" + and vim.tbl_deep_extend( + "keep", utils.map_tolower(utils.tbl_deep_clone(setup_value[k]), exclude_case_sensitive_alt), - setup_value[k][1] == true and - utils.map_tolower(fzflua_default[k], exclude_case_sensitive_alt) or {}) - or utils.map_tolower(utils.tbl_deep_clone(fzflua_default[k]), exclude_case_sensitive_alt) + setup_value[k][1] == true + and utils.map_tolower(fzflua_default[k], exclude_case_sensitive_alt) + or {} + ) + or utils.map_tolower(utils.tbl_deep_clone(fzflua_default[k]), exclude_case_sensitive_alt) if ret[k] and ret[k][1] ~= nil then -- Remove the [1] indicating inheritance from defaults and ret[k][1] = nil @@ -112,8 +115,10 @@ M.globals = setmetatable({}, { end -- (1) use fzf-lua's true defaults (pre-setup) as our options base local ret = utils.tbl_deep_clone(fzflua_default) or {} - if (fzflua_default and (fzflua_default.actions or fzflua_default._actions)) - or (setup_value and (setup_value.actions or setup_value._actions)) then + if + (fzflua_default and (fzflua_default.actions or fzflua_default._actions)) + or (setup_value and (setup_value.actions or setup_value._actions)) + then -- (2) the existence of the `actions` key implies we're dealing with a picker -- override global provider defaults supplied by the user's setup `defaults` table ret = vim.tbl_deep_extend("force", ret, setup_defaults()) @@ -124,7 +129,7 @@ M.globals = setmetatable({}, { end, __newindex = function(_, index, _) assert(false, string.format("modifying globals directly isn't allowed [index: %s]", index)) - end + end, }) do @@ -136,7 +141,9 @@ do end local eval = function(v, ...) - if vim.is_callable(v) then return v(...) end + if vim.is_callable(v) then + return v(...) + end return v end @@ -144,19 +151,22 @@ end ---@param globals string|table? ---@param __resume_key string? function M.normalize_opts(opts, globals, __resume_key) - if not opts then opts = {} end + if not opts then + opts = {} + end -- opts can also be a function that returns an opts table if type(opts) == "function" then opts = opts() end - local profile = opts.profile or (function() - if type(globals) == "string" then - local picker_opts = M.globals[globals] - return picker_opts.profile or picker_opts[1] - end - end)() + local profile = opts.profile + or (function() + if type(globals) == "string" then + local picker_opts = M.globals[globals] + return picker_opts.profile or picker_opts[1] + end + end)() if type(profile) == "table" or type(profile) == "string" then -- TODO: we should probably cache the profiles M._profile_opts = utils.load_profiles(profile, 1) @@ -186,10 +196,10 @@ function M.normalize_opts(opts, globals, __resume_key) -- resume storage data lookup key, default to the calling function ref -- __FNCREF2__ will use the 2nd function ref in the stack (calling fn) opts.__resume_key = __resume_key - or opts.__resume_key - or (type(globals) == "string" and globals) - or (type(globals) == "table" and globals.__resume_key) - or utils.__FNCREF2__() + or opts.__resume_key + or (type(globals) == "string" and globals) + or (type(globals) == "table" and globals.__resume_key) + or utils.__FNCREF2__() if type(globals) == "string" then -- globals is a string, generate provider globals @@ -223,14 +233,17 @@ function M.normalize_opts(opts, globals, __resume_key) ["winopts.treesitter"] = "winopts.treesitter", ["previewer.treesitter"] = "previewers.builtin.treesitter", ["previewer.render_markdown"] = "previewers.builtin.render_markdown", - }) - do + }) do local v = utils.map_get(opts, k) if v == false then utils.map_set(opts, k, { enabled = false }) elseif v == true or type(v) == "table" then - local newv = vim.tbl_deep_extend("keep", type(v) == "table" and v or {}, - { enabled = true }, utils.map_get(M.defaults, vfrom) or {}) + local newv = vim.tbl_deep_extend( + "keep", + type(v) == "table" and v or {}, + { enabled = true }, + utils.map_get(M.defaults, vfrom) or {} + ) utils.map_set(opts, k, newv) end end @@ -241,10 +254,12 @@ function M.normalize_opts(opts, globals, __resume_key) ---@param m {fzf: table, builtin: table} ---@return {fzf: table, builtin: table}? local keymap_tolower = function(m, exclude_patterns) - return m and { - fzf = utils.map_tolower(m.fzf, exclude_patterns), - builtin = utils.map_tolower(m.builtin, exclude_patterns), - } or nil + return m + and { + fzf = utils.map_tolower(m.fzf, exclude_patterns), + builtin = utils.map_tolower(m.builtin, exclude_patterns), + } + or nil end local exclude_case_sensitive_alt = "^alt%-%a$" opts.keymap = keymap_tolower(eval(opts.keymap, opts), exclude_case_sensitive_alt) @@ -265,7 +280,8 @@ function M.normalize_opts(opts, globals, __resume_key) 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.") + "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 @@ -275,7 +291,12 @@ function M.normalize_opts(opts, globals, __resume_key) -- Merge values from globals for _, k in ipairs({ - "winopts", "keymap", "fzf_opts", "fzf_colors", "fzf_tmux_opts", "hls" + "winopts", + "keymap", + "fzf_opts", + "fzf_colors", + "fzf_tmux_opts", + "hls", }) do local setup_val = M.globals[k] if type(setup_val) == "function" then @@ -299,8 +320,8 @@ function M.normalize_opts(opts, globals, __resume_key) opts[k] = opts[k](opts) end if type(opts[k]) == "table" then - opts[k] = vim.tbl_deep_extend("keep", - opts[k], type(setup_val) == "table" and setup_val or {}) + opts[k] = + vim.tbl_deep_extend("keep", opts[k], type(setup_val) == "table" and setup_val or {}) end end end @@ -309,7 +330,9 @@ function M.normalize_opts(opts, globals, __resume_key) -- would be set to an empty string which would now translate into a shell escaped -- string as we automatically shell escape all fzf_opts for k, v in pairs(opts.fzf_opts) do - if v == "" then opts.fzf_opts[k] = true end + if v == "" then + opts.fzf_opts[k] = true + end end -- backward compat for `winopts.preview.{wrap|hidden}` @@ -337,7 +360,9 @@ function M.normalize_opts(opts, globals, __resume_key) for _, m in ipairs({ globals, M.globals }) do if m[k] then for _, item in ipairs(m[k]) do - if not opts[k] then opts[k] = {} end + if not opts[k] then + opts[k] = {} + end table.insert(opts[k], item) end end @@ -369,10 +394,9 @@ function M.normalize_opts(opts, globals, __resume_key) pattern_prompt = "[^%s]+" end if surround then - local pattern_capture = pattern_prefix .. - ("%s(%s)%s"):format(surround, pattern_prompt, surround) - local pattern_gsub = pattern_prefix .. - ("%s%s%s"):format(surround, pattern_prompt, surround) + local pattern_capture = pattern_prefix + .. ("%s(%s)%s"):format(surround, pattern_prompt, surround) + local pattern_gsub = pattern_prefix .. ("%s%s%s"):format(surround, pattern_prompt, surround) if opts[s]:match(pattern_gsub) then opts.prompt = opts[s]:match(pattern_capture) opts[s] = opts[s]:gsub(pattern_gsub, "") @@ -383,39 +407,39 @@ function M.normalize_opts(opts, globals, __resume_key) -- backward compatibility, rhs overrides lhs -- (rhs being the "old" option) local backward_compat = { - { "winopts.row", "winopts.win_row" }, - { "winopts.col", "winopts.win_col" }, - { "winopts.width", "winopts.win_width" }, - { "winopts.height", "winopts.win_height" }, - { "winopts.border", "winopts.win_border" }, - { "winopts.on_create", "winopts.window_on_create" }, - { "winopts.preview.wrap", "preview_wrap" }, - { "winopts.preview.border", "preview_border" }, - { "winopts.preview.hidden", "preview_opts" }, - { "winopts.preview.vertical", "preview_vertical" }, - { "winopts.preview.horizontal", "preview_horizontal" }, - { "winopts.preview.layout", "preview_layout" }, - { "winopts.preview.flip_columns", "flip_columns" }, - { "winopts.preview.default", "default_previewer" }, - { "winopts.preview.delay", "previewers.builtin.delay" }, - { "winopts.preview.title", "previewers.builtin.title" }, - { "winopts.preview.title_pos", "winopts.preview.title_align" }, - { "winopts.preview.scrollbar", "previewers.builtin.scrollbar" }, - { "winopts.preview.scrollchar", "previewers.builtin.scrollchar" }, - { "cwd_header", "show_cwd_header" }, - { "cwd_prompt", "show_cwd_prompt" }, - { "resume", "continue_last_search" }, - { "resume", "repeat_last_search" }, - { "jump1", "jump_to_single_result" }, - { "jump1_action", "jump_to_single_result_action" }, - { "hls.normal", "winopts.hl_normal" }, - { "hls.border", "winopts.hl_border" }, - { "hls.cursor", "previewers.builtin.hl_cursor" }, - { "hls.cursorline", "previewers.builtin.hl_cursorline" }, - { "hls", "winopts.hl" }, - { "previewer.treesitter.enabled", "previewer.treesitter.enable" }, - { "previewer.treesitter.disabled", "previewer.treesitter.disable" }, - { "previewers.builtin.treesitter.enabled", "previewers.builtin.treesitter.enable" }, + { "winopts.row", "winopts.win_row" }, + { "winopts.col", "winopts.win_col" }, + { "winopts.width", "winopts.win_width" }, + { "winopts.height", "winopts.win_height" }, + { "winopts.border", "winopts.win_border" }, + { "winopts.on_create", "winopts.window_on_create" }, + { "winopts.preview.wrap", "preview_wrap" }, + { "winopts.preview.border", "preview_border" }, + { "winopts.preview.hidden", "preview_opts" }, + { "winopts.preview.vertical", "preview_vertical" }, + { "winopts.preview.horizontal", "preview_horizontal" }, + { "winopts.preview.layout", "preview_layout" }, + { "winopts.preview.flip_columns", "flip_columns" }, + { "winopts.preview.default", "default_previewer" }, + { "winopts.preview.delay", "previewers.builtin.delay" }, + { "winopts.preview.title", "previewers.builtin.title" }, + { "winopts.preview.title_pos", "winopts.preview.title_align" }, + { "winopts.preview.scrollbar", "previewers.builtin.scrollbar" }, + { "winopts.preview.scrollchar", "previewers.builtin.scrollchar" }, + { "cwd_header", "show_cwd_header" }, + { "cwd_prompt", "show_cwd_prompt" }, + { "resume", "continue_last_search" }, + { "resume", "repeat_last_search" }, + { "jump1", "jump_to_single_result" }, + { "jump1_action", "jump_to_single_result_action" }, + { "hls.normal", "winopts.hl_normal" }, + { "hls.border", "winopts.hl_border" }, + { "hls.cursor", "previewers.builtin.hl_cursor" }, + { "hls.cursorline", "previewers.builtin.hl_cursorline" }, + { "hls", "winopts.hl" }, + { "previewer.treesitter.enabled", "previewer.treesitter.enable" }, + { "previewer.treesitter.disabled", "previewer.treesitter.disable" }, + { "previewers.builtin.treesitter.enabled", "previewers.builtin.treesitter.enable" }, { "previewers.builtin.treesitter.disabled", "previewers.builtin.treesitter.disable" }, } @@ -433,9 +457,13 @@ function M.normalize_opts(opts, globals, __resume_key) end utils.map_set(opts, old_key, nil) if not opts.silent then - utils.warn(string.format( - "Deprecated option: '%s' -> '%s'. Add 'silent=true' to hide this message.", - old_key, new_key)) + utils.warn( + string.format( + "Deprecated option: '%s' -> '%s'. Add 'silent=true' to hide this message.", + old_key, + new_key + ) + ) end end end @@ -488,12 +516,13 @@ function M.normalize_opts(opts, globals, __resume_key) end -- Exclude file icons from the fuzzy matching (#1080) - if opts.file_icons - and opts._fzf_nth_devicons - and not opts.fzf_opts["--delimiter"] - -- Can't work due to : delimiter (#2112) - and opts.previewer ~= "bat" - and opts.previewer ~= "bat_native" + if + opts.file_icons + and opts._fzf_nth_devicons + and not opts.fzf_opts["--delimiter"] + -- Can't work due to : delimiter (#2112) + and opts.previewer ~= "bat" + and opts.previewer ~= "bat_native" then opts.fzf_opts["--nth"] = opts.fzf_opts["--nth"] or "-1.." opts.fzf_opts["--delimiter"] = string.format("[%s]", utils.nbsp) @@ -506,19 +535,22 @@ function M.normalize_opts(opts, globals, __resume_key) end -- "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" + if + type(opts.previewer) == "table" + or opts.previewer == true + or opts.previewer == "hidden" + or opts.previewer == "nohidden" then -- of type string, can only be "hidden|nohidden" if type(opts.previewer) == "string" then assert(opts.previewer == "hidden" or opts.previewer == "nohidden") utils.map_set(opts, "winopts.preview.hidden", opts.previewer ~= "nohidden") end - opts.previewer = vim.tbl_deep_extend("keep", + opts.previewer = vim.tbl_deep_extend( + "keep", type(opts.previewer) == "table" and opts.previewer or {}, - M.globals.previewers.builtin) + M.globals.previewers.builtin + ) end -- Convert again in case the bool option came from global opts @@ -526,7 +558,8 @@ function M.normalize_opts(opts, globals, __resume_key) -- Auto-generate fzf's colorscheme opts.fzf_colors = type(opts.fzf_colors) == "table" and opts.fzf_colors - or opts.fzf_colors == true and { true } or {} + or opts.fzf_colors == true and { true } + or {} -- Inerherit from fzf.vim's g:fzf_colors -- fzf.vim: @@ -537,47 +570,56 @@ function M.normalize_opts(opts, globals, __resume_key) -- fzf_colors = { -- ["fg"] = { "fg" , { "Comment", "Normal" } } -- } - opts.fzf_colors = vim.tbl_extend("keep", opts.fzf_colors, + opts.fzf_colors = vim.tbl_extend( + "keep", + opts.fzf_colors, vim.tbl_map(function(v) -- Value isn't guaranteed a table, e.g: -- vim.g.fzf_colors = { ["gutter"] = "-1" } - if type(v) ~= "table" then return tostring(v) end + if type(v) ~= "table" then + return tostring(v) + end -- We accept both fzf.vim and fzf-lua style values - if type(v[2]) == "table" then return v end + if type(v[2]) == "table" then + return v + end local new_v = { v[1], { v[2] } } for i = 3, #v do table.insert(new_v[2], v[i]) end return new_v - end, type(vim.g.fzf_colors) == "table" and vim.g.fzf_colors or {})) + end, type(vim.g.fzf_colors) == "table" and vim.g.fzf_colors or {}) + ) if opts.fzf_colors[1] == true then opts.fzf_colors[1] = nil opts.fzf_colors = vim.tbl_deep_extend("keep", opts.fzf_colors, { - ["fg"] = { "fg", opts.hls.fzf.normal }, - ["bg"] = { "bg", opts.hls.fzf.normal }, - ["hl"] = { "fg", opts.hls.fzf.match }, - ["fg+"] = { "fg", { opts.hls.fzf.cursorline, opts.hls.fzf.normal } }, - ["bg+"] = { "bg", opts.hls.fzf.cursorline }, - ["hl+"] = { "fg", opts.hls.fzf.match }, - ["info"] = { "fg", opts.hls.fzf.info }, - ["border"] = { "fg", opts.hls.fzf.border }, - ["gutter"] = { "bg", opts.hls.fzf.gutter }, - ["query"] = { "fg", opts.hls.fzf.query, "regular" }, - ["prompt"] = { "fg", opts.hls.fzf.prompt }, - ["pointer"] = { "fg", opts.hls.fzf.pointer }, - ["marker"] = { "fg", opts.hls.fzf.marker }, - ["spinner"] = { "fg", opts.hls.fzf.spinner }, - ["header"] = { "fg", opts.hls.fzf.header }, + ["fg"] = { "fg", opts.hls.fzf.normal }, + ["bg"] = { "bg", opts.hls.fzf.normal }, + ["hl"] = { "fg", opts.hls.fzf.match }, + ["fg+"] = { "fg", { opts.hls.fzf.cursorline, opts.hls.fzf.normal } }, + ["bg+"] = { "bg", opts.hls.fzf.cursorline }, + ["hl+"] = { "fg", opts.hls.fzf.match }, + ["info"] = { "fg", opts.hls.fzf.info }, + ["border"] = { "fg", opts.hls.fzf.border }, + ["gutter"] = { "bg", opts.hls.fzf.gutter }, + ["query"] = { "fg", opts.hls.fzf.query, "regular" }, + ["prompt"] = { "fg", opts.hls.fzf.prompt }, + ["pointer"] = { "fg", opts.hls.fzf.pointer }, + ["marker"] = { "fg", opts.hls.fzf.marker }, + ["spinner"] = { "fg", opts.hls.fzf.spinner }, + ["header"] = { "fg", opts.hls.fzf.header }, ["separator"] = { "fg", opts.hls.fzf.separator }, - ["scrollbar"] = { "fg", opts.hls.fzf.scrollbar } + ["scrollbar"] = { "fg", opts.hls.fzf.scrollbar }, }) end -- Adjust main fzf window treesitter settings -- Disabled unless the picker is TS enabled with `_treesitter=true` -- Unless `enabled=false` is specifically set `true` is asssumed - if not opts._treesitter then opts.winopts.treesitter = nil end + if not opts._treesitter then + opts.winopts.treesitter = nil + end if not opts.winopts.treesitter or opts.winopts.treesitter.enabled == false then opts.winopts.treesitter = nil else @@ -588,11 +630,13 @@ function M.normalize_opts(opts, globals, __resume_key) -- 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 = vim.tbl_deep_extend( + "force", type(opts.fzf_colors) == "table" and opts.fzf_colors or {}, M.defaults.winopts.treesitter.fzf_colors, - type(opts.winopts.treesitter.fzf_colors) == "table" - and opts.winopts.treesitter.fzf_colors or {}) + type(opts.winopts.treesitter.fzf_colors) == "table" and opts.winopts.treesitter.fzf_colors + or {} + ) end end @@ -641,8 +685,7 @@ function M.normalize_opts(opts, globals, __resume_key) opts.fzf_bin = opts.fzf_bin or M.globals.fzf_bin opts.fzf_bin = opts.fzf_bin and libuv.expand(opts.fzf_bin) or nil - if not opts.fzf_bin or - not executable(opts.fzf_bin, utils.warn, "fallback to 'fzf'.") then + if not opts.fzf_bin or not executable(opts.fzf_bin, utils.warn, "fallback to 'fzf'.") then -- default|fallback to fzf opts.fzf_bin = "fzf" -- try fzf plugin if fzf is not installed globally @@ -652,8 +695,9 @@ function M.normalize_opts(opts, globals, __resume_key) opts.fzf_bin = fzf_plug end end - if not executable(opts.fzf_bin, utils.err, - "aborting. Please make sure 'fzf' is in installed.") then + if + not executable(opts.fzf_bin, utils.err, "aborting. Please make sure 'fzf' is in installed.") + then return nil end end @@ -671,8 +715,12 @@ function M.normalize_opts(opts, globals, __resume_key) utils.err(string.format("'fzf --version' failed with error %s: %s", rc, err)) return nil elseif not utils.has(opts, "fzf", { 0, 25 }) then - utils.err(string.format("fzf version %s is lower than minimum (0.25), aborting.", - utils.ver2str(opts.__FZF_VERSION))) + utils.err( + string.format( + "fzf version %s is lower than minimum (0.25), aborting.", + utils.ver2str(opts.__FZF_VERSION) + ) + ) return nil end else @@ -684,14 +732,19 @@ function M.normalize_opts(opts, globals, __resume_key) end end - if utils.has(opts, "fzf", { 0, 53 }) - -- `_multiline` is used to override `multiline` inherited from `defaults = {}` - and opts.multiline and opts._multiline ~= false then + if + utils.has(opts, "fzf", { 0, 53 }) + -- `_multiline` is used to override `multiline` inherited from `defaults = {}` + and opts.multiline + and opts._multiline ~= false + then -- If `multiline` was specified we add both "read0" & "print0" flags opts.fzf_opts["--read0"] = true opts.fzf_opts["--print0"] = true local gap = (tonumber(opts.multiline) or 1) - 1 - if gap > 0 then opts.fzf_opts["--gap"] = gap end + if gap > 0 then + opts.fzf_opts["--gap"] = gap + end else -- If not possible (fzf v<0.53|skim), nullify the option opts.multiline = nil @@ -704,96 +757,114 @@ function M.normalize_opts(opts, globals, __resume_key) -- (3) `table` flags are removed if the value is contained local bin, version, changelog = (function() if opts.__SK_VERSION then - return "sk", opts.__SK_VERSION, { - ["0.15.5"] = { fzf_opts = { ["--tmux"] = true } }, - ["0.53"] = { fzf_opts = { ["--inline-info"] = true } }, - -- All fzf flags not existing in skim - ["all"] = { - fzf_opts = { - ["--scheme"] = false, - ["--gap"] = false, - ["--info"] = false, - ["--border"] = false, - ["--scrollbar"] = false, - ["--no-scrollbar"] = false, - ["--wrap"] = true, - ["--wrap-sign"] = true, - ["--highlight-line"] = false, - } - }, - } + return "sk", + opts.__SK_VERSION, + { + ["0.15.5"] = { fzf_opts = { ["--tmux"] = true } }, + ["0.53"] = { fzf_opts = { ["--inline-info"] = true } }, + -- All fzf flags not existing in skim + ["all"] = { + fzf_opts = { + ["--scheme"] = false, + ["--gap"] = false, + ["--info"] = false, + ["--border"] = false, + ["--scrollbar"] = false, + ["--no-scrollbar"] = false, + ["--wrap"] = true, + ["--wrap-sign"] = true, + ["--highlight-line"] = false, + }, + }, + } else - return "fzf", opts.__FZF_VERSION, { - ["0.59"] = { fzf_opts = { ["--scheme"] = "path" } }, - ["0.56"] = { fzf_opts = { ["--gap"] = true } }, - ["0.54"] = { - fzf_opts = { - ["--wrap"] = true, - ["--wrap-sign"] = true, - ["--highlight-line"] = true, - } - }, - ["0.53"] = { fzf_opts = { ["--tmux"] = true } }, - ["0.52"] = { fzf_opts = { ["--highlight-line"] = true } }, - ["0.42"] = { - fzf_opts = { - ["--info"] = { "right", "inline-right" }, - } - }, - ["0.39"] = { fzf_opts = { ["--track"] = true } }, - ["0.36"] = { - fzf_opts = { - ["--listen"] = true, - ["--scrollbar"] = true, - ["--no-scrollbar"] = true, - } - }, - ["0.35"] = { - fzf_opts = { - ["--border"] = { "bold", "double" }, - ["--border-label"] = true, - ["--border-label-pos"] = true, - ["--preview-label"] = true, - ["--preview-label-pos"] = true, - } - }, - ["0.33"] = { fzf_opts = { ["--scheme"] = true } }, - ["0.30"] = { fzf_opts = { ["--ellipsis"] = true } }, - ["0.28"] = { - fzf_opts = { - ["--header-first"] = true, - ["--scroll-off"] = true, - } - }, - ["0.27"] = { fzf_opts = { ["--border"] = "none" } }, - -- All skim flags not existing in fzf - ["all"] = { - fzf_opts = { - ["--inline-info"] = false, - } - }, - } + return "fzf", + opts.__FZF_VERSION, + { + ["0.59"] = { fzf_opts = { ["--scheme"] = "path" } }, + ["0.56"] = { fzf_opts = { ["--gap"] = true } }, + ["0.54"] = { + fzf_opts = { + ["--wrap"] = true, + ["--wrap-sign"] = true, + ["--highlight-line"] = true, + }, + }, + ["0.53"] = { fzf_opts = { ["--tmux"] = true } }, + ["0.52"] = { fzf_opts = { ["--highlight-line"] = true } }, + ["0.42"] = { + fzf_opts = { + ["--info"] = { "right", "inline-right" }, + }, + }, + ["0.39"] = { fzf_opts = { ["--track"] = true } }, + ["0.36"] = { + fzf_opts = { + ["--listen"] = true, + ["--scrollbar"] = true, + ["--no-scrollbar"] = true, + }, + }, + ["0.35"] = { + fzf_opts = { + ["--border"] = { "bold", "double" }, + ["--border-label"] = true, + ["--border-label-pos"] = true, + ["--preview-label"] = true, + ["--preview-label-pos"] = true, + }, + }, + ["0.33"] = { fzf_opts = { ["--scheme"] = true } }, + ["0.30"] = { fzf_opts = { ["--ellipsis"] = true } }, + ["0.28"] = { + fzf_opts = { + ["--header-first"] = true, + ["--scroll-off"] = true, + }, + }, + ["0.27"] = { fzf_opts = { ["--border"] = "none" } }, + -- All skim flags not existing in fzf + ["all"] = { + fzf_opts = { + ["--inline-info"] = false, + }, + }, + } end end)() local function warn(flag, val, min_ver) - return utils.warn(string.format("Removed flag '%s%s', %s.", - flag, type(val) == "string" and "=" .. val or "", - not min_ver and string.format("not supported with %s", bin) - or string.format("only supported with %s v%s (has=%s)", - bin, utils.ver2str(min_ver), utils.ver2str(version)) - )) + return utils.warn( + string.format( + "Removed flag '%s%s', %s.", + flag, + type(val) == "string" and "=" .. val or "", + not min_ver and string.format("not supported with %s", bin) + or string.format( + "only supported with %s v%s (has=%s)", + bin, + utils.ver2str(min_ver), + utils.ver2str(version) + ) + ) + ) end for min_verstr, ver_data in pairs(changelog) do for flag, non_compat_value in pairs(ver_data.fzf_opts) do (function() local min_ver = utils.parse_verstr(min_verstr) local opt_value = opts.fzf_opts[flag] - if not opt_value then return end - non_compat_value = type(non_compat_value) == "string" - and { non_compat_value } or non_compat_value - if not min_ver or not utils.has(opts, bin, min_ver) - and (non_compat_value == true or type(non_compat_value) == "table" - and utils.tbl_contains(non_compat_value, opt_value)) + if not opt_value then + return + end + non_compat_value = type(non_compat_value) == "string" and { non_compat_value } + or non_compat_value + if + not min_ver + or not utils.has(opts, bin, min_ver) + and (non_compat_value == true or type(non_compat_value) == "table" and utils.tbl_contains( + non_compat_value, + opt_value + )) then if opts.compat_warn == true then warn(flag, opt_value, min_ver) @@ -812,12 +883,11 @@ function M.normalize_opts(opts, globals, __resume_key) opts.fzf_opts["--tmux"] = nil return end - local is_tmux = - (opts.fzf_bin:match("fzf%-tmux$") or opts.fzf_bin:match("sk%-tmux$")) and 1 - -- fzf v0.53 added native tmux integration - or utils.has(opts, "fzf", { 0, 53 }) and opts.fzf_opts["--tmux"] and 2 - -- skim v0.15.5 added native tmux integration - or utils.has(opts, "sk", { 0, 15, 5 }) and opts.fzf_opts["--tmux"] and 2 + local is_tmux = (opts.fzf_bin:match("fzf%-tmux$") or opts.fzf_bin:match("sk%-tmux$")) and 1 + -- fzf v0.53 added native tmux integration + or utils.has(opts, "fzf", { 0, 53 }) and opts.fzf_opts["--tmux"] and 2 + -- skim v0.15.5 added native tmux integration + or utils.has(opts, "sk", { 0, 15, 5 }) and opts.fzf_opts["--tmux"] and 2 if is_tmux == 1 then -- backward compat when using the `fzf-tmux` script: prioritize fzf-tmux -- split pane flags over the popup flag `-p` from fzf-lua defaults (#865) @@ -833,9 +903,11 @@ function M.normalize_opts(opts, globals, __resume_key) end)() -- refresh highlights if background/colorscheme changed (#1092) - if not M.__HLS_STATE - or M.__HLS_STATE.bg ~= vim.o.bg - or M.__HLS_STATE.colorscheme ~= vim.g.colors_name then + if + not M.__HLS_STATE + or M.__HLS_STATE.bg ~= vim.o.bg + or M.__HLS_STATE.colorscheme ~= vim.g.colors_name + then utils.setup_highlights() end @@ -849,25 +921,29 @@ function M.normalize_opts(opts, globals, __resume_key) utils.cache_ansi_escseq(hlgroup, escseq) end - if opts.file_icons then -- refresh icons, does nothing if "vim.o.bg" didn't change - if not devicons.load({ - plugin = opts.file_icons, - icon_padding = opts.file_icon_padding, - dir_icon = { - icon = opts.dir_icon, - color = utils.hexcol_from_hl(opts.hls.dir_icon, "fg") - } - }) + if + not devicons.load({ + plugin = opts.file_icons, + icon_padding = opts.file_icon_padding, + dir_icon = { + icon = opts.dir_icon, + color = utils.hexcol_from_hl(opts.hls.dir_icon, "fg"), + }, + }) then -- Disable file_icons if requested package isn't available -- we set the default value to "1" but since it's the default -- don't display the warning unless the user specifically set -- file_icons to `true` or `mini|devicons` if not tonumber(opts.file_icons) then - utils.warn(string.format("error loading '%s', disabling 'file_icons'.", - opts.file_icons == "mini" and "mini.icons" or "nvim-web-devicons")) + utils.warn( + string.format( + "error loading '%s', disabling 'file_icons'.", + opts.file_icons == "mini" and "mini.icons" or "nvim-web-devicons" + ) + ) end opts.file_icons = nil end @@ -880,9 +956,9 @@ function M.normalize_opts(opts, globals, __resume_key) -- which we do in "make_entry.postprocess" opts.__mt_postprocess = opts.multiprocess and [[return require("fzf-lua.make_entry").postprocess]] - -- NOTE: we don't need to update mini when running on main thread - -- or require("fzf-lua.make_entry").postprocess - or nil + -- NOTE: we don't need to update mini when running on main thread + -- or require("fzf-lua.make_entry").postprocess + or nil end end @@ -890,22 +966,28 @@ function M.normalize_opts(opts, globals, __resume_key) utils.warn("'line_query' requires fzf >= 0.59, ignoring.") elseif opts.line_query then utils.map_set(opts, "winopts.preview.winopts.cursorline", true) - utils.map_set(opts, "keymap.fzf.change", - "transform:" .. FzfLua.shell.raw_action(function(q, _, _) - local lnum = q[1]:match(":(%d+)$") - local new_q, subs = q[1]:gsub(":%d*$", "") - -- No subs made, no ":" at end of string, do nothing - if subs == 0 then return end - local trans = string.format("search(%s)", new_q) - local win = FzfLua.win.__SELF() - -- Do we need to change the offset in native fzf previewer (e.g. bat)? - if lnum and win and win._previewer and win._previewer._preview_offset then - local optstr = opts.fzf_opts["--preview-window"] - local offset = win._previewer:_preview_offset(lnum) - trans = string.format("%s+change-preview-window(%s:%s)", trans, optstr, offset) - end - return trans - end, "{q}", opts.debug)) + utils.map_set( + opts, + "keymap.fzf.change", + "transform:" + .. FzfLua.shell.raw_action(function(q, _, _) + local lnum = q[1]:match(":(%d+)$") + local new_q, subs = q[1]:gsub(":%d*$", "") + -- No subs made, no ":" at end of string, do nothing + if subs == 0 then + return + end + local trans = string.format("search(%s)", new_q) + local win = FzfLua.win.__SELF() + -- Do we need to change the offset in native fzf previewer (e.g. bat)? + if lnum and win and win._previewer and win._previewer._preview_offset then + local optstr = opts.fzf_opts["--preview-window"] + local offset = win._previewer:_preview_offset(lnum) + trans = string.format("%s+change-preview-window(%s:%s)", trans, optstr, offset) + end + return trans + end, "{q}", opts.debug) + ) end if type(opts.enrich) == "function" then @@ -926,7 +1008,9 @@ M.bytecode = function(s, datatype) local iter = M for i = 1, #keys do iter = iter[keys[i]] - if not iter then break end + if not iter then + break + end if i == #keys and type(iter) == datatype then -- Not sure if second argument 'true' is needed -- can't find any references for it other than @@ -946,16 +1030,16 @@ M.get_action_helpstr = function(fn) end M._action_to_helpstr = { - [actions.dummy_abort] = "abort", - [actions.file_edit] = "file-edit", - [actions.file_edit_or_qf] = "file-edit-or-qf", - [actions.file_split] = "file-split", - [actions.file_vsplit] = "file-vsplit", - [actions.file_tabedit] = "file-tabedit", - [actions.file_sel_to_qf] = "file-selection-to-qf", - [actions.file_sel_to_ll] = "file-selection-to-loclist", - [actions.file_switch] = "file-switch", - [actions.file_switch_or_edit] = "file-switch-or-edit", + [actions.dummy_abort] = "abort", + [actions.file_edit] = "file-edit", + [actions.file_edit_or_qf] = "file-edit-or-qf", + [actions.file_split] = "file-split", + [actions.file_vsplit] = "file-vsplit", + [actions.file_tabedit] = "file-tabedit", + [actions.file_sel_to_qf] = "file-selection-to-qf", + [actions.file_sel_to_ll] = "file-selection-to-loclist", + [actions.file_switch] = "file-switch", + [actions.file_switch_or_edit] = "file-switch-or-edit", -- Since default actions refactor these are just refs to -- their correspondent `file_xxx` equivalents -- [actions.buf_edit] = "buffer-edit", @@ -967,67 +1051,67 @@ M._action_to_helpstr = { -- [actions.buf_tabedit] = "buffer-tabedit", -- [actions.buf_switch] = "buffer-switch", -- [actions.buf_switch_or_edit] = "buffer-switch-or-edit", - [actions.buf_del] = "buffer-delete", - [actions.run_builtin] = "run-builtin", - [actions.ex_run] = "edit-cmd", - [actions.ex_run_cr] = "exec-cmd", - [actions.exec_menu] = "exec-menu", - [actions.search] = "edit-search", - [actions.search_cr] = "exec-search", - [actions.goto_mark] = "goto-mark", - [actions.goto_jump] = "goto-jump", - [actions.keymap_apply] = "keymap-apply", - [actions.keymap_edit] = "keymap-edit", - [actions.keymap_split] = "keymap-split", - [actions.keymap_vsplit] = "keymap-vsplit", - [actions.keymap_tabedit] = "keymap-tabedit", - [actions.nvim_opt_edit_local] = "nvim-opt-edit-local", + [actions.buf_del] = "buffer-delete", + [actions.run_builtin] = "run-builtin", + [actions.ex_run] = "edit-cmd", + [actions.ex_run_cr] = "exec-cmd", + [actions.exec_menu] = "exec-menu", + [actions.search] = "edit-search", + [actions.search_cr] = "exec-search", + [actions.goto_mark] = "goto-mark", + [actions.goto_jump] = "goto-jump", + [actions.keymap_apply] = "keymap-apply", + [actions.keymap_edit] = "keymap-edit", + [actions.keymap_split] = "keymap-split", + [actions.keymap_vsplit] = "keymap-vsplit", + [actions.keymap_tabedit] = "keymap-tabedit", + [actions.nvim_opt_edit_local] = "nvim-opt-edit-local", [actions.nvim_opt_edit_global] = "nvim-opt-edit-global", - [actions.spell_apply] = "spell-apply", - [actions.spell_suggest] = "spell-suggest", - [actions.set_filetype] = "set-filetype", - [actions.packadd] = "packadd", - [actions.help] = "help-open", - [actions.help_vert] = "help-vertical", - [actions.help_tab] = "help-tab", - [actions.man] = "man-open", - [actions.man_vert] = "man-vertical", - [actions.man_tab] = "man-tab", - [actions.git_branch_add] = "git-branch-add", - [actions.git_branch_del] = "git-branch-del", - [actions.git_switch] = "git-switch", - [actions.git_checkout] = "git-checkout", - [actions.git_reset] = "git-reset", - [actions.git_stage] = "git-stage", - [actions.git_unstage] = "git-unstage", - [actions.git_stage_unstage] = "git-stage-unstage", - [actions.git_stash_pop] = "git-stash-pop", - [actions.git_stash_drop] = "git-stash-drop", - [actions.git_stash_apply] = "git-stash-apply", - [actions.git_buf_edit] = "git-buffer-edit", - [actions.git_buf_tabedit] = "git-buffer-tabedit", - [actions.git_buf_split] = "git-buffer-split", - [actions.git_buf_vsplit] = "git-buffer-vsplit", - [actions.git_goto_line] = "git-goto-line", - [actions.git_yank_commit] = "git-yank-commit", - [actions.arg_add] = "arg-list-add", - [actions.arg_del] = "arg-list-delete", - [actions.toggle_ignore] = "toggle-ignore", - [actions.toggle_hidden] = "toggle-hidden", - [actions.toggle_follow] = "toggle-follow", - [actions.grep_lgrep] = "grep<->lgrep", - [actions.sym_lsym] = "sym<->lsym", - [actions.tmux_buf_set_reg] = "set-register", - [actions.paste_register] = "paste-register", - [actions.set_qflist] = "set-{qf|loc}list", - [actions.apply_profile] = "apply-profile", - [actions.complete] = "complete", - [actions.dap_bp_del] = "dap-bp-delete", - [actions.colorscheme] = "colorscheme-apply", - [actions.cs_delete] = "colorscheme-delete", - [actions.cs_update] = "colorscheme-update", - [actions.toggle_bg] = "toggle-background", - [actions.cd] = "change-directory", + [actions.spell_apply] = "spell-apply", + [actions.spell_suggest] = "spell-suggest", + [actions.set_filetype] = "set-filetype", + [actions.packadd] = "packadd", + [actions.help] = "help-open", + [actions.help_vert] = "help-vertical", + [actions.help_tab] = "help-tab", + [actions.man] = "man-open", + [actions.man_vert] = "man-vertical", + [actions.man_tab] = "man-tab", + [actions.git_branch_add] = "git-branch-add", + [actions.git_branch_del] = "git-branch-del", + [actions.git_switch] = "git-switch", + [actions.git_checkout] = "git-checkout", + [actions.git_reset] = "git-reset", + [actions.git_stage] = "git-stage", + [actions.git_unstage] = "git-unstage", + [actions.git_stage_unstage] = "git-stage-unstage", + [actions.git_stash_pop] = "git-stash-pop", + [actions.git_stash_drop] = "git-stash-drop", + [actions.git_stash_apply] = "git-stash-apply", + [actions.git_buf_edit] = "git-buffer-edit", + [actions.git_buf_tabedit] = "git-buffer-tabedit", + [actions.git_buf_split] = "git-buffer-split", + [actions.git_buf_vsplit] = "git-buffer-vsplit", + [actions.git_goto_line] = "git-goto-line", + [actions.git_yank_commit] = "git-yank-commit", + [actions.arg_add] = "arg-list-add", + [actions.arg_del] = "arg-list-delete", + [actions.toggle_ignore] = "toggle-ignore", + [actions.toggle_hidden] = "toggle-hidden", + [actions.toggle_follow] = "toggle-follow", + [actions.grep_lgrep] = "grep<->lgrep", + [actions.sym_lsym] = "sym<->lsym", + [actions.tmux_buf_set_reg] = "set-register", + [actions.paste_register] = "paste-register", + [actions.set_qflist] = "set-{qf|loc}list", + [actions.apply_profile] = "apply-profile", + [actions.complete] = "complete", + [actions.dap_bp_del] = "dap-bp-delete", + [actions.colorscheme] = "colorscheme-apply", + [actions.cs_delete] = "colorscheme-delete", + [actions.cs_update] = "colorscheme-update", + [actions.toggle_bg] = "toggle-background", + [actions.cd] = "change-directory", } return M diff --git a/lua/fzf-lua/core.lua b/lua/fzf-lua/core.lua index f843e7b7d..65bca68a7 100644 --- a/lua/fzf-lua/core.lua +++ b/lua/fzf-lua/core.lua @@ -1,22 +1,22 @@ local uv = vim.uv or vim.loop -local fzf = require "fzf-lua.fzf" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local actions = require "fzf-lua.actions" -local win = require "fzf-lua.win" -local libuv = require "fzf-lua.libuv" -local shell = require "fzf-lua.shell" -local make_entry = require "fzf-lua.make_entry" -local base64 = require "fzf-lua.lib.base64" -local serpent = require "fzf-lua.lib.serpent" +local fzf = require("fzf-lua.fzf") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local actions = require("fzf-lua.actions") +local win = require("fzf-lua.win") +local libuv = require("fzf-lua.libuv") +local shell = require("fzf-lua.shell") +local make_entry = require("fzf-lua.make_entry") +local base64 = require("fzf-lua.lib.base64") +local serpent = require("fzf-lua.lib.serpent") local M = {} M.ACTION_DEFINITIONS = { -- list of supported actions with labels to be displayed in the headers -- no pos implies an append to header array - [actions.toggle_ignore] = { + [actions.toggle_ignore] = { function(o) local flag = o.toggle_ignore_flag or "--no-ignore" if o.cmd and o.cmd:match(utils.lua_regex_escape(flag)) then @@ -26,7 +26,7 @@ M.ACTION_DEFINITIONS = { end end, }, - [actions.toggle_hidden] = { + [actions.toggle_hidden] = { function(o) local flag = o.toggle_hidden_flag or "--hidden" if o.cmd and o.cmd:match(utils.lua_regex_escape(flag)) then @@ -36,7 +36,7 @@ M.ACTION_DEFINITIONS = { end end, }, - [actions.toggle_follow] = { + [actions.toggle_follow] = { function(o) local flag = o.toggle_follow_flag or "-L" if o.cmd and o.cmd:match(utils.lua_regex_escape(flag)) then @@ -46,7 +46,7 @@ M.ACTION_DEFINITIONS = { end end, }, - [actions.grep_lgrep] = { + [actions.grep_lgrep] = { function(o) if o.fn_reload then return "Fuzzy Search" @@ -55,7 +55,7 @@ M.ACTION_DEFINITIONS = { end end, }, - [actions.sym_lsym] = { + [actions.sym_lsym] = { function(o) if o.fn_reload then return "Fuzzy Search" @@ -64,29 +64,29 @@ M.ACTION_DEFINITIONS = { end end, }, - [actions.toggle_bg] = { + [actions.toggle_bg] = { function(_) -- return string.format("set bg=%s", vim.o.background == "dark" and "light" or "dark") return "toggle bg" end, }, - [actions.buf_del] = { "close" }, - [actions.arg_del] = { "delete" }, - [actions.dap_bp_del] = { "delete" }, - [actions.cs_delete] = { "uninstall" }, - [actions.cs_update] = { "[down|re]-load" }, - [actions.git_reset] = { "reset" }, - [actions.git_stage] = { "stage", pos = 1 }, - [actions.git_unstage] = { "unstage", pos = 2 }, + [actions.buf_del] = { "close" }, + [actions.arg_del] = { "delete" }, + [actions.dap_bp_del] = { "delete" }, + [actions.cs_delete] = { "uninstall" }, + [actions.cs_update] = { "[down|re]-load" }, + [actions.git_reset] = { "reset" }, + [actions.git_stage] = { "stage", pos = 1 }, + [actions.git_unstage] = { "unstage", pos = 2 }, [actions.git_stage_unstage] = { "[un-]stage", pos = 1 }, - [actions.git_stash_drop] = { "drop a stash" }, - [actions.git_yank_commit] = { "copy commit hash" }, - [actions.git_branch_add] = { "add branch" }, - [actions.git_branch_del] = { "delete branch" }, - [actions.ex_run] = { "edit" }, - [actions.ex_run_cr] = { "execute" }, - [actions.search] = { "edit" }, - [actions.search_cr] = { "search" }, + [actions.git_stash_drop] = { "drop a stash" }, + [actions.git_yank_commit] = { "copy commit hash" }, + [actions.git_branch_add] = { "add branch" }, + [actions.git_branch_del] = { "delete branch" }, + [actions.ex_run] = { "edit" }, + [actions.ex_run_cr] = { "execute" }, + [actions.search] = { "edit" }, + [actions.search_cr] = { "search" }, } -- converts contents array sent to `fzf_exec` into a single contents @@ -100,11 +100,9 @@ local contents_from_arr = function(cont_arr) contents = {} for _, t in ipairs(cont_arr) do assert(type(t.contents) == cont_type, "Unable to combine contents of different types") - contents = utils.tbl_join(contents, t.prefix and - vim.tbl_map(function(x) - return t.prefix .. x - end, t.contents) - or t.contents) + contents = utils.tbl_join(contents, t.prefix and vim.tbl_map(function(x) + return t.prefix .. x + end, t.contents) or t.contents) end elseif cont_type == "function" then contents = function(fzf_cb) @@ -151,7 +149,9 @@ M.fzf_exec = function(contents, opts) end if not opts or not opts._normalized then opts = config.normalize_opts(opts or {}, {}) - if not opts then return end + if not opts then + return + end end -- save a copy of cprovider info in the opts, we later use it for better named -- quickfix lists, use `pcall` because we will circular ref main object (#776) @@ -162,12 +162,14 @@ M.fzf_exec = function(contents, opts) -- wrapper for command transformer if type(contents) == "string" and (opts.fn_transform or opts.fn_preprocess) then contents = libuv.spawn_nvim_fzf_cmd({ - cmd = contents, - cwd = opts.cwd, - cb_pid = function(pid) opts.__pid = pid end, - }, - opts.fn_transform or function(x) return x end, - opts.fn_preprocess) + cmd = contents, + cwd = opts.cwd, + cb_pid = function(pid) + opts.__pid = pid + end, + }, opts.fn_transform or function(x) + return x + end, opts.fn_preprocess) end -- setup as "live": disables fuzzy matching and reload the content -- every keystroke (query changed), utilizes fzf's 'change:reload' @@ -216,7 +218,9 @@ end M.fzf_resume = function(opts) -- First try to unhide the window - if win.unhide() then return end + if win.unhide() then + return + end if not config.__resume_data or not config.__resume_data.opts then utils.info("No resume data available.") return @@ -238,7 +242,9 @@ M.fzf_wrap = function(opts, contents, fn_selected) local _co coroutine.wrap(function() _co = coroutine.running() - if type(opts.cb_co) == "function" then opts.cb_co(_co) end + if type(opts.cb_co) == "function" then + opts.cb_co(_co) + end opts.fn_selected = opts.fn_selected or fn_selected local selected = M.fzf(contents, opts) if opts.fn_selected then @@ -266,15 +272,16 @@ M.CTX = function(opts) -- save caller win/buf context, ignore when fzf -- is already open (actions.sym_lsym|grep_lgrep) local winobj = utils.fzf_winobj() - if not M.__CTX - -- when called from the LSP module in "sync" mode when no results are found - -- the fzf window won't open (e.g. "No references found") and the context is - -- never cleared. The below condition validates the source window when the - -- UI is not open (#907) - or (not winobj and M.__CTX.bufnr ~= vim.api.nvim_get_current_buf()) - -- we should never get here when fzf process is hidden unless the user requested - -- not to resume or a different picker, i.e. hide files and open buffers - or winobj and winobj:hidden() + if + not M.__CTX + -- when called from the LSP module in "sync" mode when no results are found + -- the fzf window won't open (e.g. "No references found") and the context is + -- never cleared. The below condition validates the source window when the + -- UI is not open (#907) + or (not winobj and M.__CTX.bufnr ~= vim.api.nvim_get_current_buf()) + -- we should never get here when fzf process is hidden unless the user requested + -- not to resume or a different picker, i.e. hide files and open buffers + or winobj and winobj:hidden() then M.__CTX = { mode = vim.api.nvim_get_mode().mode, @@ -293,7 +300,7 @@ M.CTX = function(opts) ret[tostring(w)] = true end return ret - end)() + end)(), } end -- perhaps a min impact optimization but since only @@ -330,7 +337,9 @@ M.fzf = function(contents, opts) -- normalize with globals if not already normalized if not opts or not opts._normalized then opts = config.normalize_opts(opts or {}, {}) - if not opts then return end + if not opts then + return + end end -- flag used to print the query on stdout line 1 -- later to be removed from the result by M.fzf() @@ -344,8 +353,7 @@ M.fzf = function(contents, opts) opts.keymap = opts.keymap or {} opts.keymap.fzf = opts.keymap.fzf or {} for _, k in ipairs({ "ctrl-c", "ctrl-q", "esc", "enter" }) do - if opts.actions[k] == nil and (opts.keymap.fzf[k] == nil or opts.keymap.fzf[k] == "abort") - then + if opts.actions[k] == nil and (opts.keymap.fzf[k] == nil or opts.keymap.fzf[k] == "abort") then opts.actions[k] = actions.dummy_abort end end @@ -420,9 +428,15 @@ M.fzf = function(contents, opts) -- some functions such as buffers|tabs -- need to reacquire current buffer|tab state - if opts.__fn_pre_fzf then opts.__fn_pre_fzf(opts) end - if opts._fn_pre_fzf then opts._fn_pre_fzf(opts) end - if opts.fn_pre_fzf then opts.fn_pre_fzf(opts) end + if opts.__fn_pre_fzf then + opts.__fn_pre_fzf(opts) + end + if opts._fn_pre_fzf then + opts._fn_pre_fzf(opts) + end + if opts.fn_pre_fzf then + opts.fn_pre_fzf(opts) + end fzf_win:attach_previewer(previewer) local fzf_bufnr = fzf_win:create() @@ -430,16 +444,15 @@ M.fzf = function(contents, opts) -- convert "exec_silent" actions to fzf's `execute-silent` binds opts = M.convert_reload_actions(opts.__reload_cmd or contents, opts) opts = M.convert_exec_silent_actions(opts) - local selected, exit_code = fzf.raw_fzf(contents, M.build_fzf_cli(opts, fzf_win), - { - fzf_bin = opts.fzf_bin, - cwd = opts.cwd, - pipe_cmd = opts.pipe_cmd, - silent_fail = opts.silent_fail, - is_fzf_tmux = opts._is_fzf_tmux, - debug = opts.debug == true or opts.debug == "verbose", - RIPGREP_CONFIG_PATH = opts.RIPGREP_CONFIG_PATH, - }) + local selected, exit_code = fzf.raw_fzf(contents, M.build_fzf_cli(opts, fzf_win), { + fzf_bin = opts.fzf_bin, + cwd = opts.cwd, + pipe_cmd = opts.pipe_cmd, + silent_fail = opts.silent_fail, + is_fzf_tmux = opts._is_fzf_tmux, + debug = opts.debug == true or opts.debug == "verbose", + RIPGREP_CONFIG_PATH = opts.RIPGREP_CONFIG_PATH, + }) -- kill fzf piped process PID -- NOTE: might be an overkill since we're using $FZF_DEFAULT_COMMAND -- to spawn the piped process and fzf is responsible for termination @@ -448,7 +461,9 @@ M.fzf = function(contents, opts) libuv.process_kill(opts.__pid) end -- If a hidden process was killed by [re-]starting a new picker do nothing - if fzf_win:was_hidden() then return end + if fzf_win:was_hidden() then + return + end -- This was added by 'resume': when '--print-query' is specified -- we are guaranteed to have the query in the first line, save&remove it if selected and #selected > 0 then @@ -461,9 +476,15 @@ M.fzf = function(contents, opts) end table.remove(selected, 1) end - if opts.__fn_post_fzf then opts.__fn_post_fzf(opts, selected) end - if opts._fn_post_fzf then opts._fn_post_fzf(opts, selected) end - if opts.fn_post_fzf then opts.fn_post_fzf(opts, selected) end + if opts.__fn_post_fzf then + opts.__fn_post_fzf(opts, selected) + end + if opts._fn_post_fzf then + opts._fn_post_fzf(opts, selected) + end + if opts.fn_post_fzf then + opts.fn_post_fzf(opts, selected) + end fzf_win:check_exit_status(exit_code, fzf_bufnr) -- retrieve the future action and check: -- * if it's a single function we can close the window @@ -473,7 +494,7 @@ M.fzf = function(contents, opts) -- only close the window if autoclose wasn't specified or is 'true' -- or if the action wasn't a table or defined with `reload|noclose` local do_not_close = type(action) == "table" - and (action[1] ~= nil or action.reload or action.noclose or action.reuse) + and (action[1] ~= nil or action.reload or action.noclose or action.reuse) if (not fzf_win:autoclose() == false) and not do_not_close then fzf_win:close(fzf_bufnr) -- only clear context if we didn't open a new interface, for example, opening @@ -488,23 +509,27 @@ 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", + 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", + thicc = "border-bold", + thiccc = "border-block", + thicccc = "border-block", } local border = winopts.border - if not border then border = "none" end - if border == true then border = "border" end + if not border then + border = "none" + end + if border == true then + border = "border" + end if type(border) == "function" then border = border(winopts, metadata) end @@ -516,22 +541,26 @@ end ---@return string M.preview_window = function(o, fzf_win) local layout - local prefix = string.format("%s:%s%s", + local prefix = string.format( + "%s:%s%s", o.winopts.preview.hidden and "hidden" or "nohidden", o.winopts.preview.wrap and "wrap" or "nowrap", (function() local border = (function() local preview_str = fzf_win:fzf_preview_layout_str() local preview_pos = preview_str:match("[^:]+") or "right" - return translate_border(o.winopts.preview, - { type = "fzf", name = "prev", layout = preview_pos }) + 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 + if + utils.has(o, "fzf", { 0, 31 }) + and o.winopts.preview.layout == "flex" + and tonumber(o.winopts.preview.flip_columns) > 0 then -- Fzf's alternate layout calculates the available preview width in a horizontal split -- (left/right), for the "<%d" condition to trigger the width should be test against a @@ -544,9 +573,14 @@ M.preview_window = function(o, fzf_win) local fzf_main_width = math.ceil(columns * (100 - fzf_prev_percent) / 100) local horizontal_min_width = o.winopts.preview.flip_columns - fzf_main_width + 1 if horizontal_min_width > 0 then - layout = string.format("%s:%s,<%d(%s:%s)", - prefix, o.winopts.preview.horizontal, horizontal_min_width, - prefix, o.winopts.preview.vertical) + layout = string.format( + "%s:%s,<%d(%s:%s)", + prefix, + o.winopts.preview.horizontal, + horizontal_min_width, + prefix, + o.winopts.preview.vertical + ) end end if not layout then @@ -557,7 +591,9 @@ end -- Create fzf --color arguments from a table of vim highlight groups. M.create_fzf_colors = function(opts) - if type(opts.fzf_colors) ~= "table" then return end + if type(opts.fzf_colors) ~= "table" then + return + end local colors = opts.fzf_colors if opts.fn_reload then @@ -616,7 +652,9 @@ end M.create_fzf_binds = function(opts) local binds = opts.keymap.fzf - if not binds or utils.tbl_isempty(binds) then return {} end + if not binds or utils.tbl_isempty(binds) then + return {} + end local combine, separate = {}, {} local dedup = {} for k, v in pairs(binds) do @@ -638,9 +676,10 @@ M.create_fzf_binds = function(opts) -- Since we no longer use `--expect` any bind that contains `accept` -- should be assumed to "accept" the default action, using `--expect` -- that meant printing an empty string for the default enter key - if utils.has(opts, "fzf", { 0, 53 }) - and action:match("accept%s-$") - and not action:match("print(.-)%+accept") + if + utils.has(opts, "fzf", { 0, 53 }) + and action:match("accept%s-$") + and not action:match("print(.-)%+accept") then action = action:gsub("accept%s-$", "print(enter)+accept") end @@ -648,13 +687,14 @@ M.create_fzf_binds = function(opts) -- Separate "transform|execute|execute-silent" binds to their own `--bind` argument, this -- way we can use `transform:...` and not be forced to use brackets, i.e. `transform(...)` -- this enables us to use brackets in the inner actions, e.g. "zero:transform:rebind(...)" - if action:match("transform") - or action:match("execute") - or action:match("reload") - or key == "zero" - or key == "load" - or key == "start" - or key == "resize" + if + action:match("transform") + or action:match("execute") + or action:match("reload") + or key == "zero" + or key == "load" + or key == "start" + or key == "resize" then table.insert(separate, bind) else @@ -691,8 +731,8 @@ M.build_fzf_cli = function(opts, fzf_win) field_index = "{}", }) if preview_spec.type == "cmd" then - preview_cmd = shell.raw_preview_action_cmd( - preview_spec.fn, preview_spec.field_index, opts.debug) + preview_cmd = + shell.raw_preview_action_cmd(preview_spec.fn, preview_spec.field_index, opts.debug) else preview_cmd = shell.raw_action(preview_spec.fn, preview_spec.field_index, opts.debug) end @@ -721,8 +761,9 @@ M.build_fzf_cli = function(opts, fzf_win) opts.fzf_opts["--preview-window"] = M.preview_window(opts, fzf_win) end if opts.fzf_opts["--preview-window"] and opts.preview_offset and #opts.preview_offset > 0 then - opts.fzf_opts["--preview-window"] = - opts.fzf_opts["--preview-window"] .. ":" .. opts.preview_offset + opts.fzf_opts["--preview-window"] = opts.fzf_opts["--preview-window"] + .. ":" + .. opts.preview_offset end -- build the cli args local cli_args = {} @@ -745,7 +786,9 @@ M.build_fzf_cli = function(opts, fzf_win) for _, v in ipairs(type(t) == "table" and t or { t }) do (function() -- flag can be set to `false` to negate a default - if not v then return end + if not v then + return + end local opt_v if type(v) == "string" or type(v) == "number" then v = tostring(v) -- convert number type to string @@ -758,8 +801,14 @@ M.build_fzf_cli = function(opts, fzf_win) v = [["]] .. v:sub(2, #v - 1) .. [["]] end if libuv.is_escaped(v) then - utils.warn(string.format("`fzf_opts` are automatically shellescaped." - .. " Please remove surrounding quotes from %s=%s", k, v)) + utils.warn( + string.format( + "`fzf_opts` are automatically shellescaped." + .. " Please remove surrounding quotes from %s=%s", + k, + v + ) + ) end opt_v = libuv.is_escaped(v) and v or libuv.shellescape(v) end @@ -772,7 +821,9 @@ M.build_fzf_cli = function(opts, fzf_win) table.insert(cli_args, not opt_v and k or string.format("%s=%s", k, opt_v)) else table.insert(cli_args, k) - if opt_v then table.insert(cli_args, opt_v) end + if opt_v then + table.insert(cli_args, opt_v) + end end end)() end @@ -846,26 +897,25 @@ M.mt_cmd_wrapper = function(opts) ---@param obj table|string ---@return string local serialize = function(obj) - local str = type(obj) == "table" - and serpent.line(obj, { comment = false, sortkeys = false }) - or tostring(obj) + local str = type(obj) == "table" and serpent.line(obj, { comment = false, sortkeys = false }) + or tostring(obj) if opts._base64 ~= false then -- by default, base64 encode all arguments return "[==[" .. base64.encode(str) .. "]==]" else -- if not encoding, don't string wrap the table - return type(obj) == "table" and str - or "[==[" .. str .. "]==]" + return type(obj) == "table" and str or "[==[" .. str .. "]==]" end end - if not opts.requires_processing - and not opts.git_icons - and not opts.file_icons - and not opts.file_ignore_patterns - and not opts.path_shorten - and not opts.formatter - and not opts.multiline + if + not opts.requires_processing + and not opts.git_icons + and not opts.file_icons + and not opts.file_ignore_patterns + and not opts.path_shorten + and not opts.formatter + and not opts.multiline then -- command does not require any processing, we also reset `argv_expr` -- to keep `setup_fzf_interactive_flags::no_query_condi` in the command @@ -901,19 +951,14 @@ M.mt_cmd_wrapper = function(opts) assert(not opts.__mt_transform or type(opts.__mt_transform) == "function") assert(not opts.__mt_preprocess or type(opts.__mt_preprocess) == "function") assert(not opts.__mt_postprocess or type(opts.__mt_postprocess) == "function") - return libuv.spawn_nvim_fzf_cmd(opts, - function(x) - return opts.__mt_transform - and opts.__mt_transform(x, opts) - or make_entry.file(x, opts) - end, - function(o) - -- setup opts.cwd and git diff files - return opts.__mt_preprocess - and opts.__mt_preprocess(o) - or make_entry.preprocess(o) - end, - opts.__mt_postprocess and function(o) return opts.__mt_postprocess(o) end or nil) + return libuv.spawn_nvim_fzf_cmd(opts, function(x) + return opts.__mt_transform and opts.__mt_transform(x, opts) or make_entry.file(x, opts) + end, function(o) + -- setup opts.cwd and git diff files + return opts.__mt_preprocess and opts.__mt_preprocess(o) or make_entry.preprocess(o) + end, opts.__mt_postprocess and function(o) + return opts.__mt_postprocess(o) + end or nil) end end @@ -938,17 +983,23 @@ end M.set_title_flags = function(opts, titles) -- NOTE: we only support cmd titles ATM - if not vim.tbl_contains(titles or {}, "cmd") then return opts end - if opts.winopts.title_flags == false then return opts end + if not vim.tbl_contains(titles or {}, "cmd") then + return opts + end + if opts.winopts.title_flags == false then + return opts + end local cmd = type(opts.cmd) == "string" and opts.cmd - or type(opts.fn_reload) == "string" and opts.fn_reload - or nil - if not cmd then return opts end + or type(opts.fn_reload) == "string" and opts.fn_reload + or nil + if not cmd then + return opts + end local flags = {} local patterns = { - { { utils.lua_regex_escape(opts.toggle_hidden_flag) or "%-%-hidden" }, "h" }, + { { utils.lua_regex_escape(opts.toggle_hidden_flag) or "%-%-hidden" }, "h" }, { { utils.lua_regex_escape(opts.toggle_ignore_flag) or "%-%-no%-ignore" }, "i" }, - { { utils.lua_regex_escape(opts.toggle_follow_flag) or "%-L" }, "f" }, + { { utils.lua_regex_escape(opts.toggle_follow_flag) or "%-L" }, "f" }, } for _, def in ipairs(patterns) do for _, p in ipairs(def[1]) do @@ -990,11 +1041,15 @@ M.set_header = function(opts, hdr_tbl) return path.HOME_to_tilde(cwd) end - if not opts then opts = {} end + if not opts then + opts = {} + end if opts.cwd_prompt then opts.prompt = normalize_cwd(opts.cwd or uv.cwd()) - if tonumber(opts.cwd_prompt_shorten_len) and - #opts.prompt >= tonumber(opts.cwd_prompt_shorten_len) then + if + tonumber(opts.cwd_prompt_shorten_len) + and #opts.prompt >= tonumber(opts.cwd_prompt_shorten_len) + then opts.prompt = path.shorten(opts.prompt, tonumber(opts.cwd_prompt_shorten_val) or 1) end opts.prompt = path.add_trailing(opts.prompt) @@ -1013,14 +1068,15 @@ M.set_header = function(opts, hdr_tbl) val = function() -- do not display header when we're inside our -- cwd unless the caller specifically requested - if opts.cwd_header == false or - opts.cwd_prompt and opts.cwd_header == nil or - opts.cwd_header == nil and - (not opts.cwd or path.equals(opts.cwd, uv.cwd())) then + if + opts.cwd_header == false + or opts.cwd_prompt and opts.cwd_header == nil + or opts.cwd_header == nil and (not opts.cwd or path.equals(opts.cwd, uv.cwd())) + then return end return normalize_cwd(opts.cwd or uv.cwd()) - end + end, }, search = { hdr_txt_opt = "grep_header_txt", @@ -1046,9 +1102,11 @@ M.set_header = function(opts, hdr_tbl) if type(opts.regex_filter) == "string" then return opts.regex_filter elseif type(opts.regex_filter) == "table" and type(opts.regex_filter[1]) == "string" then - return string.format("%s%s", + return string.format( + "%s%s", opts.regex_filter.exclude and "not " or "", - opts.regex_filter[1]) + opts.regex_filter[1] + ) elseif type(opts.regex_filter) == "function" then return "" end @@ -1058,7 +1116,9 @@ M.set_header = function(opts, hdr_tbl) hdr_txt_opt = "interactive_header_txt", hdr_txt_str = "", val = function(o) - if opts.no_header_i then return end + if opts.no_header_i then + return + end local defs = M.ACTION_DEFINITIONS local ret = {} local sorted = vim.tbl_keys(opts.actions or {}) @@ -1067,7 +1127,9 @@ M.set_header = function(opts, hdr_tbl) (function() local v = opts.actions[k] local action = type(v) == "function" and v or type(v) == "table" and (v.fn or v[1]) - if type(v) == "table" and v.header == false then return end + if type(v) == "table" and v.header == false then + return + end local def, to = nil, type(v) == "table" and v.header if not to and type(action) == "function" and defs[action] then def = defs[action] @@ -1077,22 +1139,29 @@ M.set_header = function(opts, hdr_tbl) if type(to) == "function" then to = to(o) end - table.insert(ret, def and def.pos or #ret + 1, - string.format("<%s> to %s", + table.insert( + ret, + def and def.pos or #ret + 1, + string.format( + "<%s> to %s", utils.ansi_from_hl(opts.hls.header_bind, k), - utils.ansi_from_hl(opts.hls.header_text, tostring(to)))) + utils.ansi_from_hl(opts.hls.header_text, tostring(to)) + ) + ) end end)() end -- table.concat fails if the table indexes aren't consecutive - return not utils.tbl_isempty(ret) and (function() - local t = {} - for _, i in pairs(ret) do - table.insert(t, i) - end - t[1] = (opts.header_prefix or ":: ") .. t[1] - return table.concat(t, opts.header_separator or "|") - end)() or nil + return not utils.tbl_isempty(ret) + and (function() + local t = {} + for _, i in pairs(ret) do + table.insert(t, i) + end + t[1] = (opts.header_prefix or ":: ") .. t[1] + return table.concat(t, opts.header_separator or "|") + end)() + or nil end, }, } @@ -1117,9 +1186,11 @@ M.set_header = function(opts, hdr_tbl) local txt = def.val(opts) if def and txt then hdr_str = not hdr_str and "" or (hdr_str .. ", ") - hdr_str = ("%s%s%s"):format(hdr_str, def.hdr_txt_str, - not def.hdr_txt_col and txt or - utils.ansi_from_hl(def.hdr_txt_col, txt)) + hdr_str = ("%s%s%s"):format( + hdr_str, + def.hdr_txt_str, + not def.hdr_txt_col and txt or utils.ansi_from_hl(def.hdr_txt_col, txt) + ) end end if hdr_str and #hdr_str > 0 then @@ -1128,7 +1199,6 @@ M.set_header = function(opts, hdr_tbl) return opts end - -- Use both {q} and {+} as field indexes so we can update last query when -- executing the action, without this we lose the last query on "hide" as -- the process never terminates and `--print-query` isn't being printed @@ -1178,9 +1248,11 @@ M.convert_reload_actions = function(reload_cmd, opts) -- Does not work with fzf version < 0.36, fzf fails with -- "error 2: bind action not specified:" (#735) -- Not yet supported with skim - if not utils.has(opts, "fzf", { 0, 36 }) - or utils.has(opts, "sk") - or type(reload_cmd) ~= "string" then + if + not utils.has(opts, "fzf", { 0, 36 }) + or utils.has(opts, "sk") + or type(reload_cmd) ~= "string" + then fallback = true end -- Two types of action as table: @@ -1198,8 +1270,12 @@ M.convert_reload_actions = function(reload_cmd, opts) if fallback then opts.actions[k] = { v.fn, actions.resume } end - elseif not fallback and type(v) == "table" - and type(v[1]) == "function" and v[2] == actions.resume then + elseif + not fallback + and type(v) == "table" + and type(v[1]) == "function" + and v[2] == actions.resume + then -- backward compat: we can use the `reload` event but action -- definition is still using the old style using `actions.resume` -- convert to the new style using { fn = , reload = true } @@ -1209,7 +1285,8 @@ M.convert_reload_actions = function(reload_cmd, opts) end if opts.silent ~= true and has_reload and reload_cmd and type(reload_cmd) ~= "string" then utils.warn( - "actions with `reload` are only supported with string commands, using resume fallback") + "actions with `reload` are only supported with string commands, using resume fallback" + ) end if fallback then -- for fallback, conversion to "old-style" actions is sufficient @@ -1223,10 +1300,15 @@ M.convert_reload_actions = function(reload_cmd, opts) end end local bind_concat = function(tbl, act) - if #tbl == 0 then return nil end - return table.concat(vim.tbl_map(function(x) - return string.format("%s(%s)", act, x) - end, tbl), "+") + if #tbl == 0 then + return nil + end + return table.concat( + vim.tbl_map(function(x) + return string.format("%s(%s)", act, x) + end, tbl), + "+" + ) end local unbind = bind_concat(reload_binds, "unbind") local rebind = bind_concat(reload_binds, "rebind") @@ -1242,13 +1324,15 @@ M.convert_reload_actions = function(reload_cmd, opts) v.postfix = "+" .. v.postfix end opts.keymap.fzf[k] = { - string.format("%s%sexecute-silent(%s)+reload(%s)%s", + string.format( + "%s%sexecute-silent(%s)+reload(%s)%s", type(v.prefix) == "string" and v.prefix or "", unbind and (unbind .. "+") or "", shell_action, reload_cmd, - type(v.postfix) == "string" and v.postfix or ""), - desc = v.desc or config.get_action_helpstr(v.fn) + type(v.postfix) == "string" and v.postfix or "" + ), + desc = v.desc or config.get_action_helpstr(v.fn), } end end @@ -1256,8 +1340,8 @@ M.convert_reload_actions = function(reload_cmd, opts) -- NOTE: this fixes existence of both load as function and rebind, e.g. git_status with: -- setup({ keymap = { fzf = { true, load = function() _G._fzf_load_called = true end } } } if type(opts.keymap.fzf.load) == "function" then - opts.keymap.fzf.load = "execute-silent:" .. - shell.raw_action(opts.keymap.fzf.load, nil, opts.debug) + opts.keymap.fzf.load = "execute-silent:" + .. shell.raw_action(opts.keymap.fzf.load, nil, opts.debug) end if rebind and type(opts.keymap.fzf.load) == "string" then return string.format("%s+%s", rebind, opts.keymap.fzf.load) @@ -1303,15 +1387,18 @@ M.convert_exec_silent_actions = function(opts) -- local has_fzf036 = utils.has(opts, "fzf", { 0, 36 }) opts.keymap.fzf[k] = { - string.format("%sexecute-silent%s%s", + string.format( + "%sexecute-silent%s%s", type(v.prefix) == "string" and v.prefix or "", -- prefer "execute-silent:..." unless we have postfix - has_fzf036 and type(v.postfix) == "string" - and string.format("(%s)", shell_action) - or string.format(":%s", shell_action), + has_fzf036 + and type(v.postfix) == "string" and string.format("(%s)", shell_action) + or string.format(":%s", shell_action), -- can't use postfix since we use "execute-silent:..." - has_fzf036 and type(v.postfix) == "string" and v.postfix or ""), - desc = v.desc or config.get_action_helpstr(v.fn) + has_fzf036 + and type(v.postfix) == "string" and v.postfix or "" + ), + desc = v.desc or config.get_action_helpstr(v.fn), } end end @@ -1343,8 +1430,8 @@ M.setup_fzf_interactive_flags = function(command, fzf_field_expression, opts) -- to fail on spaces, comma and semicolon (and perhaps other use cases), -- moving the test to our cmd wrapper solves it for anything but "native" local no_query_condi = (opts.exec_empty_query or opts.argv_expr) and "" - or string.format( - utils._if_win( + or string.format( + utils._if_win( -- due to the reload command already being shellescaped and fzf's {q} -- also escaping the query with ^""^ any spaces in the query -- will fail the command, by adding caret escaping before fzf's @@ -1356,11 +1443,12 @@ M.setup_fzf_interactive_flags = function(command, fzf_field_expression, opts) -- TODO: open an upstream bug rgd ! as without the double escape -- if an ! is found in the command (i.e. -g "rg ... -g !.git") -- sending a caret will require doubling (i.e. sending ^^ for ^) - utils.has(opts, "fzf", { 0, 51 }) and [[IF %s NEQ ^"^" ]] or [[IF ^%s NEQ ^^"^" ]], - "[ -z %s ] || "), - -- {q} for fzf is automatically shell escaped - fzf_field_expression - ) + utils.has(opts, "fzf", { 0, 51 }) and [[IF %s NEQ ^"^" ]] or [[IF ^%s NEQ ^^"^" ]], + "[ -z %s ] || " + ), + -- {q} for fzf is automatically shell escaped + fzf_field_expression + ) if opts._is_skim then -- skim interactive mode does not need a piped command @@ -1385,8 +1473,8 @@ M.setup_fzf_interactive_flags = function(command, fzf_field_expression, opts) opts.fzf_opts["--query"] = nil opts.query = nil -- setup as interactive - opts._fzf_cli_args = string.format("--interactive --cmd %s", - libuv.shellescape(no_query_condi .. reload_command)) + opts._fzf_cli_args = + string.format("--interactive --cmd %s", libuv.shellescape(no_query_condi .. reload_command)) else -- **send an empty table to avoid running $FZF_DEFAULT_COMMAND -- The above seems to create a hang in some systems @@ -1394,7 +1482,7 @@ M.setup_fzf_interactive_flags = function(command, fzf_field_expression, opts) opts.__fzf_init_cmd = utils.shell_nop() if opts.exec_empty_query or (opts.query and #opts.query > 0) then local q = not utils.__IS_WINDOWS and opts.query - or libuv.escape_fzf(opts.query, utils.has(opts, "fzf", { 0, 52 }) and 0.52 or 0) + or libuv.escape_fzf(opts.query, utils.has(opts, "fzf", { 0, 52 }) and 0.52 or 0) -- gsub doesn't like single % on rhs local escaped_q = libuv.shellescape(q):gsub("%%", "%%%%") opts.__fzf_init_cmd = initial_command:gsub(fzf_field_expression, escaped_q) @@ -1405,8 +1493,10 @@ M.setup_fzf_interactive_flags = function(command, fzf_field_expression, opts) if opts.silent_fail ~= false then reload_command = reload_command .. " || " .. utils.shell_nop() end - opts._fzf_cli_args = string.format("--bind=%s", libuv.shellescape( - string.format("change:reload:%s%s", no_query_condi, reload_command))) + opts._fzf_cli_args = string.format( + "--bind=%s", + libuv.shellescape(string.format("change:reload:%s%s", no_query_condi, reload_command)) + ) end return opts diff --git a/lua/fzf-lua/defaults.lua b/lua/fzf-lua/defaults.lua index a1f82fbde..8e145c2e2 100644 --- a/lua/fzf-lua/defaults.lua +++ b/lua/fzf-lua/defaults.lua @@ -1,7 +1,7 @@ -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local actions = require "fzf-lua.actions" -local previewers = require "fzf-lua.previewer" +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local actions = require("fzf-lua.actions") +local previewers = require("fzf-lua.previewer") local M = {} function M._default_previewer_fn() @@ -20,69 +20,69 @@ function M._default_previewer_fn() end function M._preview_pager_fn() - return vim.fn.executable("delta") == 1 and ("delta --width=$COLUMNS --%s"):format(vim.o.bg) or - nil + return vim.fn.executable("delta") == 1 and ("delta --width=$COLUMNS --%s"):format(vim.o.bg) or nil end function M._man_cmd_fn(bat_pager) local cmd = utils.is_darwin() and "man -P cat" - or vim.fn.executable("mandb") == 1 and "man" - or "man -c" - local bat_cmd = bat_pager and (function() - for _, bin in ipairs({ "batcat", "bat" }) do - if vim.fn.executable(bin) == 1 then - return string.format("%s --color=always -p -l man", bin) + or vim.fn.executable("mandb") == 1 and "man" + or "man -c" + local bat_cmd = bat_pager + and (function() + for _, bin in ipairs({ "batcat", "bat" }) do + if vim.fn.executable(bin) == 1 then + return string.format("%s --color=always -p -l man", bin) + end end - end - end)() + end)() local pager = bat_cmd or "col -bx" return string.format("%s %%s 2>/dev/null | %s", cmd, pager) end -M.defaults = { - nbsp = utils.nbsp, - winopts = { - height = 0.85, - width = 0.80, - row = 0.35, - col = 0.55, - border = "rounded", - zindex = 50, - backdrop = 60, +M.defaults = { + nbsp = utils.nbsp, + winopts = { + height = 0.85, + width = 0.80, + row = 0.35, + col = 0.55, + border = "rounded", + zindex = 50, + backdrop = 60, fullscreen = false, - title_pos = "center", + title_pos = "center", treesitter = { - enabled = utils.__HAS_NVIM_010, - fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" } + enabled = utils.__HAS_NVIM_010, + fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" }, }, - preview = { - default = "builtin", - border = "rounded", - wrap = false, - hidden = false, - vertical = "down:45%", - horizontal = "right:60%", - layout = "flex", + preview = { + default = "builtin", + border = "rounded", + wrap = false, + hidden = false, + vertical = "down:45%", + horizontal = "right:60%", + layout = "flex", flip_columns = 100, - title = true, - title_pos = "center", - scrollbar = "border", - scrolloff = -1, + title = true, + title_pos = "center", + scrollbar = "border", + scrolloff = -1, -- default preview delay, fzf native previewers has a 100ms delay: -- https://github.com/junegunn/fzf/issues/2417#issuecomment-809886535 - delay = 20, - winopts = { - number = true, + delay = 20, + winopts = { + number = true, relativenumber = false, - cursorline = true, - cursorlineopt = "both", - cursorcolumn = false, - signcolumn = "no", - list = false, - foldenable = false, - foldmethod = "manual", + cursorline = true, + cursorlineopt = "both", + cursorcolumn = false, + signcolumn = "no", + list = false, + foldenable = false, + foldmethod = "manual", -- >0 to prevent scrolling issues (#500) - scrolloff = 1, + scrolloff = 1, }, }, -- on_create = function(_) @@ -90,111 +90,121 @@ M.defaults = { -- utils.keymap_set("t", "", actions.hide, { nowait = true, buffer = e.bufnr }) -- end, }, - keymap = { + keymap = { builtin = { - [""] = "hide", - [""] = "toggle-help", - [""] = "toggle-fullscreen", + [""] = "hide", + [""] = "toggle-help", + [""] = "toggle-fullscreen", -- Only valid with the 'builtin' previewer - [""] = "toggle-preview-wrap", - [""] = "toggle-preview", - [""] = "toggle-preview-ccw", - [""] = "toggle-preview-cw", - [""] = "toggle-preview-ts-ctx", - [""] = "preview-ts-ctx-dec", - [""] = "preview-ts-ctx-inc", - [""] = "preview-reset", - [""] = "preview-page-down", - [""] = "preview-page-up", + [""] = "toggle-preview-wrap", + [""] = "toggle-preview", + [""] = "toggle-preview-ccw", + [""] = "toggle-preview-cw", + [""] = "toggle-preview-ts-ctx", + [""] = "preview-ts-ctx-dec", + [""] = "preview-ts-ctx-inc", + [""] = "preview-reset", + [""] = "preview-page-down", + [""] = "preview-page-up", [""] = "preview-down", - [""] = "preview-up", + [""] = "preview-up", }, fzf = { - ["ctrl-z"] = "abort", - ["ctrl-u"] = "unix-line-discard", - ["ctrl-f"] = "half-page-down", - ["ctrl-b"] = "half-page-up", - ["ctrl-a"] = "beginning-of-line", - ["ctrl-e"] = "end-of-line", - ["alt-a"] = "toggle-all", - ["alt-g"] = "first", - ["alt-G"] = "last", + ["ctrl-z"] = "abort", + ["ctrl-u"] = "unix-line-discard", + ["ctrl-f"] = "half-page-down", + ["ctrl-b"] = "half-page-up", + ["ctrl-a"] = "beginning-of-line", + ["ctrl-e"] = "end-of-line", + ["alt-a"] = "toggle-all", + ["alt-g"] = "first", + ["alt-G"] = "last", -- Only valid with fzf previewers (bat/cat/git/etc) - ["f3"] = "toggle-preview-wrap", - ["f4"] = "toggle-preview", - ["shift-down"] = "preview-page-down", - ["shift-up"] = "preview-page-up", + ["f3"] = "toggle-preview-wrap", + ["f4"] = "toggle-preview", + ["shift-down"] = "preview-page-down", + ["shift-up"] = "preview-page-up", ["alt-shift-down"] = "preview-down", - ["alt-shift-up"] = "preview-up", + ["alt-shift-up"] = "preview-up", }, }, - actions = { + actions = { files = { - ["enter"] = actions.file_edit_or_qf, + ["enter"] = actions.file_edit_or_qf, ["ctrl-s"] = actions.file_split, ["ctrl-v"] = actions.file_vsplit, ["ctrl-t"] = actions.file_tabedit, - ["alt-q"] = actions.file_sel_to_qf, - ["alt-Q"] = actions.file_sel_to_ll, - ["alt-i"] = { fn = actions.toggle_ignore, reuse = true, header = false }, - ["alt-h"] = { fn = actions.toggle_hidden, reuse = true, header = false }, - ["alt-f"] = { fn = actions.toggle_follow, reuse = true, header = false }, + ["alt-q"] = actions.file_sel_to_qf, + ["alt-Q"] = actions.file_sel_to_ll, + ["alt-i"] = { fn = actions.toggle_ignore, reuse = true, header = false }, + ["alt-h"] = { fn = actions.toggle_hidden, reuse = true, header = false }, + ["alt-f"] = { fn = actions.toggle_follow, reuse = true, header = false }, }, }, - fzf_bin = nil, - fzf_opts = { - ["--ansi"] = true, - ["--info"] = "inline-right", - ["--height"] = "100%", - ["--layout"] = "reverse", - ["--border"] = "none", + fzf_bin = nil, + fzf_opts = { + ["--ansi"] = true, + ["--info"] = "inline-right", + ["--height"] = "100%", + ["--layout"] = "reverse", + ["--border"] = "none", ["--highlight-line"] = true, }, fzf_tmux_opts = { ["-p"] = "80%,80%", ["--margin"] = "0,0" }, - previewers = { + previewers = { cat = { - cmd = "cat", - args = "-n", + cmd = "cat", + args = "-n", _ctor = previewers.fzf.cmd, }, bat = { -- reduce startup time by deferring executable check to previewer constructor (#970) - cmd = function() return vim.fn.executable("batcat") == 1 and "batcat" or "bat" end, + cmd = function() + return vim.fn.executable("batcat") == 1 and "batcat" or "bat" + end, -- args = "--color=always --style=default", - args = "--color=always --style=numbers,changes", + args = "--color=always --style=numbers,changes", _ctor = previewers.fzf.bat_async, }, bat_native = { - cmd = function() return vim.fn.executable("batcat") == 1 and "batcat" or "bat" end, - args = "--color=always --style=numbers,changes", + cmd = function() + return vim.fn.executable("batcat") == 1 and "batcat" or "bat" + end, + args = "--color=always --style=numbers,changes", -- NOTE: no support for `bat_native` on Windows, it's a hassle for no real -- benefit, native previewers will be removed from the code at one point _ctor = utils._if_win(previewers.fzf.bat_async, previewers.fzf.bat), }, head = { - cmd = "head", - args = nil, + cmd = "head", + args = nil, _ctor = previewers.fzf.head, }, git_diff = { - pager = M._preview_pager_fn, - cmd_deleted = "git diff --color HEAD --", - cmd_modified = "git diff --color HEAD", + pager = M._preview_pager_fn, + cmd_deleted = "git diff --color HEAD --", + cmd_modified = "git diff --color HEAD", cmd_untracked = "git diff --color --no-index /dev/null", -- TODO: modify previewer code to accept table cmd -- cmd_deleted = { "git", "diff", "--color", "HEAD", "--" }, -- cmd_modified = { "git", "diff", "--color", "HEAD" }, -- cmd_untracked = { "git", "diff", "--color", "--no-index", "/dev/null" }, - _fn_git_icons = function() return M.globals.git.icons end, - _ctor = previewers.fzf.git_diff, + _fn_git_icons = function() + return M.globals.git.icons + end, + _ctor = previewers.fzf.git_diff, }, man = { _ctor = previewers.builtin.man_pages, - cmd = function() return M._man_cmd_fn() end, + cmd = function() + return M._man_cmd_fn() + end, }, man_native = { _ctor = previewers.fzf.man_pages, - cmd = function() return M._man_cmd_fn(true) end, + cmd = function() + return M._man_cmd_fn(true) + end, }, help_tags = { _ctor = previewers.builtin.help_tags, @@ -203,35 +213,37 @@ M.defaults = { _ctor = previewers.fzf.help_tags, }, builtin = { - syntax = true, - syntax_delay = 0, - syntax_limit_l = 0, - syntax_limit_b = 1024 * 1024, -- 1MB - limit_b = 1024 * 1024 * 10, -- 10MB - treesitter = { + syntax = true, + syntax_delay = 0, + syntax_limit_l = 0, + syntax_limit_b = 1024 * 1024, -- 1MB + limit_b = 1024 * 1024 * 10, -- 10MB + treesitter = { enabled = true, disabled = {}, -- nvim-treesitter-context config options -- https://github.com/nvim-treesitter/nvim-treesitter-context - context = { max_lines = 1, trim_scope = "inner" } + context = { max_lines = 1, trim_scope = "inner" }, }, - ueberzug_scaler = "cover", - title_fnamemodify = function(s) return path.tail(s) end, - render_markdown = { enabled = true, filetypes = { ["markdown"] = true } }, - snacks_image = { enabled = true, render_inline = true }, - _ctor = previewers.builtin.buffer_or_file, + ueberzug_scaler = "cover", + title_fnamemodify = function(s) + return path.tail(s) + end, + render_markdown = { enabled = true, filetypes = { ["markdown"] = true } }, + snacks_image = { enabled = true, render_inline = true }, + _ctor = previewers.builtin.buffer_or_file, }, codeaction = { - _ctor = previewers.builtin.codeaction, + _ctor = previewers.builtin.codeaction, diff_opts = { ctxlen = 3 }, }, codeaction_native = { - _ctor = previewers.fzf.codeaction, + _ctor = previewers.fzf.codeaction, diff_opts = { ctxlen = 3 }, - pager = M._preview_pager_fn, + pager = M._preview_pager_fn, }, }, - formatters = { + formatters = { path = { filename_first = { -- is used as the invisible space between the parent and the file part @@ -300,7 +312,7 @@ M.defaults = { else return s end - end + end, }, dirname_first = { -- Credit fo @folke :-) @@ -329,65 +341,77 @@ M.defaults = { ]]):format(hl_dir or "", hl_file or "") end, }, - } + }, }, } -M.defaults.files = { - previewer = M._default_previewer_fn, - cmd = nil, -- default: auto detect find|fd - multiprocess = true, - file_icons = 1, - color_icons = true, - git_icons = false, - cwd_prompt = true, +M.defaults.files = { + previewer = M._default_previewer_fn, + cmd = nil, -- default: auto detect find|fd + multiprocess = true, + file_icons = 1, + color_icons = true, + git_icons = false, + cwd_prompt = true, cwd_prompt_shorten_len = 32, cwd_prompt_shorten_val = 1, - fzf_opts = { ["--multi"] = true, ["--scheme"] = "path" }, - _fzf_nth_devicons = true, - git_status_cmd = { - "git", "-c", "color.status=false", "--no-optional-locks", "status", "--porcelain=v1" }, - find_opts = [[-type f \! -path '*/.git/*']], - rg_opts = [[--color=never --files -g "!.git"]], - fd_opts = [[--color=never --type f --type l --exclude .git]], - dir_opts = [[/s/b/a:-d]], - hidden = true, - toggle_ignore_flag = "--no-ignore", - toggle_hidden_flag = "--hidden", - toggle_follow_flag = "-L", - _actions = function() return M.globals.actions.files end, - winopts = { preview = { winopts = { cursorline = false } } }, + fzf_opts = { ["--multi"] = true, ["--scheme"] = "path" }, + _fzf_nth_devicons = true, + git_status_cmd = { + "git", + "-c", + "color.status=false", + "--no-optional-locks", + "status", + "--porcelain=v1", + }, + find_opts = [[-type f \! -path '*/.git/*']], + rg_opts = [[--color=never --files -g "!.git"]], + fd_opts = [[--color=never --type f --type l --exclude .git]], + dir_opts = [[/s/b/a:-d]], + hidden = true, + toggle_ignore_flag = "--no-ignore", + toggle_hidden_flag = "--hidden", + toggle_follow_flag = "-L", + _actions = function() + return M.globals.actions.files + end, + winopts = { preview = { winopts = { cursorline = false } } }, } -- Must construct our opts table in stages -- so we can reference 'M.globals.files' -M.defaults.git = { +M.defaults.git = { files = { - previewer = M._default_previewer_fn, - cmd = "git ls-files --exclude-standard", - multiprocess = true, - file_icons = 1, - color_icons = true, - git_icons = true, - fzf_opts = { ["--multi"] = true, ["--scheme"] = "path" }, + previewer = M._default_previewer_fn, + cmd = "git ls-files --exclude-standard", + multiprocess = true, + file_icons = 1, + color_icons = true, + git_icons = true, + fzf_opts = { ["--multi"] = true, ["--scheme"] = "path" }, _fzf_nth_devicons = true, - _actions = function() return M.globals.actions.files end, - winopts = { preview = { winopts = { cursorline = false } } }, + _actions = function() + return M.globals.actions.files + end, + winopts = { preview = { winopts = { cursorline = false } } }, }, status = { -- override `color.status=always`, technically not required -- since we now also call `utils.strip_ansi_coloring` (#706) - cmd = "git -c color.status=false --no-optional-locks status --porcelain=v1 -u", - previewer = "git_diff", - multiprocess = true, - file_icons = 1, - color_icons = true, - fzf_opts = { ["--multi"] = true }, + cmd = "git -c color.status=false --no-optional-locks status --porcelain=v1 -u", + previewer = "git_diff", + multiprocess = true, + file_icons = 1, + color_icons = true, + fzf_opts = { ["--multi"] = true }, _fzf_nth_devicons = true, - _actions = function() return M.globals.actions.files end, - actions = { - ["right"] = { fn = actions.git_unstage, reload = true }, - ["left"] = { fn = actions.git_stage, reload = true }, + _actions = function() + return M.globals.actions.files + end, + actions = { + ["right"] = { fn = actions.git_unstage, reload = true }, + ["left"] = { fn = actions.git_stage, reload = true }, ["ctrl-x"] = { fn = actions.git_reset, reload = true }, -- Uncomment to test stage|unstage and backward compat -- ["ctrl-s"] = { fn = actions.git_stage_unstage, reload = true }, @@ -395,113 +419,119 @@ M.defaults.git = { }, }, diff = { - cmd = "git --no-pager diff --name-only {ref}", - ref = "HEAD", - preview = "git diff {ref} {file}", - preview_pager = M._preview_pager_fn, - multiprocess = true, - file_icons = 1, - color_icons = true, - fzf_opts = { ["--multi"] = true }, + cmd = "git --no-pager diff --name-only {ref}", + ref = "HEAD", + preview = "git diff {ref} {file}", + preview_pager = M._preview_pager_fn, + multiprocess = true, + file_icons = 1, + color_icons = true, + fzf_opts = { ["--multi"] = true }, _fzf_nth_devicons = true, - _actions = function() return M.globals.actions.files end, + _actions = function() + return M.globals.actions.files + end, }, hunks = { - previewer = M._default_previewer_fn, - cmd = "git --no-pager diff --color=always {ref}", - ref = "HEAD", - multiprocess = true, - file_icons = 1, - color_icons = true, - fzf_opts = { + previewer = M._default_previewer_fn, + cmd = "git --no-pager diff --color=always {ref}", + ref = "HEAD", + multiprocess = true, + file_icons = 1, + color_icons = true, + fzf_opts = { ["--multi"] = true, ["--delimiter"] = ":", ["--nth"] = "3..", }, _fzf_nth_devicons = true, - _actions = function() return M.globals.actions.files end, + _actions = function() + return M.globals.actions.files + end, }, commits = { - cmd = [[git log --color --pretty=format:"%C(yellow)%h%Creset ]] - .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset"]], - preview = "git show --color {1}", + cmd = [[git log --color --pretty=format:"%C(yellow)%h%Creset ]] + .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset"]], + preview = "git show --color {1}", preview_pager = M._preview_pager_fn, - actions = { - ["enter"] = actions.git_checkout, + actions = { + ["enter"] = actions.git_checkout, ["ctrl-y"] = { fn = actions.git_yank_commit, exec_silent = true }, }, - fzf_opts = { ["--no-multi"] = true }, - _multiline = false, + fzf_opts = { ["--no-multi"] = true }, + _multiline = false, }, bcommits = { - cmd = [[git log --color --pretty=format:"%C(yellow)%h%Creset ]] - .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset" {file}]], - preview = "git show --color {1} -- {file}", + cmd = [[git log --color --pretty=format:"%C(yellow)%h%Creset ]] + .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset" {file}]], + preview = "git show --color {1} -- {file}", preview_pager = M._preview_pager_fn, - actions = { - ["enter"] = actions.git_buf_edit, + actions = { + ["enter"] = actions.git_buf_edit, ["ctrl-s"] = actions.git_buf_split, ["ctrl-v"] = actions.git_buf_vsplit, ["ctrl-t"] = actions.git_buf_tabedit, ["ctrl-y"] = { fn = actions.git_yank_commit, exec_silent = true }, }, - fzf_opts = { ["--no-multi"] = true }, - _multiline = false, + fzf_opts = { ["--no-multi"] = true }, + _multiline = false, }, blame = { - cmd = [[git blame --color-lines {file}]], - preview = "git show --color {1} -- {file}", + cmd = [[git blame --color-lines {file}]], + preview = "git show --color {1} -- {file}", preview_pager = M._preview_pager_fn, - actions = { - ["enter"] = actions.git_goto_line, + actions = { + ["enter"] = actions.git_goto_line, ["ctrl-s"] = actions.git_buf_split, ["ctrl-v"] = actions.git_buf_vsplit, ["ctrl-t"] = actions.git_buf_tabedit, ["ctrl-y"] = { fn = actions.git_yank_commit, exec_silent = true }, }, - fzf_opts = { ["--no-multi"] = true }, - _multiline = false, + fzf_opts = { ["--no-multi"] = true }, + _multiline = false, -- `winopts.treesitter==true` line match format - _treesitter = function(line) return line:match("(%s+)(%d+)%)(.+)$") end, + _treesitter = function(line) + return line:match("(%s+)(%d+)%)(.+)$") + end, }, branches = { - cmd = "git branch --all --color", - preview = "git log --graph --pretty=oneline --abbrev-commit --color {1}", - remotes = "local", - actions = { - ["enter"] = actions.git_switch, + cmd = "git branch --all --color", + preview = "git log --graph --pretty=oneline --abbrev-commit --color {1}", + remotes = "local", + actions = { + ["enter"] = actions.git_switch, ["ctrl-x"] = { fn = actions.git_branch_del, reload = true }, ["ctrl-a"] = { fn = actions.git_branch_add, field_index = "{q}", reload = true }, }, - cmd_add = { "git", "branch" }, - cmd_del = { "git", "branch", "--delete" }, - fzf_opts = { ["--no-multi"] = true }, + cmd_add = { "git", "branch" }, + cmd_del = { "git", "branch", "--delete" }, + fzf_opts = { ["--no-multi"] = true }, _multiline = false, }, tags = { - cmd = [[git for-each-ref --color --sort="-taggerdate" --format ]] - .. [["%(color:yellow)%(refname:short)%(color:reset) ]] - .. [[%(color:green)(%(taggerdate:relative))%(color:reset)]] - .. [[ %(subject) %(color:blue)%(taggername)%(color:reset)" refs/tags]], - preview = [[git log --graph --color --pretty=format:"%C(yellow)%h%Creset ]] - .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset" {1}]], - actions = { ["enter"] = actions.git_checkout }, - fzf_opts = { ["--no-multi"] = true }, + cmd = [[git for-each-ref --color --sort="-taggerdate" --format ]] + .. [["%(color:yellow)%(refname:short)%(color:reset) ]] + .. [[%(color:green)(%(taggerdate:relative))%(color:reset)]] + .. [[ %(subject) %(color:blue)%(taggername)%(color:reset)" refs/tags]], + preview = [[git log --graph --color --pretty=format:"%C(yellow)%h%Creset ]] + .. [[%Cgreen(%><(12)%cr%><|(12))%Creset %s %C(blue)<%an>%Creset" {1}]], + actions = { ["enter"] = actions.git_checkout }, + fzf_opts = { ["--no-multi"] = true }, _multiline = false, }, stash = { - cmd = "git --no-pager stash list", - preview = "git --no-pager stash show --patch --color {1}", + cmd = "git --no-pager stash list", + preview = "git --no-pager stash show --patch --color {1}", preview_pager = M._preview_pager_fn, - actions = { - ["enter"] = actions.git_stash_apply, + actions = { + ["enter"] = actions.git_stash_apply, ["ctrl-x"] = { fn = actions.git_stash_drop, reload = true }, }, - fzf_opts = { + fzf_opts = { -- TODO: multiselect requires more work as dropping -- a stash changes the stash index, causing an error -- when the next stash is attempted - ["--no-multi"] = true, + ["--no-multi"] = true, ["--delimiter"] = "[:]", }, }, @@ -516,417 +546,449 @@ M.defaults.git = { }, } -M.defaults.grep = { - previewer = M._default_previewer_fn, - input_prompt = "Grep For> ", - cmd = nil, -- default: auto detect rg|grep - multiprocess = true, - file_icons = 1, - color_icons = true, - git_icons = false, - fzf_opts = { ["--multi"] = true }, - grep_opts = utils.is_darwin() - and "--binary-files=without-match --line-number --recursive --color=always " - .. "--extended-regexp -e" - or "--binary-files=without-match --line-number --recursive --color=always " +M.defaults.grep = { + previewer = M._default_previewer_fn, + input_prompt = "Grep For> ", + cmd = nil, -- default: auto detect rg|grep + multiprocess = true, + file_icons = 1, + color_icons = true, + git_icons = false, + fzf_opts = { ["--multi"] = true }, + grep_opts = utils.is_darwin() + and "--binary-files=without-match --line-number --recursive --color=always " .. "--extended-regexp -e" + or "--binary-files=without-match --line-number --recursive --color=always " .. "--perl-regexp -e", - rg_opts = "--column --line-number --no-heading --color=always --smart-case " - .. "--max-columns=4096 -e", - rg_glob = 1, -- do not display warning if using `grep` - _actions = function() return M.globals.actions.files end, - actions = { ["ctrl-g"] = { actions.grep_lgrep } }, + rg_opts = "--column --line-number --no-heading --color=always --smart-case " + .. "--max-columns=4096 -e", + rg_glob = 1, -- do not display warning if using `grep` + _actions = function() + return M.globals.actions.files + end, + actions = { ["ctrl-g"] = { actions.grep_lgrep } }, -- live_grep_glob options - glob_flag = "--iglob", -- for case sensitive globs use '--glob' - glob_separator = "%s%-%-", -- query separator pattern (lua): ' --' - _treesitter = true, + 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, { - rg_glob = false, -- meaningless for single file rg - exec_empty_query = true, -- makes sense to display lines immediately - fzf_opts = { +M.defaults.grep_curbuf = vim.tbl_deep_extend("force", M.defaults.grep, { + 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..", + ["--with-nth"] = "2..", + ["--nth"] = "2..", }, }) -M.defaults.args = { - previewer = M._default_previewer_fn, - files_only = true, - file_icons = 1, - color_icons = true, - git_icons = false, - fzf_opts = { ["--multi"] = true, ["--scheme"] = "path" }, +M.defaults.args = { + previewer = M._default_previewer_fn, + files_only = true, + file_icons = 1, + color_icons = true, + git_icons = false, + fzf_opts = { ["--multi"] = true, ["--scheme"] = "path" }, _fzf_nth_devicons = true, - _actions = function() return M.globals.actions.files end, - actions = { ["ctrl-x"] = { fn = actions.arg_del, reload = true } }, + _actions = function() + return M.globals.actions.files + end, + actions = { ["ctrl-x"] = { fn = actions.arg_del, reload = true } }, } -M.defaults.oldfiles = { - previewer = M._default_previewer_fn, - file_icons = 1, - color_icons = true, - git_icons = false, - stat_file = true, - fzf_opts = { ["--tiebreak"] = "index", ["--multi"] = true }, +M.defaults.oldfiles = { + previewer = M._default_previewer_fn, + file_icons = 1, + color_icons = true, + git_icons = false, + stat_file = true, + fzf_opts = { ["--tiebreak"] = "index", ["--multi"] = true }, _fzf_nth_devicons = true, - _actions = function() return M.globals.actions.files end, + _actions = function() + return M.globals.actions.files + end, } -M.defaults.quickfix = { - previewer = M._default_previewer_fn, - separator = "▏", - file_icons = 1, +M.defaults.quickfix = { + previewer = M._default_previewer_fn, + separator = "▏", + file_icons = 1, color_icons = true, - git_icons = false, - only_valid = false, - fzf_opts = { ["--multi"] = true }, - _actions = function() return M.globals.actions.files end, + git_icons = false, + only_valid = false, + fzf_opts = { ["--multi"] = true }, + _actions = function() + return M.globals.actions.files + end, _treesitter = true, _cached_hls = { "path_colnr", "path_linenr" }, } -M.defaults.quickfix_stack = { - marker = ">", - previewer = { _ctor = previewers.builtin.quickfix, }, - fzf_opts = { ["--no-multi"] = true }, - actions = { ["enter"] = actions.set_qflist, }, +M.defaults.quickfix_stack = { + marker = ">", + previewer = { _ctor = previewers.builtin.quickfix }, + fzf_opts = { ["--no-multi"] = true }, + actions = { ["enter"] = actions.set_qflist }, } -M.defaults.loclist = { - previewer = M._default_previewer_fn, - separator = "▏", - file_icons = 1, +M.defaults.loclist = { + previewer = M._default_previewer_fn, + separator = "▏", + file_icons = 1, color_icons = true, - git_icons = false, - only_valid = false, - fzf_opts = { ["--multi"] = true }, - _actions = function() return M.globals.actions.files end, + git_icons = false, + only_valid = false, + fzf_opts = { ["--multi"] = true }, + _actions = function() + return M.globals.actions.files + end, _treesitter = true, _cached_hls = { "path_colnr", "path_linenr" }, } -M.defaults.loclist_stack = { - marker = ">", - previewer = { _ctor = previewers.builtin.quickfix, }, - fzf_opts = { ["--no-multi"] = true }, - actions = { ["enter"] = actions.set_qflist, }, +M.defaults.loclist_stack = { + marker = ">", + previewer = { _ctor = previewers.builtin.quickfix }, + fzf_opts = { ["--no-multi"] = true }, + actions = { ["enter"] = actions.set_qflist }, } -M.defaults.buffers = { - previewer = M._default_previewer_fn, - file_icons = 1, - color_icons = true, - sort_lastused = true, - show_unloaded = true, - show_unlisted = false, +M.defaults.buffers = { + previewer = M._default_previewer_fn, + file_icons = 1, + color_icons = true, + sort_lastused = true, + show_unloaded = true, + show_unlisted = false, ignore_current_buffer = false, - no_action_set_cursor = true, - cwd_only = false, - cwd = nil, - fzf_opts = { ["--tiebreak"] = "index", ["--multi"] = true }, - _actions = function() + no_action_set_cursor = true, + cwd_only = false, + cwd = nil, + fzf_opts = { ["--tiebreak"] = "index", ["--multi"] = true }, + _actions = function() return M.globals.actions.buffers or M.globals.actions.files end, - actions = { ["ctrl-x"] = { fn = actions.buf_del, reload = true } }, - _cached_hls = { "buf_nr", "buf_flag_cur", "buf_flag_alt", "path_linenr" }, + actions = { ["ctrl-x"] = { fn = actions.buf_del, reload = true } }, + _cached_hls = { "buf_nr", "buf_flag_cur", "buf_flag_alt", "path_linenr" }, } -M.defaults.tabs = { - previewer = M._default_previewer_fn, - tab_title = "Tab", - tab_marker = "<<", - locate = true, - file_icons = 1, +M.defaults.tabs = { + previewer = M._default_previewer_fn, + tab_title = "Tab", + tab_marker = "<<", + locate = true, + file_icons = 1, color_icons = true, - _actions = function() + _actions = function() return M.globals.actions.buffers or M.globals.actions.files end, - actions = { - ["enter"] = actions.buf_switch, + actions = { + ["enter"] = actions.buf_switch, ["ctrl-x"] = { fn = actions.buf_del, reload = true }, }, - fzf_opts = { - ["--multi"] = true, + fzf_opts = { + ["--multi"] = true, ["--delimiter"] = "[\\):]", - ["--with-nth"] = "5..", + ["--with-nth"] = "5..", + }, + _cached_hls = { + "buf_nr", + "buf_flag_cur", + "buf_flag_alt", + "tab_title", + "tab_marker", + "path_linenr", }, - _cached_hls = { "buf_nr", "buf_flag_cur", "buf_flag_alt", "tab_title", "tab_marker", "path_linenr" }, } -M.defaults.lines = { - previewer = M._default_previewer_fn, - file_icons = 1, - color_icons = true, - show_bufname = 120, - show_unloaded = true, - show_unlisted = false, - no_term_buffers = true, - sort_lastused = true, - fzf_opts = { - ["--multi"] = true, +M.defaults.lines = { + previewer = M._default_previewer_fn, + file_icons = 1, + color_icons = true, + show_bufname = 120, + show_unloaded = true, + show_unlisted = false, + no_term_buffers = true, + sort_lastused = true, + fzf_opts = { + ["--multi"] = true, ["--delimiter"] = "[\t]", - ["--tabstop"] = "1", - ["--tiebreak"] = "index", - ["--with-nth"] = "2..", - ["--nth"] = "4..", + ["--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 = { + _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, + 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, + 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 + lnum, + text + ) + end, }, - _actions = function() + _actions = function() return M.globals.actions.buffers or M.globals.actions.files end, } -M.defaults.blines = vim.tbl_deep_extend("force", M.defaults.lines, { - show_bufname = false, - show_unloaded = true, - show_unlisted = true, +M.defaults.blines = vim.tbl_deep_extend("force", M.defaults.lines, { + show_bufname = false, + show_unloaded = true, + show_unlisted = true, no_term_buffers = false, - fzf_opts = { + fzf_opts = { ["--with-nth"] = "4..", - ["--nth"] = "2..", + ["--nth"] = "2..", }, }) -M.defaults.treesitter = { - previewer = M._default_previewer_fn, - file_icons = false, - color_icons = false, - fzf_opts = { - ["--multi"] = true, - ["--tabstop"] = "4", +M.defaults.treesitter = { + previewer = M._default_previewer_fn, + file_icons = false, + color_icons = false, + fzf_opts = { + ["--multi"] = true, + ["--tabstop"] = "4", ["--delimiter"] = "[:]", - ["--with-nth"] = "2..", + ["--with-nth"] = "2..", }, line_field_index = "{2}", - _actions = function() + _actions = function() return M.globals.actions.buffers or M.globals.actions.files end, - _cached_hls = { "buf_name", "buf_nr", "buf_linenr", "path_colnr" }, - _fmt = { - to = false, + _cached_hls = { "buf_name", "buf_nr", "buf_linenr", "path_colnr" }, + _fmt = { + to = false, from = function(s, _) return s:gsub("\t\t", ": ") - end + end, }, } -M.defaults.spellcheck = { - previewer = M._default_previewer_fn, - file_icons = false, - color_icons = false, - word_separator = "[%s%p]", - fzf_opts = { - ["--multi"] = true, - ["--tabstop"] = "4", +M.defaults.spellcheck = { + previewer = M._default_previewer_fn, + file_icons = false, + color_icons = false, + word_separator = "[%s%p]", + fzf_opts = { + ["--multi"] = true, + ["--tabstop"] = "4", ["--delimiter"] = "[:]", - ["--with-nth"] = "2..", + ["--with-nth"] = "2..", }, line_field_index = "{2}", - _actions = function() + _actions = function() return M.globals.actions.buffers or M.globals.actions.files end, - actions = { - ["ctrl-s"] = { fn = actions.spell_suggest, header = "spell suggest" } + actions = { + ["ctrl-s"] = { fn = actions.spell_suggest, header = "spell suggest" }, }, - _cached_hls = { "buf_name", "buf_nr", "buf_linenr", "path_colnr" }, - _fmt = { - to = false, + _cached_hls = { "buf_name", "buf_nr", "buf_linenr", "path_colnr" }, + _fmt = { + to = false, from = function(s, _) return s:gsub("\t\t", ": ") - end + end, }, } -M.defaults.tags = { - previewer = { _ctor = previewers.builtin.tags }, +M.defaults.tags = { + previewer = { _ctor = previewers.builtin.tags }, input_prompt = "[tags] Grep For> ", - ctags_file = nil, -- auto-detect - rg_opts = "--no-heading --color=always --smart-case", - grep_opts = "--color=auto --perl-regexp", + ctags_file = nil, -- auto-detect + rg_opts = "--no-heading --color=always --smart-case", + grep_opts = "--color=auto --perl-regexp", multiprocess = true, - file_icons = 1, - git_icons = false, - color_icons = true, - fzf_opts = { - ["--no-multi"] = true, + file_icons = 1, + git_icons = false, + color_icons = true, + fzf_opts = { + ["--no-multi"] = true, ["--delimiter"] = string.format("[:%s]", utils.nbsp), - ["--tiebreak"] = "begin", + ["--tiebreak"] = "begin", }, - _actions = function() return M.globals.actions.files end, - actions = { ["ctrl-g"] = { actions.grep_lgrep } }, - formatter = false, + _actions = function() + return M.globals.actions.files + end, + actions = { ["ctrl-g"] = { actions.grep_lgrep } }, + formatter = false, } -M.defaults.btags = { - previewer = { _ctor = previewers.builtin.tags }, - ctags_file = nil, -- auto-detect - rg_opts = "--color=never --no-heading", - grep_opts = "--color=never --perl-regexp", - multiprocess = true, - file_icons = false, - git_icons = false, - color_icons = true, +M.defaults.btags = { + previewer = { _ctor = previewers.builtin.tags }, + ctags_file = nil, -- auto-detect + rg_opts = "--color=never --no-heading", + grep_opts = "--color=never --perl-regexp", + multiprocess = true, + file_icons = false, + git_icons = false, + color_icons = true, ctags_autogen = true, - fzf_opts = { - ["--no-multi"] = true, + fzf_opts = { + ["--no-multi"] = true, ["--delimiter"] = string.format("[:%s]", utils.nbsp), - ["--with-nth"] = "1,-1", - ["--tiebreak"] = "begin", + ["--with-nth"] = "1,-1", + ["--tiebreak"] = "begin", }, - _actions = function() return M.globals.actions.files end, - actions = { ["ctrl-g"] = false }, - formatter = false, + _actions = function() + return M.globals.actions.files + end, + actions = { ["ctrl-g"] = false }, + formatter = false, } -M.defaults.colorschemes = { +M.defaults.colorschemes = { live_preview = true, - winopts = { height = 0.55, width = 0.50, backdrop = false }, - fzf_opts = { ["--no-multi"] = true }, - actions = { ["enter"] = actions.colorscheme }, + winopts = { height = 0.55, width = 0.50, backdrop = false }, + fzf_opts = { ["--no-multi"] = true }, + actions = { ["enter"] = actions.colorscheme }, } -M.defaults.highlights = { - fzf_opts = { ["--no-multi"] = true }, +M.defaults.highlights = { + fzf_opts = { ["--no-multi"] = true }, fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" }, - previewer = { _ctor = previewers.builtin.highlights, }, - actions = { ["enter"] = actions.hi } + previewer = { _ctor = previewers.builtin.highlights }, + actions = { ["enter"] = actions.hi }, } M.defaults.awesome_colorschemes = { - winopts = { row = 0, col = 0.99, width = 0.50, backdrop = false }, + winopts = { row = 0, col = 0.99, width = 0.50, backdrop = false }, live_preview = true, - max_threads = 5, - fzf_opts = { - ["--multi"] = true, + max_threads = 5, + fzf_opts = { + ["--multi"] = true, ["--delimiter"] = "[:]", - ["--with-nth"] = "3..", - ["--tiebreak"] = "index", + ["--with-nth"] = "3..", + ["--tiebreak"] = "index", }, - dbfile = "data/colorschemes.json", - icons = { utils.ansi_codes.blue("󰇚"), utils.ansi_codes.yellow(""), " " }, - packpath = function() + dbfile = "data/colorschemes.json", + icons = { utils.ansi_codes.blue("󰇚"), utils.ansi_codes.yellow(""), " " }, + packpath = function() return path.join({ vim.fn.stdpath("cache"), "fzf-lua" }) end, - actions = { - ["enter"] = actions.colorscheme, + actions = { + ["enter"] = actions.colorscheme, ["ctrl-g"] = { fn = actions.toggle_bg, exec_silent = true }, ["ctrl-r"] = { fn = actions.cs_update, reload = true }, ["ctrl-x"] = { fn = actions.cs_delete, reload = true }, - } + }, } -M.defaults.helptags = { - actions = { - ["enter"] = actions.help, +M.defaults.helptags = { + actions = { + ["enter"] = actions.help, ["ctrl-s"] = actions.help, ["ctrl-v"] = actions.help_vert, ["ctrl-t"] = actions.help_tab, }, - fzf_opts = { - ["--no-multi"] = true, + fzf_opts = { + ["--no-multi"] = true, ["--delimiter"] = string.format("[%s]", utils.nbsp), - ["--with-nth"] = "..-2", - ["--tiebreak"] = "begin", + ["--with-nth"] = "..-2", + ["--tiebreak"] = "begin", }, previewer = { _ctor = previewers.builtin.help_tags, }, } -M.defaults.manpages = { - cmd = "man -k .", - actions = { - ["enter"] = actions.man, +M.defaults.manpages = { + cmd = "man -k .", + actions = { + ["enter"] = actions.man, ["ctrl-s"] = actions.man, ["ctrl-v"] = actions.man_vert, ["ctrl-t"] = actions.man_tab, }, - fzf_opts = { ["--tiebreak"] = "begin", ["--no-multi"] = true }, + fzf_opts = { ["--tiebreak"] = "begin", ["--no-multi"] = true }, previewer = "man", } -M.defaults.lsp = { - previewer = M._default_previewer_fn, - file_icons = 1, - color_icons = true, - git_icons = false, +M.defaults.lsp = { + previewer = M._default_previewer_fn, + file_icons = 1, + color_icons = true, + git_icons = false, async_or_timeout = 5000, - jump1 = true, - jump1_action = actions.file_edit, - fzf_opts = { ["--multi"] = true }, - _actions = function() return M.globals.actions.files end, - _cached_hls = { "path_colnr", "path_linenr" }, - _treesitter = true, + jump1 = true, + jump1_action = actions.file_edit, + 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, + _uri = true, } -M.defaults.lsp.symbols = { - previewer = M._default_previewer_fn, - file_icons = 1, - color_icons = true, - git_icons = false, - symbol_style = 1, - symbol_icons = { - File = "󰈙", - Module = "", - Namespace = "󰦮", - Package = "", - Class = "󰆧", - Method = "󰊕", - Property = "", - Field = "", - Constructor = "", - Enum = "", - Interface = "", - Function = "󰊕", - Variable = "󰀫", - Constant = "󰏿", - String = "", - Number = "󰎠", - Boolean = "󰨙", - Array = "󱡠", - Object = "", - Key = "󰌋", - Null = "󰟢", - EnumMember = "", - Struct = "󰆼", - Event = "", - Operator = "󰆕", +M.defaults.lsp.symbols = { + previewer = M._default_previewer_fn, + file_icons = 1, + color_icons = true, + git_icons = false, + symbol_style = 1, + symbol_icons = { + File = "󰈙", + Module = "", + Namespace = "󰦮", + Package = "", + Class = "󰆧", + Method = "󰊕", + Property = "", + Field = "", + Constructor = "", + Enum = "", + Interface = "", + Function = "󰊕", + Variable = "󰀫", + Constant = "󰏿", + String = "", + Number = "󰎠", + Boolean = "󰨙", + Array = "󱡠", + Object = "", + Key = "󰌋", + Null = "󰟢", + EnumMember = "", + Struct = "󰆼", + Event = "", + Operator = "󰆕", TypeParameter = "󰗴", }, - symbol_hl = function(s) return "@" .. s:lower() end, - symbol_fmt = function(s, _) return "[" .. s .. "]" end, - child_prefix = true, + symbol_hl = function(s) + return "@" .. s:lower() + end, + symbol_fmt = function(s, _) + return "[" .. s .. "]" + end, + child_prefix = true, async_or_timeout = true, exec_empty_query = true, -- new formatting options with symbol name at the start - fzf_opts = { + fzf_opts = { ["--delimiter"] = string.format("[:%s]", utils.nbsp), - ["--tiebreak"] = "begin", - ["--multi"] = true, + ["--tiebreak"] = "begin", + ["--multi"] = true, }, line_field_index = "{-2}", -- line field index - field_index_expr = "{}", -- entry field index - _fmt = { + field_index_expr = "{}", -- entry field index + _fmt = { -- NOT NEEDED: we format at the source in `lsp.symbol_handler` -- to = function(s, _) -- local file, text = s:match("^(.+:.+:.+:)%s(.*)") @@ -942,76 +1004,82 @@ M.defaults.lsp.symbols = { -- it will fail when the symbol contains "[%d]" (which we use as bufnr) local text, file = s:match(string.format("^(.-)%s(.*)", utils.nbsp)) return string.format("%s %s", file, text) - end + end, }, - _actions = function() return M.globals.actions.files end, - actions = { ["ctrl-g"] = { actions.sym_lsym } }, - _cached_hls = { "live_sym", "path_colnr", "path_linenr" }, - _uri = true, + _actions = function() + return M.globals.actions.files + end, + actions = { ["ctrl-g"] = { actions.sym_lsym } }, + _cached_hls = { "live_sym", "path_colnr", "path_linenr" }, + _uri = true, } -M.defaults.lsp.finder = { - previewer = M._default_previewer_fn, - file_icons = 1, +M.defaults.lsp.finder = { + previewer = M._default_previewer_fn, + file_icons = 1, color_icons = true, - git_icons = false, - async = true, - silent = true, - separator = "|" .. utils.nbsp, - _actions = function() return M.globals.actions.files end, + git_icons = false, + async = true, + silent = true, + separator = "|" .. utils.nbsp, + _actions = function() + return M.globals.actions.files + end, -- currently supported providers, defined as map so we can query easily - _providers = { - references = true, - definitions = true, - declarations = true, - typedefs = true, + _providers = { + references = true, + definitions = true, + declarations = true, + typedefs = true, implementations = true, - incoming_calls = true, - outgoing_calls = true, + incoming_calls = true, + outgoing_calls = true, }, -- by default display all supported providers - providers = { - { "declarations", prefix = utils.ansi_codes.magenta("decl") }, + providers = { + { "declarations", prefix = utils.ansi_codes.magenta("decl") }, { "implementations", prefix = utils.ansi_codes.green("impl") }, - { "definitions", prefix = utils.ansi_codes.green("def ") }, - { "typedefs", prefix = utils.ansi_codes.red("tdef") }, - { "references", prefix = utils.ansi_codes.blue("ref ") }, - { "incoming_calls", prefix = utils.ansi_codes.cyan("in ") }, - { "outgoing_calls", prefix = utils.ansi_codes.yellow("out ") }, + { "definitions", prefix = utils.ansi_codes.green("def ") }, + { "typedefs", prefix = utils.ansi_codes.red("tdef") }, + { "references", prefix = utils.ansi_codes.blue("ref ") }, + { "incoming_calls", prefix = utils.ansi_codes.cyan("in ") }, + { "outgoing_calls", prefix = utils.ansi_codes.yellow("out ") }, }, - fzf_opts = { ["--multi"] = true }, + fzf_opts = { ["--multi"] = true }, _treesitter = true, _cached_hls = { "path_colnr", "path_linenr" }, - _uri = true, + _uri = true, } -M.defaults.lsp.code_actions = { +M.defaults.lsp.code_actions = { async_or_timeout = 5000, - previewer = "codeaction", + previewer = "codeaction", -- previewer = "codeaction_native", - fzf_opts = { ["--no-multi"] = true }, + fzf_opts = { ["--no-multi"] = true }, -- NOTE: we don't need an action as code actions are executed by the ui.select -- callback but we setup an empty table to indicate to `globals.__index` that -- we need to inherit from the global defaults (#1232) - actions = {}, + actions = {}, } -M.defaults.diagnostics = { - previewer = M._default_previewer_fn, - file_icons = false, - color_icons = true, +M.defaults.diagnostics = { + previewer = M._default_previewer_fn, + file_icons = false, + color_icons = true, color_headings = true, - git_icons = false, - diag_icons = true, - diag_source = true, - diag_code = true, - multiline = 2, - fzf_opts = { + git_icons = false, + diag_icons = true, + diag_source = true, + diag_code = true, + multiline = 2, + fzf_opts = { ["--multi"] = true, - ["--wrap"] = true, + ["--wrap"] = true, }, - _actions = function() return M.globals.actions.files end, - _cached_hls = { "path_colnr", "path_linenr" }, + _actions = function() + return M.globals.actions.files + end, + _cached_hls = { "path_colnr", "path_linenr" }, -- signs = { -- ["Error"] = { text = "e", texthl = "DiagnosticError" }, -- ["Warn"] = { text = "w", texthl = "DiagnosticWarn" }, @@ -1020,293 +1088,305 @@ M.defaults.diagnostics = { -- }, } -M.defaults.builtin = { - winopts = { +M.defaults.builtin = { + winopts = { height = 0.65, - width = 0.50, + width = 0.50, }, fzf_opts = { ["--no-multi"] = true }, - actions = { ["enter"] = actions.run_builtin }, + actions = { ["enter"] = actions.run_builtin }, } -M.defaults.profiles = { +M.defaults.profiles = { previewer = M._default_previewer_fn, - fzf_opts = { + fzf_opts = { ["--delimiter"] = "[:]", - ["--with-nth"] = "-1..", - ["--tiebreak"] = "begin", - ["--no-multi"] = true, + ["--with-nth"] = "-1..", + ["--tiebreak"] = "begin", + ["--no-multi"] = true, }, - actions = { ["enter"] = actions.apply_profile }, + actions = { ["enter"] = actions.apply_profile }, } -M.defaults.marks = { - fzf_opts = { ["--no-multi"] = true }, - actions = { +M.defaults.marks = { + fzf_opts = { ["--no-multi"] = true }, + actions = { ["enter"] = actions.goto_mark, - ["ctrl-x"] = { fn = actions.mark_del, reload = true } + ["ctrl-x"] = { fn = actions.mark_del, reload = true }, }, previewer = { _ctor = previewers.builtin.marks }, } -M.defaults.changes = { +M.defaults.changes = { cmd = "changes", h1 = "change", } -M.defaults.jumps = { - cmd = "jumps", - fzf_opts = { ["--no-multi"] = true }, - actions = { ["enter"] = actions.goto_jump }, +M.defaults.jumps = { + cmd = "jumps", + fzf_opts = { ["--no-multi"] = true }, + actions = { ["enter"] = actions.goto_jump }, previewer = { _ctor = previewers.builtin.jumps }, } -M.defaults.tagstack = { - file_icons = 1, +M.defaults.tagstack = { + file_icons = 1, color_icons = true, - git_icons = true, - fzf_opts = { ["--multi"] = true }, - previewer = M._default_previewer_fn, - _actions = function() return M.globals.actions.files end, + git_icons = true, + fzf_opts = { ["--multi"] = true }, + previewer = M._default_previewer_fn, + _actions = function() + return M.globals.actions.files + end, } -M.defaults.commands = { - actions = { ["enter"] = actions.ex_run }, - flatten = {}, +M.defaults.commands = { + actions = { ["enter"] = actions.ex_run }, + flatten = {}, include_builtin = true, } -M.defaults.autocmds = { +M.defaults.autocmds = { show_desc = true, previewer = { _ctor = previewers.builtin.autocmds }, - _actions = function() return M.globals.actions.files end, - fzf_opts = { + _actions = function() + return M.globals.actions.files + end, + fzf_opts = { ["--delimiter"] = "[│]", - ["--with-nth"] = "2..", - ["--no-multi"] = true, + ["--with-nth"] = "2..", + ["--no-multi"] = true, }, } -M.defaults.command_history = { - fzf_opts = { ["--tiebreak"] = "index", ["--no-multi"] = true }, - _treesitter = function(line) return "foo.vim", nil, line end, - fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" }, - actions = { - ["enter"] = actions.ex_run_cr, +M.defaults.command_history = { + fzf_opts = { ["--tiebreak"] = "index", ["--no-multi"] = true }, + _treesitter = function(line) + return "foo.vim", nil, line + end, + fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" }, + actions = { + ["enter"] = actions.ex_run_cr, ["ctrl-e"] = actions.ex_run, }, } -M.defaults.search_history = { - fzf_opts = { ["--tiebreak"] = "index", ["--no-multi"] = true }, - _treesitter = function(line) return "", nil, line, "regex" end, - fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" }, - actions = { - ["enter"] = actions.search_cr, +M.defaults.search_history = { + fzf_opts = { ["--tiebreak"] = "index", ["--no-multi"] = true }, + _treesitter = function(line) + return "", nil, line, "regex" + end, + fzf_colors = { ["hl"] = "-1:reverse", ["hl+"] = "-1:reverse" }, + actions = { + ["enter"] = actions.search_cr, ["ctrl-e"] = actions.search, }, } -M.defaults.registers = { - multiline = true, +M.defaults.registers = { + multiline = true, ignore_empty = true, - actions = { ["enter"] = actions.paste_register }, - fzf_opts = { ["--no-multi"] = true }, + actions = { ["enter"] = actions.paste_register }, + fzf_opts = { ["--no-multi"] = true }, } -M.defaults.keymaps = { - previewer = { _ctor = previewers.builtin.keymaps }, - winopts = { preview = { layout = "vertical" } }, - fzf_opts = { ["--tiebreak"] = "index", ["--no-multi"] = true }, +M.defaults.keymaps = { + previewer = { _ctor = previewers.builtin.keymaps }, + winopts = { preview = { layout = "vertical" } }, + fzf_opts = { ["--tiebreak"] = "index", ["--no-multi"] = true }, ignore_patterns = { "^", "^" }, - show_desc = true, - show_details = true, - actions = { - ["enter"] = actions.keymap_apply, + show_desc = true, + show_details = true, + actions = { + ["enter"] = actions.keymap_apply, ["ctrl-s"] = actions.keymap_split, ["ctrl-v"] = actions.keymap_vsplit, ["ctrl-t"] = actions.keymap_tabedit, }, } -M.defaults.nvim_options = { - previewer = { _ctor = previewers.builtin.nvim_options }, - separator = "│", +M.defaults.nvim_options = { + previewer = { _ctor = previewers.builtin.nvim_options }, + separator = "│", color_values = true, - actions = { - ["enter"] = { fn = actions.nvim_opt_edit_local, reload = true }, + actions = { + ["enter"] = { fn = actions.nvim_opt_edit_local, reload = true }, ["alt-enter"] = { fn = actions.nvim_opt_edit_global, reload = true }, }, - fzf_opts = { + fzf_opts = { ["--nth"] = 1, ["--delimiter"] = "[│]", ["--no-multi"] = true, }, } -M.defaults.spell_suggest = { +M.defaults.spell_suggest = { winopts = { relative = "cursor", - row = 1, - col = 0, - height = 0.40, - width = 0.30, + row = 1, + col = 0, + height = 0.40, + width = 0.30, }, actions = { ["enter"] = actions.complete, }, } -M.defaults.filetypes = { +M.defaults.filetypes = { file_icons = false, - actions = { ["enter"] = actions.set_filetype }, + actions = { ["enter"] = actions.set_filetype }, } -M.defaults.packadd = { +M.defaults.packadd = { actions = { ["enter"] = actions.packadd, }, } -M.defaults.menus = { +M.defaults.menus = { actions = { ["enter"] = actions.exec_menu, }, } -M.defaults.tmux = { +M.defaults.tmux = { buffers = { - cmd = "tmux list-buffers", + cmd = "tmux list-buffers", register = [["]], - actions = { ["enter"] = actions.tmux_buf_set_reg }, - fzf_opts = { ["--no-multi"] = true, ["--delimiter"] = "[:]" } + actions = { ["enter"] = actions.tmux_buf_set_reg }, + fzf_opts = { ["--no-multi"] = true, ["--delimiter"] = "[:]" }, }, } -M.defaults.dap = { - commands = { fzf_opts = { ["--no-multi"] = true }, }, - configurations = { fzf_opts = { ["--no-multi"] = true }, }, - variables = { fzf_opts = { ["--no-multi"] = true }, }, - frames = { fzf_opts = { ["--no-multi"] = true }, }, - breakpoints = { - file_icons = 1, +M.defaults.dap = { + commands = { fzf_opts = { ["--no-multi"] = true } }, + configurations = { fzf_opts = { ["--no-multi"] = true } }, + variables = { fzf_opts = { ["--no-multi"] = true } }, + frames = { fzf_opts = { ["--no-multi"] = true } }, + breakpoints = { + file_icons = 1, color_icons = true, - git_icons = false, - previewer = M._default_previewer_fn, - _actions = function() return M.globals.actions.files end, - actions = { ["ctrl-x"] = { fn = actions.dap_bp_del, reload = true } }, - fzf_opts = { + git_icons = false, + previewer = M._default_previewer_fn, + _actions = function() + return M.globals.actions.files + end, + actions = { ["ctrl-x"] = { fn = actions.dap_bp_del, reload = true } }, + fzf_opts = { ["--delimiter"] = "[\\]:]", - ["--with-nth"] = "2..", + ["--with-nth"] = "2..", }, _cached_hls = { "path_colnr", "path_linenr" }, }, } -M.defaults.complete_path = { - cmd = nil, -- default: auto detect fd|rg|find - file_icons = false, - git_icons = false, - color_icons = true, - multiprocess = true, - word_pattern = nil, - fzf_opts = { ["--no-multi"] = true }, +M.defaults.complete_path = { + cmd = nil, -- default: auto detect fd|rg|find + file_icons = false, + git_icons = false, + color_icons = true, + multiprocess = true, + word_pattern = nil, + fzf_opts = { ["--no-multi"] = true }, _fzf_nth_devicons = true, - actions = { ["enter"] = actions.complete }, + actions = { ["enter"] = actions.complete }, } -M.defaults.complete_file = { - cmd = nil, -- default: auto detect rg|fd|find - multiprocess = true, - file_icons = 1, - color_icons = true, - git_icons = false, - word_pattern = nil, - _actions = function() return M.globals.actions.files end, - actions = { ["enter"] = actions.complete }, - previewer = M._default_previewer_fn, - winopts = { preview = { hidden = true } }, - fzf_opts = { ["--no-multi"] = true }, +M.defaults.complete_file = { + cmd = nil, -- default: auto detect rg|fd|find + multiprocess = true, + file_icons = 1, + color_icons = true, + git_icons = false, + word_pattern = nil, + _actions = function() + return M.globals.actions.files + end, + actions = { ["enter"] = actions.complete }, + previewer = M._default_previewer_fn, + winopts = { preview = { hidden = true } }, + fzf_opts = { ["--no-multi"] = true }, _fzf_nth_devicons = true, } -M.defaults.zoxide = { +M.defaults.zoxide = { multiprocess = true, - cmd = "zoxide query --list --score", - git_root = false, - formatter = "path.dirname_first", - fzf_opts = { - ["--no-multi"] = true, + cmd = "zoxide query --list --score", + git_root = false, + formatter = "path.dirname_first", + fzf_opts = { + ["--no-multi"] = true, ["--delimiter"] = "[\t]", - ["--tabstop"] = "4", - ["--tiebreak"] = "end,index", - ["--nth"] = "2..", - ["--no-sort"] = true, -- sort by score + ["--tabstop"] = "4", + ["--tiebreak"] = "end,index", + ["--nth"] = "2..", + ["--no-sort"] = true, -- sort by score }, - actions = { enter = actions.cd } + actions = { enter = actions.cd }, } -M.defaults.complete_line = { complete = true } +M.defaults.complete_line = { complete = true } -M.defaults.file_icon_padding = "" +M.defaults.file_icon_padding = "" -- No need to sset this, already defaults to `nvim_open_win` -- M.help_open_win = vim.api.nvim_open_win -M.defaults.dir_icon = "" +M.defaults.dir_icon = "" -M.defaults.__HLS = { - normal = "FzfLuaNormal", - border = "FzfLuaBorder", - title = "FzfLuaTitle", - title_flags = "FzfLuaTitleFlags", - backdrop = "FzfLuaBackdrop", - help_normal = "FzfLuaHelpNormal", - help_border = "FzfLuaHelpBorder", +M.defaults.__HLS = { + normal = "FzfLuaNormal", + border = "FzfLuaBorder", + title = "FzfLuaTitle", + title_flags = "FzfLuaTitleFlags", + backdrop = "FzfLuaBackdrop", + help_normal = "FzfLuaHelpNormal", + help_border = "FzfLuaHelpBorder", preview_normal = "FzfLuaPreviewNormal", preview_border = "FzfLuaPreviewBorder", - preview_title = "FzfLuaPreviewTitle", - cursor = "FzfLuaCursor", - cursorline = "FzfLuaCursorLine", - cursorlinenr = "FzfLuaCursorLineNr", - search = "FzfLuaSearch", + preview_title = "FzfLuaPreviewTitle", + cursor = "FzfLuaCursor", + cursorline = "FzfLuaCursorLine", + cursorlinenr = "FzfLuaCursorLineNr", + search = "FzfLuaSearch", scrollborder_e = "FzfLuaScrollBorderEmpty", scrollborder_f = "FzfLuaScrollBorderFull", - scrollfloat_e = "FzfLuaScrollFloatEmpty", - scrollfloat_f = "FzfLuaScrollFloatFull", - header_bind = "FzfLuaHeaderBind", - header_text = "FzfLuaHeaderText", - 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", - tab_marker = "FzfLuaTabMarker", - dir_icon = "FzfLuaDirIcon", - dir_part = "FzfLuaDirPart", - file_part = "FzfLuaFilePart", - live_prompt = "FzfLuaLivePrompt", - live_sym = "FzfLuaLiveSym", - fzf = { - normal = "FzfLuaFzfNormal", + scrollfloat_e = "FzfLuaScrollFloatEmpty", + scrollfloat_f = "FzfLuaScrollFloatFull", + header_bind = "FzfLuaHeaderBind", + header_text = "FzfLuaHeaderText", + 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", + tab_marker = "FzfLuaTabMarker", + dir_icon = "FzfLuaDirIcon", + dir_part = "FzfLuaDirPart", + file_part = "FzfLuaFilePart", + live_prompt = "FzfLuaLivePrompt", + live_sym = "FzfLuaLiveSym", + fzf = { + normal = "FzfLuaFzfNormal", cursorline = "FzfLuaFzfCursorLine", - match = "FzfLuaFzfMatch", - border = "FzfLuaFzfBorder", - scrollbar = "FzfLuaFzfScrollbar", - separator = "FzfLuaFzfSeparator", - gutter = "FzfLuaFzfGutter", - header = "FzfLuaFzfHeader", - info = "FzfLuaFzfInfo", - pointer = "FzfLuaFzfPointer", - marker = "FzfLuaFzfMarker", - spinner = "FzfLuaFzfSpinner", - prompt = "FzfLuaFzfPrompt", - query = "FzfLuaFzfQuery", - } + match = "FzfLuaFzfMatch", + border = "FzfLuaFzfBorder", + scrollbar = "FzfLuaFzfScrollbar", + separator = "FzfLuaFzfSeparator", + gutter = "FzfLuaFzfGutter", + header = "FzfLuaFzfHeader", + info = "FzfLuaFzfInfo", + pointer = "FzfLuaFzfPointer", + marker = "FzfLuaFzfMarker", + spinner = "FzfLuaFzfSpinner", + prompt = "FzfLuaFzfPrompt", + query = "FzfLuaFzfQuery", + }, } return M diff --git a/lua/fzf-lua/devicons.lua b/lua/fzf-lua/devicons.lua index 2c6c3468d..d188fbd5b 100644 --- a/lua/fzf-lua/devicons.lua +++ b/lua/fzf-lua/devicons.lua @@ -1,7 +1,7 @@ local uv = vim.uv or vim.loop -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local Object = require "fzf-lua.class" +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local Object = require("fzf-lua.class") -- Our "copy" of the devicons library functions so we can load the library -- from the headless instance and better support edge cases like multi-part @@ -45,40 +45,48 @@ function NvimWebDevicons:new() end function NvimWebDevicons:load(do_not_lazy_load) - if not self._package_loaded - -- do not trigger lazy loading - and (not do_not_lazy_load or package.loaded[self._package_name]) + if + not self._package_loaded + -- do not trigger lazy loading + and (not do_not_lazy_load or package.loaded[self._package_name]) then self._package_loaded, self._package = pcall(require, self._package_name) if self._package_loaded then - self._package_path = path.parent(path.parent(path.normalize( - debug.getinfo(self._package.setup, "S").source:gsub("^@", "")))) + self._package_path = path.parent( + path.parent(path.normalize(debug.getinfo(self._package.setup, "S").source:gsub("^@", ""))) + ) end end return self._package_loaded end function NvimWebDevicons:is_mock() - return type(self._package_path) == "string" - and self._package_path:match("mini") ~= nil + return type(self._package_path) == "string" and self._package_path:match("mini") ~= nil end ---@return boolean|nil success function NvimWebDevicons:load_icons(opts) - if not self:loaded() then return end + if not self:loaded() then + return + end self._state = vim.tbl_deep_extend("force", self._state or {}, { icon_padding = type(opts.icon_padding) == "string" and opts.icon_padding or nil, dir_icon = vim.tbl_extend("force", { icon = "", color = nil }, opts.dir_icon or {}), - default_icon = - vim.tbl_extend("force", { icon = "", color = "#6d8086" }, opts.default_icon or {}), + default_icon = vim.tbl_extend( + "force", + { icon = "", color = "#6d8086" }, + opts.default_icon or {} + ), }) -- test if we have the correct icon set for the current background -- if the background changed from light<->dark, refresh the icons (#855) - if self._state and self._state.icons - and self._state.bg == vim.o.bg - and self._state.termguicolors == vim.o.termguicolors + if + self._state + and self._state.icons + and self._state.bg == vim.o.bg + and self._state.termguicolors == vim.o.termguicolors then return true end @@ -113,18 +121,17 @@ function NvimWebDevicons:load_icons(opts) } if type(all_devicons[1]) == "table" then self._state.default_icon.icon = all_devicons[1].icon or self._state.default_icon.icon - self._state.default_icon.color = - (self._state.termguicolors and all_devicons[1].color or all_devicons[1].cterm_color) or - self._state.default_icon.color + self._state.default_icon.color = ( + self._state.termguicolors and all_devicons[1].color or all_devicons[1].cterm_color + ) or self._state.default_icon.color end self._state.icons = { - by_filename = {}, -- full filename (path.tail) lookup - by_ext = {}, -- simple extension lookup + by_filename = {}, -- full filename (path.tail) lookup + by_ext = {}, -- simple extension lookup by_ext_2part = {}, -- 2-part extensions, e.g. "foo.test.js" -- lookup table to indicate extension has potentially has better match -- in the 2part for example, ".js" will send us looking for "test.js" ext_has_2part = {}, - } for k, v in pairs(all_devicons) do -- skip all indexed (numeric) entries @@ -133,16 +140,15 @@ function NvimWebDevicons:load_icons(opts) -- NOTE: we no longer need name since we use the RGB color directly -- name = v.name or k, icon = v.icon or "", - color = (self._state.termguicolors and v.color or v.cterm_color) - or (function() - -- some devicons customizations remove `info.color` - -- retrieve the color from the highlight group (#801) - local hlgroup = "DevIcon" .. (v.name or k) - local hexcol = utils.hexcol_from_hl(hlgroup, "fg", opts.mode) - if hexcol and #hexcol > 0 then - return hexcol - end - end)(), + color = (self._state.termguicolors and v.color or v.cterm_color) or (function() + -- some devicons customizations remove `info.color` + -- retrieve the color from the highlight group (#801) + local hlgroup = "DevIcon" .. (v.name or k) + local hexcol = utils.hexcol_from_hl(hlgroup, "fg", opts.mode) + if hexcol and #hexcol > 0 then + return hexcol + end + end)(), } -- NOTE: entries like "R" can appear in both icons by filename/extension if icons.by_filename[k] then @@ -165,7 +171,9 @@ function NvimWebDevicons:load_icons(opts) end function NvimWebDevicons:icon_by_ft(ft) - if not self:loaded() then return end + if not self:loaded() then + return + end return self._package.get_icon_by_filetype(ft) end @@ -178,21 +186,27 @@ function MiniIcons:new() end function MiniIcons:load(do_not_lazy_load) - if not self._package_loaded - -- do not trigger lazy loading - and (not do_not_lazy_load or package.loaded[self._package_name]) + if + not self._package_loaded + -- do not trigger lazy loading + and (not do_not_lazy_load or package.loaded[self._package_name]) then self._package_loaded, self._package = pcall(require, self._package_name) if self._package_loaded then - self._package_path = path.parent(path.parent(path.parent(path.normalize( - debug.getinfo(self._package.setup, "S").source:gsub("^@", ""))))) + self._package_path = path.parent( + path.parent( + path.parent(path.normalize(debug.getinfo(self._package.setup, "S").source:gsub("^@", ""))) + ) + ) end end return self._package_loaded end function MiniIcons:refresh_hlgroups(mode) - if not self._state or not self._hlgroups then return end + if not self._state or not self._hlgroups then + return + end self._state.hl2hex = {} for hl, _ in pairs(self._hlgroups) do self._state.hl2hex["_" .. hl] = utils.hexcol_from_hl(hl, "fg", mode) @@ -200,7 +214,9 @@ function MiniIcons:refresh_hlgroups(mode) end function MiniIcons:load_icons(opts) - if not self:loaded() then return end + if not self:loaded() then + return + end -- Icon set already loaded, refresh hlgroups and return if self._state and self._state.icons then @@ -215,7 +231,9 @@ function MiniIcons:load_icons(opts) end -- Something isn't right - if not _G.MiniIcons then return end + if not _G.MiniIcons then + return + end -- Automatically discover highlight groups used by mini self._hlgroups = {} @@ -234,14 +252,14 @@ function MiniIcons:load_icons(opts) default_icon = mini_get("default", "file"), icons = { by_filename_case_sensitive = true, - by_filename = {}, -- full filename (path.tail) lookup - by_filetype = {}, -- filetype lookup (vim.filetype.match) - by_ext = {}, -- simple extension lookup + by_filename = {}, -- full filename (path.tail) lookup + by_filetype = {}, -- filetype lookup (vim.filetype.match) + by_ext = {}, -- simple extension lookup by_ext_2part = {}, -- 2-part extensions, e.g. "foo.test.js" -- lookup table to indicate extension has potentially has better match -- in the 2part for example, ".js" will send us looking for "test.js" ext_has_2part = {}, - } + }, }) for _, file in ipairs(_G.MiniIcons.list("file")) do @@ -265,9 +283,9 @@ function MiniIcons:load_icons(opts) -- Extensions that have weird behaviors within `vim.filetype.match` -- https://github.com/ibhagwan/fzf-lua/issues/1358#issuecomment-2254215160 for k, v in pairs({ - sh = "sh", + sh = "sh", bash = "sh", - ksh = "sh", + ksh = "sh", tcsh = "sh", }) do self._state.icons.by_ext[k] = self._state.icons.by_filetype[v] @@ -280,7 +298,9 @@ function MiniIcons:load_icons(opts) end function MiniIcons:icon_by_ft(ft) - if not self:loaded() then return end + if not self:loaded() then + return + end return self._package.get("filetype", ft) end @@ -310,12 +330,14 @@ function FzfLuaServer:load_icons(opts) chan_id, "nvim_exec_lua", "return require'fzf-lua.devicons'.state(...)", - { opts and opts.srv_plugin or nil }) + { opts and opts.srv_plugin or nil } + ) vim.fn.chanclose(chan_id) end) if not ok then - io.stdout:write(string.format( - "RPC error getting fzf_lua:devicons:STATE (%s): %s\n", self:path(), errmsg)) + io.stdout:write( + string.format("RPC error getting fzf_lua:devicons:STATE (%s): %s\n", self:path(), errmsg) + ) end return self._state == "table" end @@ -324,17 +346,25 @@ end function FzfLuaServer:update_state_mini() -- Abort when `self._state` is `nil`, can happen with live_grep -- `exec_empty_query=false` (default) as icons aren't loaded (#1391) - if not self:path() or type(self._state) ~= "table" then return end + if not self:path() or type(self._state) ~= "table" then + return + end local ok, errmsg = pcall(function() local chan_id = vim.fn.sockconnect("pipe", self:path(), { rpc = true }) - self._state = vim.rpcrequest(chan_id, "nvim_exec_lua", [[ + self._state = vim.rpcrequest( + chan_id, + "nvim_exec_lua", + [[ require"fzf-lua.devicons".set_state(...) - ]], { "mini", self._state }) + ]], + { "mini", self._state } + ) vim.fn.chanclose(chan_id) end) if not ok then - io.stdout:write(string.format( - "RPC error setting fzf_lua:devicons:STATE (%s): %s\n", self:path(), errmsg)) + io.stdout:write( + string.format("RPC error setting fzf_lua:devicons:STATE (%s): %s\n", self:path(), errmsg) + ) end end @@ -354,50 +384,56 @@ M.plugin_load = function(provider, do_not_lazy_load) return true end M.PLUGIN = provider == "srv" and M.__SRV - or provider == "mini" and M.__MINI - or provider == "devicons" and M.__DEVICONS - or (function() - if _G._fzf_lua_is_headless then - -- headless instance, fzf-lua server exists, attempt - -- to load icons from main neovim instance - ---@diagnostic disable-next-line: undefined-field - if type(_G._fzf_lua_server) == "string" then - return M.__SRV - end - ---@diagnostic disable-next-line: undefined-field - if _G._devicons_path then - -- headless instance, no fzf-lua server was specified - -- but we got devicon's lib path, add to runtime path - -- so `load()` can find the library - ---@diagnostic disable-next-line: undefined-field - vim.opt.runtimepath:append(_G._devicons_path) - else - -- FATAL: headless but no global vars are defined - local errmsg = "fzf-lua fatal: '_G._fzf_lua_server', '_G._devicons_path' both nil\n" - io.stderr:write(errmsg) - print(errmsg) - end - end - -- Prioritize nvim-web-devicons - local ret = M.__DEVICONS - -- Load mini only if `_G.MiniIcons` is present or if using `mock_nvim_web_devicons()` - -- at which point we would like to replace the mock with first-class MiniIcons (#1358) + or provider == "mini" and M.__MINI + or provider == "devicons" and M.__DEVICONS + or (function() + if _G._fzf_lua_is_headless then + -- headless instance, fzf-lua server exists, attempt + -- to load icons from main neovim instance ---@diagnostic disable-next-line: undefined-field - if not M.__DEVICONS:load(do_not_lazy_load) and _G.MiniIcons - or M.__DEVICONS:is_mock() and M.__MINI:load(do_not_lazy_load) - then - ret = M.__MINI + if type(_G._fzf_lua_server) == "string" then + return M.__SRV end - -- Load custom setup file - if _G._fzf_lua_is_headless - ---@diagnostic disable-next-line: undefined-field - and _G._devicons_setup and uv.fs_stat(_G._devicons_setup) then + ---@diagnostic disable-next-line: undefined-field + if _G._devicons_path then + -- headless instance, no fzf-lua server was specified + -- but we got devicon's lib path, add to runtime path + -- so `load()` can find the library ---@diagnostic disable-next-line: undefined-field - local file = loadfile(_G._devicons_setup) - if file then pcall(file) end + vim.opt.runtimepath:append(_G._devicons_path) + else + -- FATAL: headless but no global vars are defined + local errmsg = "fzf-lua fatal: '_G._fzf_lua_server', '_G._devicons_path' both nil\n" + io.stderr:write(errmsg) + print(errmsg) + end + end + -- Prioritize nvim-web-devicons + local ret = M.__DEVICONS + -- Load mini only if `_G.MiniIcons` is present or if using `mock_nvim_web_devicons()` + -- at which point we would like to replace the mock with first-class MiniIcons (#1358) + ---@diagnostic disable-next-line: undefined-field + if + not M.__DEVICONS:load(do_not_lazy_load) and _G.MiniIcons + or M.__DEVICONS:is_mock() and M.__MINI:load(do_not_lazy_load) + then + ret = M.__MINI + end + -- Load custom setup file + if + _G._fzf_lua_is_headless + ---@diagnostic disable-next-line: undefined-field + and _G._devicons_setup + and uv.fs_stat(_G._devicons_setup) + then + ---@diagnostic disable-next-line: undefined-field + local file = loadfile(_G._devicons_setup) + if file then + pcall(file) end - return ret - end)() + end + return ret + end)() return M.PLUGIN:load(do_not_lazy_load) end @@ -452,7 +488,6 @@ M.unload = function() M.PLUGIN:unload() end - ---@param filepath string ---@param extensionOverride string? ---@return string, string? @@ -480,13 +515,15 @@ M.get_devicon = function(filepath, extensionOverride) local ext = extensionOverride or path.extension(filename, true) -- lookup directly by filename - local by_filename = STATE.icons.by_filename - [STATE.icons.by_filename_case_sensitive and filename or filename:lower()] + local by_filename = + STATE.icons.by_filename[STATE.icons.by_filename_case_sensitive and filename or filename:lower()] if by_filename then icon, color = by_filename.icon, by_filename.color end - if ext then ext = ext:lower() end + if ext then + ext = ext:lower() + end -- check for `ext` as extension can be nil, e.g. "dockerfile" -- lookup by 2 part extensions, e.g. "foo.test.tsx" @@ -552,7 +589,9 @@ M.load = function(opts) opts = opts or {} -- If unable to load mini/devicons, abort - if not M.plugin_load(opts.plugin) then return end + if not M.plugin_load(opts.plugin) then + return + end -- Load/refresh the icon set, does nothing unless unloaded or bg changed return M.PLUGIN:load_icons(opts) diff --git a/lua/fzf-lua/fzf.lua b/lua/fzf-lua/fzf.lua index 8e3fca84a..0774837d6 100644 --- a/lua/fzf-lua/fzf.lua +++ b/lua/fzf-lua/fzf.lua @@ -5,8 +5,8 @@ -- https://github.com/vijaymarupudi/nvim-fzf/blob/master/lua/fzf.lua local uv = vim.uv or vim.loop -local utils = require "fzf-lua.utils" -local libuv = require "fzf-lua.libuv" +local utils = require("fzf-lua.utils") +local libuv = require("fzf-lua.libuv") local M = {} @@ -43,7 +43,9 @@ function M.raw_fzf(contents, fzf_cli_args, opts) error("[Fzf-lua] function must be called inside a coroutine.") end - if not opts then opts = {} end + if not opts then + opts = {} + end local cwd = opts.fzf_cwd or opts.cwd local cmd = { opts.fzf_bin or "fzf" } local fifotmpname = utils.__IS_WINDOWS and utils.windows_pipename() or tempname() @@ -129,7 +131,9 @@ function M.raw_fzf(contents, fzf_cli_args, opts) -- have to open this after there is a reader (termopen) -- otherwise this will block uv.fs_open(fifotmpname, "w", -1, function(err, fd) - if err then error(err) end + if err then + error(err) + end output_pipe = uv.new_pipe(false) output_pipe:open(fd) -- print(output_pipe:getpeername()) @@ -149,13 +153,17 @@ function M.raw_fzf(contents, fzf_cli_args, opts) end local function write_cb(data, cb) - if not output_pipe then return end + if not output_pipe then + return + end write_cb_count = write_cb_count + 1 output_pipe:write(data, function(err) -- decrement write call count write_cb_count = write_cb_count - 1 -- this will call the user's cb - if cb then cb(err) end + if cb then + cb(err) + end if err then -- can fail with premature process kill finish(2) @@ -175,7 +183,9 @@ function M.raw_fzf(contents, fzf_cli_args, opts) local function usr_write_cb(nl) local function end_of_data(usrdata, cb) if usrdata == nil then - if cb then cb(nil) end + if cb then + cb(nil) + end finish(5) return true end @@ -256,7 +266,7 @@ function M.raw_fzf(contents, fzf_cli_args, opts) local shell_cmd = utils.__IS_WINDOWS -- MSYS2 comes with "/usr/bin/cmd" that precedes "cmd.exe" (#1396) and { "cmd.exe", "/d", "/e:off", "/f:off", "/v:off", "/c" } - or { "sh", "-c" } + or { "sh", "-c" } if opts.pipe_cmd then if FZF_DEFAULT_COMMAND then table.insert(cmd, 1, string.format("(%s) | ", FZF_DEFAULT_COMMAND)) @@ -271,7 +281,9 @@ function M.raw_fzf(contents, fzf_cli_args, opts) -- This obscure option makes jobstart fail with: "The syntax of the command is incorrect" -- temporarily set to `false`, for more info see `:help shellslash` (#1055) local nvim_opt_shellslash = utils.__WIN_HAS_SHELLSLASH and vim.o.shellslash - if nvim_opt_shellslash then vim.o.shellslash = false end + if nvim_opt_shellslash then + vim.o.shellslash = false + end jobstart(shell_cmd, { cwd = cwd, pty = true, @@ -290,7 +302,9 @@ function M.raw_fzf(contents, fzf_cli_args, opts) -- a reason to inherit `preview-window` options it can be safely stripped -- from FZF_DEFAULT_OPTS (#1107) local default_opts = os.getenv("FZF_DEFAULT_OPTS") - if not default_opts then return end + if not default_opts then + return + end local patterns = { "--preview-window" } for _, p in ipairs(patterns) do -- remove flag end of string @@ -302,8 +316,9 @@ function M.raw_fzf(contents, fzf_cli_args, opts) end)(), -- Nullify user's RG config as this can cause conflicts -- with fzf-lua's rg opts (#1266) - ["RIPGREP_CONFIG_PATH"] = type(opts.RIPGREP_CONFIG_PATH) == "string" - and libuv.expand(opts.RIPGREP_CONFIG_PATH) or "", + ["RIPGREP_CONFIG_PATH"] = type(opts.RIPGREP_CONFIG_PATH) == "string" and libuv.expand( + opts.RIPGREP_CONFIG_PATH + ) or "", -- Prevents spamming rust logs with skim (#1959) ["RUST_LOG"] = "", }, @@ -321,13 +336,19 @@ function M.raw_fzf(contents, fzf_cli_args, opts) windows_pipe_server:close() end -- in windows, pipes that are not used are automatically cleaned up - if not utils.__IS_WINDOWS then vim.fn.delete(fifotmpname) end + if not utils.__IS_WINDOWS then + vim.fn.delete(fifotmpname) + end -- Windows only, restore `shellslash` if was true before `jobstart` - if nvim_opt_shellslash then vim.o.shellslash = nvim_opt_shellslash end + if nvim_opt_shellslash then + vim.o.shellslash = nvim_opt_shellslash + end vim.fn.delete(outputtmpname) - if #output == 0 then output = nil end + if #output == 0 then + output = nil + end coroutine.resume(co, output, rc) - end + end, }) -- fzf-tmux spawns outside neovim, don't set filetype/insert mode @@ -339,7 +360,7 @@ function M.raw_fzf(contents, fzf_cli_args, opts) -- Called from another fzf-win most likely utils.feed_keys_termcodes("i") else - vim.cmd [[startinsert]] + vim.cmd([[startinsert]]) end end diff --git a/lua/fzf-lua/init.lua b/lua/fzf-lua/init.lua index 5efcf7d9d..7e566d6ad 100644 --- a/lua/fzf-lua/init.lua +++ b/lua/fzf-lua/init.lua @@ -1,7 +1,7 @@ local uv = vim.uv or vim.loop -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") local M = {} @@ -34,9 +34,13 @@ do if ok then vim.g.fzf_lua_server = srv else - error(string.format( - "serverstart(): %s. Please make sure 'XDG_RUNTIME_DIR' (%s) is writeable", - srv, vim.fn.stdpath("run"))) + error( + string.format( + "serverstart(): %s. Please make sure 'XDG_RUNTIME_DIR' (%s) is writeable", + srv, + vim.fn.stdpath("run") + ) + ) end end @@ -64,70 +68,103 @@ function M.setup_highlights(override) -- we use `default = true` so calling this function doesn't override the colorscheme local default = not override local highlights = { - { "FzfLuaNormal", "normal", { default = default, link = "Normal" } }, - { "FzfLuaBorder", "border", { default = default, link = "Normal" } }, - { "FzfLuaTitle", "title", { default = default, link = "FzfLuaNormal" } }, - { "FzfLuaTitleFlags", "title_flags", { default = default, link = "CursorLine" } }, - { "FzfLuaBackdrop", "backdrop", { default = default, bg = "Black" } }, - { "FzfLuaHelpNormal", "help_normal", { default = default, link = "FzfLuaNormal" } }, - { "FzfLuaHelpBorder", "help_border", { default = default, link = "FzfLuaBorder" } }, - { "FzfLuaPreviewNormal", "preview_normal", { default = default, link = "FzfLuaNormal" } }, - { "FzfLuaPreviewBorder", "preview_border", { default = default, link = "FzfLuaBorder" } }, - { "FzfLuaPreviewTitle", "preview_title", { default = default, link = "FzfLuaTitle" } }, - { "FzfLuaCursor", "cursor", { default = default, link = "Cursor" } }, - { "FzfLuaCursorLine", "cursorline", { default = default, link = "CursorLine" } }, - { "FzfLuaCursorLineNr", "cursorlinenr", { default = default, link = "CursorLineNr" } }, - { "FzfLuaSearch", "search", { default = default, link = "IncSearch" } }, + { "FzfLuaNormal", "normal", { default = default, link = "Normal" } }, + { "FzfLuaBorder", "border", { default = default, link = "Normal" } }, + { "FzfLuaTitle", "title", { default = default, link = "FzfLuaNormal" } }, + { "FzfLuaTitleFlags", "title_flags", { default = default, link = "CursorLine" } }, + { "FzfLuaBackdrop", "backdrop", { default = default, bg = "Black" } }, + { "FzfLuaHelpNormal", "help_normal", { default = default, link = "FzfLuaNormal" } }, + { "FzfLuaHelpBorder", "help_border", { default = default, link = "FzfLuaBorder" } }, + { "FzfLuaPreviewNormal", "preview_normal", { default = default, link = "FzfLuaNormal" } }, + { "FzfLuaPreviewBorder", "preview_border", { default = default, link = "FzfLuaBorder" } }, + { "FzfLuaPreviewTitle", "preview_title", { default = default, link = "FzfLuaTitle" } }, + { "FzfLuaCursor", "cursor", { default = default, link = "Cursor" } }, + { "FzfLuaCursorLine", "cursorline", { default = default, link = "CursorLine" } }, + { "FzfLuaCursorLineNr", "cursorlinenr", { default = default, link = "CursorLineNr" } }, + { "FzfLuaSearch", "search", { default = default, link = "IncSearch" } }, { "FzfLuaScrollBorderEmpty", "scrollborder_e", { default = default, link = "FzfLuaBorder" } }, - { "FzfLuaScrollBorderFull", "scrollborder_f", { default = default, link = "FzfLuaBorder" } }, - { "FzfLuaScrollFloatEmpty", "scrollfloat_e", { default = default, link = "PmenuSbar" } }, - { "FzfLuaScrollFloatFull", "scrollfloat_f", { default = default, link = "PmenuThumb" } }, - { "FzfLuaDirIcon", "dir_icon", { default = default, link = "Directory" } }, - { "FzfLuaDirPart", "dir_part", { default = default, link = "Comment" } }, - { "FzfLuaFilePart", "file_part", { default = default, link = "@none" } }, + { "FzfLuaScrollBorderFull", "scrollborder_f", { default = default, link = "FzfLuaBorder" } }, + { "FzfLuaScrollFloatEmpty", "scrollfloat_e", { default = default, link = "PmenuSbar" } }, + { "FzfLuaScrollFloatFull", "scrollfloat_f", { default = default, link = "PmenuThumb" } }, + { "FzfLuaDirIcon", "dir_icon", { default = default, link = "Directory" } }, + { "FzfLuaDirPart", "dir_part", { default = default, link = "Comment" } }, + { "FzfLuaFilePart", "file_part", { default = default, link = "@none" } }, -- Fzf terminal hls, colors from `vim.api.nvim_get_color_map()` - { "FzfLuaHeaderBind", "header_bind", - { default = default, fg = is_light and "MediumSpringGreen" or "BlanchedAlmond" } }, - { "FzfLuaHeaderText", "header_text", - { default = default, fg = is_light and "Brown4" or "Brown1" } }, - { "FzfLuaPathColNr", "path_colnr", -- qf|diag|lsp - { default = default, fg = is_light and "CadetBlue4" or "CadetBlue1" } }, - { "FzfLuaPathLineNr", "path_linenr", -- qf|diag|lsp - { default = default, fg = is_light and "MediumSpringGreen" or "LightGreen" } }, - { "FzfLuaLivePrompt", "live_prompt", -- "live" queries prompt text color - { default = default, fg = is_light and "PaleVioletRed1" or "PaleVioletRed1" } }, - { "FzfLuaLiveSym", "live_sym", -- lsp_live_workspace_symbols query - { default = default, fg = is_light and "PaleVioletRed1" or "PaleVioletRed1" } }, + { + "FzfLuaHeaderBind", + "header_bind", + { default = default, fg = is_light and "MediumSpringGreen" or "BlanchedAlmond" }, + }, + { + "FzfLuaHeaderText", + "header_text", + { default = default, fg = is_light and "Brown4" or "Brown1" }, + }, + { + "FzfLuaPathColNr", + "path_colnr", -- qf|diag|lsp + { default = default, fg = is_light and "CadetBlue4" or "CadetBlue1" }, + }, + { + "FzfLuaPathLineNr", + "path_linenr", -- qf|diag|lsp + { default = default, fg = is_light and "MediumSpringGreen" or "LightGreen" }, + }, + { + "FzfLuaLivePrompt", + "live_prompt", -- "live" queries prompt text color + { default = default, fg = is_light and "PaleVioletRed1" or "PaleVioletRed1" }, + }, + { + "FzfLuaLiveSym", + "live_sym", -- lsp_live_workspace_symbols query + { default = default, fg = is_light and "PaleVioletRed1" or "PaleVioletRed1" }, + }, -- lines|blines|treesitter - { "FzfLuaBufId", "buf_id", { default = default, link = "TabLine" } }, - { "FzfLuaBufName", "buf_name", { default = default, link = "Directory" } }, + { "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", - { default = default, fg = is_light and "Brown4" or "Brown1" } }, - { "FzfLuaBufFlagAlt", "buf_flag_alt", - { default = default, fg = is_light and "CadetBlue4" or "CadetBlue1" } }, - { "FzfLuaTabTitle", "tab_title", -- tabs only - { default = default, fg = is_light and "CadetBlue4" or "LightSkyBlue1", bold = true } }, - { "FzfLuaTabMarker", "tab_marker", -- tabs only - { default = default, fg = is_light and "MediumSpringGreen" or "BlanchedAlmond", bold = true } }, + { + "FzfLuaBufNr", + "buf_nr", + { default = default, fg = is_light and "AquaMarine3" or "BlanchedAlmond" }, + }, + { + "FzfLuaBufFlagCur", + "buf_flag_cur", + { default = default, fg = is_light and "Brown4" or "Brown1" }, + }, + { + "FzfLuaBufFlagAlt", + "buf_flag_alt", + { default = default, fg = is_light and "CadetBlue4" or "CadetBlue1" }, + }, + { + "FzfLuaTabTitle", + "tab_title", -- tabs only + { default = default, fg = is_light and "CadetBlue4" or "LightSkyBlue1", bold = true }, + }, + { + "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" } }, + { "FzfLuaFzfNormal", "fzf.normal", { default = default, link = "FzfLuaNormal" } }, { "FzfLuaFzfCursorLine", "fzf.cursorline", { default = default, link = "FzfLuaCursorLine" } }, - { "FzfLuaFzfMatch", "fzf.match", { default = default, link = "Special" } }, - { "FzfLuaFzfBorder", "fzf.border", { default = default, link = "FzfLuaBorder" } }, - { "FzfLuaFzfScrollbar", "fzf.scrollbar", { default = default, link = "FzfLuaFzfBorder" } }, - { "FzfLuaFzfSeparator", "fzf.separator", { default = default, link = "FzfLuaFzfBorder" } }, - { "FzfLuaFzfGutter", "fzf.gutter", { default = default, link = "FzfLuaNormal" } }, - { "FzfLuaFzfHeader", "fzf.header", { default = default, link = "FzfLuaTitle" } }, - { "FzfLuaFzfInfo", "fzf.info", { default = default, link = "NonText" } }, - { "FzfLuaFzfPointer", "fzf.pointer", { default = default, link = "Special" } }, - { "FzfLuaFzfMarker", "fzf.marker", { default = default, link = "FzfLuaFzfPointer" } }, - { "FzfLuaFzfSpinner", "fzf.spinner", { default = default, link = "FzfLuaFzfPointer" } }, - { "FzfLuaFzfPrompt", "fzf.prompt", { default = default, link = "Special" } }, - { "FzfLuaFzfQuery", "fzf.query", { default = default, link = "FzfLuaNormal" } }, + { "FzfLuaFzfMatch", "fzf.match", { default = default, link = "Special" } }, + { "FzfLuaFzfBorder", "fzf.border", { default = default, link = "FzfLuaBorder" } }, + { "FzfLuaFzfScrollbar", "fzf.scrollbar", { default = default, link = "FzfLuaFzfBorder" } }, + { "FzfLuaFzfSeparator", "fzf.separator", { default = default, link = "FzfLuaFzfBorder" } }, + { "FzfLuaFzfGutter", "fzf.gutter", { default = default, link = "FzfLuaNormal" } }, + { "FzfLuaFzfHeader", "fzf.header", { default = default, link = "FzfLuaTitle" } }, + { "FzfLuaFzfInfo", "fzf.info", { default = default, link = "NonText" } }, + { "FzfLuaFzfPointer", "fzf.pointer", { default = default, link = "Special" } }, + { "FzfLuaFzfMarker", "fzf.marker", { default = default, link = "FzfLuaFzfPointer" } }, + { "FzfLuaFzfSpinner", "fzf.spinner", { default = default, link = "FzfLuaFzfPointer" } }, + { "FzfLuaFzfPrompt", "fzf.prompt", { default = default, link = "Special" } }, + { "FzfLuaFzfQuery", "fzf.query", { default = default, link = "FzfLuaNormal" } }, } for _, a in ipairs(highlights) do local hl_name, _, hl_def = a[1], a[2], a[3] @@ -155,8 +192,11 @@ function M.setup(opts, do_not_reset_defaults) opts[1] = opts[1] == nil and "default" or opts[1] if opts[1] then -- Did the user supply profile(s) to load? - opts = vim.tbl_deep_extend("keep", opts, - utils.load_profiles(opts[1], opts[2] == nil and 1 or opts[2])) + opts = vim.tbl_deep_extend( + "keep", + opts, + utils.load_profiles(opts[1], opts[2] == nil and 1 or opts[2]) + ) end if do_not_reset_defaults then -- no defaults reset requested, merge with previous setup options @@ -170,12 +210,21 @@ function M.setup(opts, do_not_reset_defaults) opts.defaults = opts.defaults or {} opts.defaults[o] = opts[gopt] opts[gopt] = nil - utils.warn(string.format("Deprecated option: '%s = %s' -> 'defaults = { %s = %s }'", - gopt, tostring(opts.defaults[o]), o, tostring(opts.defaults[o]))) + utils.warn( + string.format( + "Deprecated option: '%s = %s' -> 'defaults = { %s = %s }'", + gopt, + tostring(opts.defaults[o]), + o, + tostring(opts.defaults[o]) + ) + ) end end -- set custom   if caller requested - if opts.nbsp then utils.nbsp = opts.nbsp end + if opts.nbsp then + utils.nbsp = opts.nbsp + end -- store the setup options config.setup_opts = opts -- setup highlights @@ -183,7 +232,7 @@ function M.setup(opts, do_not_reset_defaults) end M.redraw = function() - local winobj = require "fzf-lua".win.__SELF() + local winobj = require("fzf-lua").win.__SELF() if winobj then winobj:redraw() end @@ -305,11 +354,11 @@ do -- we use an additional wrapper in order to save the -- current provider info: {cmd-name|module|function} M[k] = function(...) - M.set_info { + M.set_info({ cmd = k, mod = v[1], fnc = v[2], - } + }) return require(v[1])[v[2]](...) end return M[k](...) @@ -400,10 +449,12 @@ end M.builtin = function(opts) opts = config.normalize_opts(opts, "builtin") - if not opts then return end + if not opts then + return + end opts.metatable = M opts.metatable_exclude = M._excluded_metamap - return require "fzf-lua.providers.module".metatable(opts) + return require("fzf-lua.providers.module").metatable(opts) end return M diff --git a/lua/fzf-lua/lib/base64.lua b/lua/fzf-lua/lib/base64.lua index 722426758..62ca59ad5 100644 --- a/lua/fzf-lua/lib/base64.lua +++ b/lua/fzf-lua/lib/base64.lua @@ -47,20 +47,81 @@ if not extract then return w end else -- Lua 5.3+ - extract = load [[return function( v, from, width ) + extract = load([[return function( v, from, width ) return ( v >> from ) & ((1 << width) - 1) - end]] () + end]])() end end - function base64.makeencoder(s62, s63, spad) local encoder = {} - for b64code, char in pairs { [0] = 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', - 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', - '3', '4', '5', '6', '7', '8', '9', s62 or '+', s63 or '/', spad or '=' } do + for b64code, char in pairs({ + [0] = "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + s62 or "+", + s63 or "/", + spad or "=", + }) do encoder[b64code] = char:byte() end return encoder @@ -91,13 +152,21 @@ function base64.encode(str, encoder, usecaching) if usecaching then s = cache[v] if not s then - s = char(encoder[extract(v, 18, 6)], encoder[extract(v, 12, 6)], encoder[extract(v, 6, 6)], - encoder[extract(v, 0, 6)]) + s = char( + encoder[extract(v, 18, 6)], + encoder[extract(v, 12, 6)], + encoder[extract(v, 6, 6)], + encoder[extract(v, 0, 6)] + ) cache[v] = s end else - s = char(encoder[extract(v, 18, 6)], encoder[extract(v, 12, 6)], encoder[extract(v, 6, 6)], - encoder[extract(v, 0, 6)]) + s = char( + encoder[extract(v, 18, 6)], + encoder[extract(v, 12, 6)], + encoder[extract(v, 6, 6)], + encoder[extract(v, 0, 6)] + ) end t[k] = s k = k + 1 @@ -105,8 +174,12 @@ function base64.encode(str, encoder, usecaching) if lastn == 2 then local a, b = str:byte(n - 1, n) local v = a * 0x10000 + b * 0x100 - t[k] = char(encoder[extract(v, 18, 6)], encoder[extract(v, 12, 6)], encoder[extract(v, 6, 6)], - encoder[64]) + t[k] = char( + encoder[extract(v, 18, 6)], + encoder[extract(v, 12, 6)], + encoder[extract(v, 6, 6)], + encoder[64] + ) elseif lastn == 1 then local v = str:byte(n) * 0x10000 t[k] = char(encoder[extract(v, 18, 6)], encoder[extract(v, 12, 6)], encoder[64], encoder[64]) @@ -116,21 +189,23 @@ end function base64.decode(b64, decoder, usecaching) decoder = decoder or DEFAULT_DECODER - local pattern = '[^%w%+%/%=]' + local pattern = "[^%w%+%/%=]" if decoder then local s62, s63 for charcode, b64code in pairs(decoder) do - if b64code == 62 then s62 = charcode - elseif b64code == 63 then s63 = charcode + if b64code == 62 then + s62 = charcode + elseif b64code == 63 then + s63 = charcode end end - pattern = ('[^%%w%%%s%%%s%%=]'):format(char(s62), char(s63)) + pattern = ("[^%%w%%%s%%%s%%=]"):format(char(s62), char(s63)) end - b64 = b64:gsub(pattern, '') + b64 = b64:gsub(pattern, "") local cache = usecaching and {} local t, k = {}, 1 local n = #b64 - local padding = b64:sub(-2) == '==' and 2 or b64:sub(-1) == '=' and 1 or 0 + local padding = b64:sub(-2) == "==" and 2 or b64:sub(-1) == "=" and 1 or 0 for i = 1, padding > 0 and n - 4 or n, 4 do local a, b, c, d = b64:byte(i, i + 3) local s diff --git a/lua/fzf-lua/lib/serpent.lua b/lua/fzf-lua/lib/serpent.lua index 502aab8da..1cbd27bef 100644 --- a/lua/fzf-lua/lib/serpent.lua +++ b/lua/fzf-lua/lib/serpent.lua @@ -6,153 +6,280 @@ Source: https://github.com/pkulchenko/serpent ---@diagnostic disable local n, v = "serpent", "0.303" -- (C) 2012-18 Paul Kulchenko; MIT License local c, d = "Paul Kulchenko", "Lua serializer and pretty printer" -local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} -local badtype = {thread = true, userdata = true, cdata = true} +local snum = { + [tostring(1 / 0)] = "1/0 --[[math.huge]]", + [tostring(-1 / 0)] = "-1/0 --[[-math.huge]]", + [tostring(0 / 0)] = "0/0", +} +local badtype = { thread = true, userdata = true, cdata = true } local getmetatable = debug and debug.getmetatable or getmetatable -local pairs = function(t) return next, t end -- avoid using __pairs in Lua 5.2+ +local pairs = function(t) + return next, t +end -- avoid using __pairs in Lua 5.2+ local keyword, globals, G = {}, {}, (_G or _ENV) -for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false', - 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', - 'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end -for k,v in pairs(G) do globals[v] = k end -- build func to name mapping -for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do - for k,v in pairs(type(G[g]) == 'table' and G[g] or {}) do globals[v] = g..'.'..k end end +for _, k in ipairs({ + "and", + "break", + "do", + "else", + "elseif", + "end", + "false", + "for", + "function", + "goto", + "if", + "in", + "local", + "nil", + "not", + "or", + "repeat", + "return", + "then", + "true", + "until", + "while", +}) do + keyword[k] = true +end +for k, v in pairs(G) do + globals[v] = k +end -- build func to name mapping +for _, g in ipairs({ "coroutine", "debug", "io", "math", "string", "table", "os" }) do + for k, v in pairs(type(G[g]) == "table" and G[g] or {}) do + globals[v] = g .. "." .. k + end +end local function s(t, opts) local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge - local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) + local space, maxl = (opts.compact and "" or " "), (opts.maxlevel or math.huge) local maxlen, metatostring = tonumber(opts.maxlength), opts.metatostring - local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge) + local iname, comm = "_" .. (name or ""), opts.comment and (tonumber(opts.comment) or math.huge) local numformat = opts.numformat or "%.17g" - local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0 - local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)", - -- tostring(val) is needed because __tostring may return a non-string value - function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end - local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or numformat:format(s)) - or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 - or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end + local seen, sref, syms, symn = {}, { "local " .. iname .. "={}" }, {}, 0 + local function gensym(val) + return "_" + .. ( + tostring(tostring(val)):gsub("[^%w]", ""):gsub( + "(%d%w+)", + -- tostring(val) is needed because __tostring may return a non-string value + function(s) + if not syms[s] then + symn = symn + 1 + syms[s] = symn + end + return tostring(syms[s]) + end + ) + ) + end + local function safestr(s) + return type(s) == "number" and (huge and snum[tostring(s)] or numformat:format(s)) + or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 + or ("%q"):format(s):gsub("\010", "n"):gsub("\026", "\\026") + end -- handle radix changes in some locales if opts.fixradix and (".1f"):format(1.2) ~= "1.2" then local origsafestr = safestr - safestr = function(s) return type(s) == "number" - and (nohuge and snum[tostring(s)] or numformat:format(s):gsub(",",".")) or origsafestr(s) + safestr = function(s) + return type(s) == "number" + and (nohuge and snum[tostring(s)] or numformat:format(s):gsub(",", ".")) + or origsafestr(s) end end - local function comment(s,l) return comm and (l or 0) < comm and ' --[['..select(2, pcall(tostring, s))..']]' or '' end - local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal - and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end + local function comment(s, l) + return comm and (l or 0) < comm and " --[[" .. select(2, pcall(tostring, s)) .. "]]" or "" + end + local function globerr(s, l) + return globals[s] and globals[s] .. comment(s, l) + or not fatal and safestr(select(2, pcall(tostring, s))) + or error("Can't serialize " .. tostring(s)) + end local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r'] - local n = name == nil and '' or name + local n = name == nil and "" or name local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] - local safe = plain and n or '['..safestr(n)..']' - return (path or '')..(plain and path and '.' or '')..safe, safe end - local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding - local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'} - local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end - table.sort(k, function(a,b) - -- sort numeric keys first: k[key] is not nil for numerical keys - return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) - < (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end + local safe = plain and n or "[" .. safestr(n) .. "]" + return (path or "") .. (plain and path and "." or "") .. safe, safe + end + local alphanumsort = type(opts.sortkeys) == "function" and opts.sortkeys + or function(k, o, n) -- k=keys, o=originaltable, n=padding + local maxn, to = tonumber(n) or 12, { number = "a", string = "b" } + local function padnum(d) + return ("%0" .. tostring(maxn) .. "d"):format(tonumber(d)) + end + table.sort(k, function(a, b) + -- sort numeric keys first: k[key] is not nil for numerical keys + return (k[a] ~= nil and 0 or to[type(a)] or "z") .. (tostring(a):gsub("%d+", padnum)) + < (k[b] ~= nil and 0 or to[type(b)] or "z") .. (tostring(b):gsub("%d+", padnum)) + end) + end local function val2str(t, name, indent, insref, path, plainindex, level) local ttype, level, mt = type(t), (level or 0), getmetatable(t) local spath, sname = safename(path, name) - local tag = plainindex and - ((type(name) == "number") and '' or name..space..'='..space) or - (name ~= nil and sname..space..'='..space or '') + local tag = plainindex and ((type(name) == "number") and "" or name .. space .. "=" .. space) + or (name ~= nil and sname .. space .. "=" .. space or "") if seen[t] then -- already seen this element - sref[#sref+1] = spath..space..'='..space..seen[t] - return tag..'nil'..comment('ref', level) + sref[#sref + 1] = spath .. space .. "=" .. space .. seen[t] + return tag .. "nil" .. comment("ref", level) end -- protect from those cases where __tostring may fail - if type(mt) == 'table' and metatostring ~= false then - local to, tr = pcall(function() return mt.__tostring(t) end) - local so, sr = pcall(function() return mt.__serialize(t) end) - if (to or so) then -- knows how to serialize itself + if type(mt) == "table" and metatostring ~= false then + local to, tr = pcall(function() + return mt.__tostring(t) + end) + local so, sr = pcall(function() + return mt.__serialize(t) + end) + if to or so then -- knows how to serialize itself seen[t] = insref or spath t = so and sr or tr ttype = type(t) end -- new value falls through to be serialized end if ttype == "table" then - if level >= maxl then return tag..'{}'..comment('maxlvl', level) end + if level >= maxl then + return tag .. "{}" .. comment("maxlvl", level) + end seen[t] = insref or spath - if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty - if maxlen and maxlen < 0 then return tag..'{}'..comment('maxlen', level) end + if next(t) == nil then + return tag .. "{}" .. comment(t, level) + end -- table empty + if maxlen and maxlen < 0 then + return tag .. "{}" .. comment("maxlen", level) + end local maxn, o, out = math.min(#t, maxnum or #t), {}, {} - for key = 1, maxn do o[key] = key end + for key = 1, maxn do + o[key] = key + end if not maxnum or #o < maxnum then local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables for key in pairs(t) do - if o[key] ~= key then n = n + 1; o[n] = key end + if o[key] ~= key then + n = n + 1 + o[n] = key + end end end - if maxnum and #o > maxnum then o[maxnum+1] = nil end - if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end + if maxnum and #o > maxnum then + o[maxnum + 1] = nil + end + if opts.sortkeys and #o > maxn then + alphanumsort(o, t, opts.sortkeys) + end local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output) for n, key in ipairs(o) do local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse - if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing - or opts.keyallow and not opts.keyallow[key] - or opts.keyignore and opts.keyignore[key] - or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types - or sparse and value == nil then -- skipping nils; do nothing - elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then + if + opts.valignore and opts.valignore[value] -- skip ignored values; do nothing + or opts.keyallow and not opts.keyallow[key] + or opts.keyignore and opts.keyignore[key] + or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types + or sparse and value == nil + then -- skipping nils; do nothing + elseif ktype == "table" or ktype == "function" or badtype[ktype] then if not seen[key] and not globals[key] then - sref[#sref+1] = 'placeholder' + sref[#sref + 1] = "placeholder" local sname = safename(iname, gensym(key)) -- iname is table for local variables - sref[#sref] = val2str(key,sname,indent,sname,iname,true) + sref[#sref] = val2str(key, sname, indent, sname, iname, true) end - sref[#sref+1] = 'placeholder' - local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']' - sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path)) + sref[#sref + 1] = "placeholder" + local path = seen[t] .. "[" .. tostring(seen[key] or globals[key] or gensym(key)) .. "]" + sref[#sref] = path + .. space + .. "=" + .. space + .. tostring(seen[value] or val2str(value, nil, indent, path)) else - out[#out+1] = val2str(value,key,indent,nil,seen[t],plainindex,level+1) + out[#out + 1] = val2str(value, key, indent, nil, seen[t], plainindex, level + 1) if maxlen then maxlen = maxlen - #out[#out] - if maxlen < 0 then break end + if maxlen < 0 then + break + end end end end - local prefix = string.rep(indent or '', level) - local head = indent and '{\n'..prefix..indent or '{' - local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space)) - local tail = indent and "\n"..prefix..'}' or '}' - return (custom and custom(tag,head,body,tail,level) or tag..head..body..tail)..comment(t, level) + local prefix = string.rep(indent or "", level) + local head = indent and "{\n" .. prefix .. indent or "{" + local body = table.concat(out, "," .. (indent and "\n" .. prefix .. indent or space)) + local tail = indent and "\n" .. prefix .. "}" or "}" + return (custom and custom(tag, head, body, tail, level) or tag .. head .. body .. tail) + .. comment(t, level) elseif badtype[ttype] then seen[t] = insref or spath - return tag..globerr(t, level) - elseif ttype == 'function' then + return tag .. globerr(t, level) + elseif ttype == "function" then seen[t] = insref or spath - if opts.nocode then return tag.."function() --[[..skipped..]] end"..comment(t, level) end + if opts.nocode then + return tag .. "function() --[[..skipped..]] end" .. comment(t, level) + end local ok, res = pcall(string.dump, t) - local func = ok and "((loadstring or load)("..safestr(res)..",'@serialized'))"..comment(t, level) - return tag..(func or globerr(t, level)) - else return tag..safestr(t) end -- handle all other types + local func = ok + and "((loadstring or load)(" .. safestr(res) .. ",'@serialized'))" .. comment(t, level) + return tag .. (func or globerr(t, level)) + else + return tag .. safestr(t) + end -- handle all other types end - local sepr = indent and "\n" or ";"..space + local sepr = indent and "\n" or ";" .. space local body = val2str(t, name, indent) -- this call also populates sref - local tail = #sref>1 and table.concat(sref, sepr)..sepr or '' - local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or '' - return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end" + local tail = #sref > 1 and table.concat(sref, sepr) .. sepr or "" + local warn = opts.comment + and #sref > 1 + and space .. "--[[incomplete output with shared/self-references skipped]]" + or "" + return not name and body .. warn + or "do local " .. body .. sepr .. tail .. "return " .. name .. sepr .. "end" end local function deserialize(data, opts) local env = (opts and opts.safe == false) and G or setmetatable({}, { - __index = function(t,k) return t end, - __call = function(t,...) error("cannot call functions") end - }) - local f, res = (loadstring or load)('return '..data, nil, nil, env) - if not f then f, res = (loadstring or load)(data, nil, nil, env) end - if not f then return f, res end - if setfenv then setfenv(f, env) end + __index = function(t, k) + return t + end, + __call = function(t, ...) + error("cannot call functions") + end, + }) + local f, res = (loadstring or load)("return " .. data, nil, nil, env) + if not f then + f, res = (loadstring or load)(data, nil, nil, env) + end + if not f then + return f, res + end + if setfenv then + setfenv(f, env) + end return pcall(f) end -local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end -return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s, +local function merge(a, b) + if b then + for k, v in pairs(b) do + a[k] = v + end + end + return a +end +return { + _NAME = n, + _COPYRIGHT = c, + _DESCRIPTION = d, + _VERSION = v, + serialize = s, load = deserialize, - dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end, - line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end, - block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end } + dump = function(a, opts) + return s(a, merge({ name = "_", compact = true, sparse = true }, opts)) + end, + line = function(a, opts) + return s(a, merge({ sortkeys = true, comment = true }, opts)) + end, + block = function(a, opts) + return s(a, merge({ indent = " ", sortkeys = true, comment = true }, opts)) + end, +} diff --git a/lua/fzf-lua/lib/utf8.lua b/lua/fzf-lua/lib/utf8.lua index d1348b801..7f4cee129 100644 --- a/lua/fzf-lua/lib/utf8.lua +++ b/lua/fzf-lua/lib/utf8.lua @@ -67,177 +67,179 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- UTF8-tail = %x80-BF -- -local byte = string.byte -local char = string.char -local dump = string.dump -local find = string.find -local format = string.format -local len = string.len -local lower = string.lower -local rep = string.rep -local sub = string.sub -local upper = string.upper +local byte = string.byte +local char = string.char +local dump = string.dump +local find = string.find +local format = string.format +local len = string.len +local lower = string.lower +local rep = string.rep +local sub = string.sub +local upper = string.upper -- returns the number of bytes used by the UTF-8 character at byte i in s -- also doubles as a UTF-8 character validator -local function utf8charbytes (s, i) - -- argument defaults - i = i or 1 - - -- argument checking - if type(s) ~= "string" then - error("bad argument #1 to 'utf8charbytes' (string expected, got ".. type(s).. ")") - end - if type(i) ~= "number" then - error("bad argument #2 to 'utf8charbytes' (number expected, got ".. type(i).. ")") - end - - local c = byte(s, i) - - -- determine bytes needed for character, based on RFC 3629 - -- validate byte 1 - if c > 0 and c <= 127 then - -- UTF8-1 - return 1 - - elseif c >= 194 and c <= 223 then - -- UTF8-2 - local c2 = byte(s, i + 1) - - if not c2 then - error("UTF-8 string terminated early") - end - - -- validate byte 2 - if c2 < 128 or c2 > 191 then - error("Invalid UTF-8 character") - end - - return 2 - - elseif c >= 224 and c <= 239 then - -- UTF8-3 - local c2 = byte(s, i + 1) - local c3 = byte(s, i + 2) - - if not c2 or not c3 then - error("UTF-8 string terminated early") - end - - -- validate byte 2 - if c == 224 and (c2 < 160 or c2 > 191) then - error("Invalid UTF-8 character") - elseif c == 237 and (c2 < 128 or c2 > 159) then - error("Invalid UTF-8 character") - elseif c2 < 128 or c2 > 191 then - error("Invalid UTF-8 character") - end - - -- validate byte 3 - if c3 < 128 or c3 > 191 then - error("Invalid UTF-8 character") - end - - return 3 - - elseif c >= 240 and c <= 244 then - -- UTF8-4 - local c2 = byte(s, i + 1) - local c3 = byte(s, i + 2) - local c4 = byte(s, i + 3) - - if not c2 or not c3 or not c4 then - error("UTF-8 string terminated early") - end - - -- validate byte 2 - if c == 240 and (c2 < 144 or c2 > 191) then - error("Invalid UTF-8 character") - elseif c == 244 and (c2 < 128 or c2 > 143) then - error("Invalid UTF-8 character") - elseif c2 < 128 or c2 > 191 then - error("Invalid UTF-8 character") - end - - -- validate byte 3 - if c3 < 128 or c3 > 191 then - error("Invalid UTF-8 character") - end - - -- validate byte 4 - if c4 < 128 or c4 > 191 then - error("Invalid UTF-8 character") - end - - return 4 - - else - error("Invalid UTF-8 character") - end +local function utf8charbytes(s, i) + -- argument defaults + i = i or 1 + + -- argument checking + if type(s) ~= "string" then + error("bad argument #1 to 'utf8charbytes' (string expected, got " .. type(s) .. ")") + end + if type(i) ~= "number" then + error("bad argument #2 to 'utf8charbytes' (number expected, got " .. type(i) .. ")") + end + + local c = byte(s, i) + + -- determine bytes needed for character, based on RFC 3629 + -- validate byte 1 + if c > 0 and c <= 127 then + -- UTF8-1 + return 1 + elseif c >= 194 and c <= 223 then + -- UTF8-2 + local c2 = byte(s, i + 1) + + if not c2 then + error("UTF-8 string terminated early") + end + + -- validate byte 2 + if c2 < 128 or c2 > 191 then + error("Invalid UTF-8 character") + end + + return 2 + elseif c >= 224 and c <= 239 then + -- UTF8-3 + local c2 = byte(s, i + 1) + local c3 = byte(s, i + 2) + + if not c2 or not c3 then + error("UTF-8 string terminated early") + end + + -- validate byte 2 + if c == 224 and (c2 < 160 or c2 > 191) then + error("Invalid UTF-8 character") + elseif c == 237 and (c2 < 128 or c2 > 159) then + error("Invalid UTF-8 character") + elseif c2 < 128 or c2 > 191 then + error("Invalid UTF-8 character") + end + + -- validate byte 3 + if c3 < 128 or c3 > 191 then + error("Invalid UTF-8 character") + end + + return 3 + elseif c >= 240 and c <= 244 then + -- UTF8-4 + local c2 = byte(s, i + 1) + local c3 = byte(s, i + 2) + local c4 = byte(s, i + 3) + + if not c2 or not c3 or not c4 then + error("UTF-8 string terminated early") + end + + -- validate byte 2 + if c == 240 and (c2 < 144 or c2 > 191) then + error("Invalid UTF-8 character") + elseif c == 244 and (c2 < 128 or c2 > 143) then + error("Invalid UTF-8 character") + elseif c2 < 128 or c2 > 191 then + error("Invalid UTF-8 character") + end + + -- validate byte 3 + if c3 < 128 or c3 > 191 then + error("Invalid UTF-8 character") + end + + -- validate byte 4 + if c4 < 128 or c4 > 191 then + error("Invalid UTF-8 character") + end + + return 4 + else + error("Invalid UTF-8 character") + end end -- returns the number of characters in a UTF-8 string -local function utf8len (s) - -- argument checking - if type(s) ~= "string" then - for k,v in pairs(s) do print('"',tostring(k),'"',tostring(v),'"') end - error("bad argument #1 to 'utf8len' (string expected, got ".. type(s).. ")") - end - - local pos = 1 - local bytes = len(s) - local length = 0 - - while pos <= bytes do - length = length + 1 - pos = pos + utf8charbytes(s, pos) - end - - return length +local function utf8len(s) + -- argument checking + if type(s) ~= "string" then + for k, v in pairs(s) do + print('"', tostring(k), '"', tostring(v), '"') + end + error("bad argument #1 to 'utf8len' (string expected, got " .. type(s) .. ")") + end + + local pos = 1 + local bytes = len(s) + local length = 0 + + while pos <= bytes do + length = length + 1 + pos = pos + utf8charbytes(s, pos) + end + + return length end -- functions identically to string.sub except that i and j are UTF-8 characters -- instead of bytes -local function utf8sub (s, i, j) - -- argument defaults - j = j or -1 - - local pos = 1 - local bytes = len(s) - local length = 0 - - -- only set l if i or j is negative - local l = (i >= 0 and j >= 0) or utf8len(s) - local startChar = (i >= 0) and i or l + i + 1 - local endChar = (j >= 0) and j or l + j + 1 - - -- can't have start before end! - if startChar > endChar then - return "" - end - - -- byte offsets to pass to string.sub - local startByte,endByte = 1,bytes - - while pos <= bytes do - length = length + 1 - - if length == startChar then - startByte = pos - end - - pos = pos + utf8charbytes(s, pos) - - if length == endChar then - endByte = pos - 1 - break - end - end - - if startChar > length then startByte = bytes+1 end - if endChar < 1 then endByte = 0 end - - return sub(s, startByte, endByte) +local function utf8sub(s, i, j) + -- argument defaults + j = j or -1 + + local pos = 1 + local bytes = len(s) + local length = 0 + + -- only set l if i or j is negative + local l = (i >= 0 and j >= 0) or utf8len(s) + local startChar = (i >= 0) and i or l + i + 1 + local endChar = (j >= 0) and j or l + j + 1 + + -- can't have start before end! + if startChar > endChar then + return "" + end + + -- byte offsets to pass to string.sub + local startByte, endByte = 1, bytes + + while pos <= bytes do + length = length + 1 + + if length == startChar then + startByte = pos + end + + pos = pos + utf8charbytes(s, pos) + + if length == endChar then + endByte = pos - 1 + break + end + end + + if startChar > length then + startByte = bytes + 1 + end + if endChar < 1 then + endByte = 0 + end + + return sub(s, startByte, endByte) end --[[ @@ -281,283 +283,295 @@ end ]] -- identical to string.reverse except that it supports UTF-8 -local function utf8reverse (s) - -- argument checking - if type(s) ~= "string" then - error("bad argument #1 to 'utf8reverse' (string expected, got ".. type(s).. ")") - end +local function utf8reverse(s) + -- argument checking + if type(s) ~= "string" then + error("bad argument #1 to 'utf8reverse' (string expected, got " .. type(s) .. ")") + end - local bytes = len(s) - local pos = bytes - local charbytes - local newstr = "" + local bytes = len(s) + local pos = bytes + local charbytes + local newstr = "" - while pos > 0 do - local c = byte(s, pos) - while c >= 128 and c <= 191 do - pos = pos - 1 - c = byte(s, pos) - end + while pos > 0 do + local c = byte(s, pos) + while c >= 128 and c <= 191 do + pos = pos - 1 + c = byte(s, pos) + end - charbytes = utf8charbytes(s, pos) + charbytes = utf8charbytes(s, pos) - newstr = newstr .. sub(s, pos, pos + charbytes - 1) + newstr = newstr .. sub(s, pos, pos + charbytes - 1) - pos = pos - 1 - end + pos = pos - 1 + end - return newstr + return newstr end -- http://en.wikipedia.org/wiki/Utf8 -- http://developer.coronalabs.com/code/utf-8-conversion-utility local function utf8char(unicode) - if unicode <= 0x7F then return char(unicode) end - - if (unicode <= 0x7FF) then - local Byte0 = 0xC0 + math.floor(unicode / 0x40); - local Byte1 = 0x80 + (unicode % 0x40); - return char(Byte0, Byte1); - end; - - if (unicode <= 0xFFFF) then - local Byte0 = 0xE0 + math.floor(unicode / 0x1000); - local Byte1 = 0x80 + (math.floor(unicode / 0x40) % 0x40); - local Byte2 = 0x80 + (unicode % 0x40); - return char(Byte0, Byte1, Byte2); - end; - - if (unicode <= 0x10FFFF) then - local code = unicode - local Byte3= 0x80 + (code % 0x40); - code = math.floor(code / 0x40) - local Byte2= 0x80 + (code % 0x40); - code = math.floor(code / 0x40) - local Byte1= 0x80 + (code % 0x40); - code = math.floor(code / 0x40) - local Byte0= 0xF0 + code; - - return char(Byte0, Byte1, Byte2, Byte3); - end; - - error 'Unicode cannot be greater than U+10FFFF!' + if unicode <= 0x7F then + return char(unicode) + end + + if unicode <= 0x7FF then + local Byte0 = 0xC0 + math.floor(unicode / 0x40) + local Byte1 = 0x80 + (unicode % 0x40) + return char(Byte0, Byte1) + end + + if unicode <= 0xFFFF then + local Byte0 = 0xE0 + math.floor(unicode / 0x1000) + local Byte1 = 0x80 + (math.floor(unicode / 0x40) % 0x40) + local Byte2 = 0x80 + (unicode % 0x40) + return char(Byte0, Byte1, Byte2) + end + + if unicode <= 0x10FFFF then + local code = unicode + local Byte3 = 0x80 + (code % 0x40) + code = math.floor(code / 0x40) + local Byte2 = 0x80 + (code % 0x40) + code = math.floor(code / 0x40) + local Byte1 = 0x80 + (code % 0x40) + code = math.floor(code / 0x40) + local Byte0 = 0xF0 + code + + return char(Byte0, Byte1, Byte2, Byte3) + end + + error("Unicode cannot be greater than U+10FFFF!") end -local shift_6 = 2^6 -local shift_12 = 2^12 -local shift_18 = 2^18 +local shift_6 = 2 ^ 6 +local shift_12 = 2 ^ 12 +local shift_18 = 2 ^ 18 local utf8unicode utf8unicode = function(str, i, j, byte_pos) - i = i or 1 - j = j or i - - if i > j then return end - - local ch,bytes - - if byte_pos then - bytes = utf8charbytes(str,byte_pos) - ch = sub(str,byte_pos,byte_pos-1+bytes) - else - ch,byte_pos = utf8sub(str,i,i), 0 - bytes = #ch - end - - local unicode - - if bytes == 1 then unicode = byte(ch) end - if bytes == 2 then - local byte0,byte1 = byte(ch,1,2) - local code0,code1 = byte0-0xC0,byte1-0x80 - unicode = code0*shift_6 + code1 - end - if bytes == 3 then - local byte0,byte1,byte2 = byte(ch,1,3) - local code0,code1,code2 = byte0-0xE0,byte1-0x80,byte2-0x80 - unicode = code0*shift_12 + code1*shift_6 + code2 - end - if bytes == 4 then - local byte0,byte1,byte2,byte3 = byte(ch,1,4) - local code0,code1,code2,code3 = byte0-0xF0,byte1-0x80,byte2-0x80,byte3-0x80 - unicode = code0*shift_18 + code1*shift_12 + code2*shift_6 + code3 - end - - return unicode,utf8unicode(str, i+1, j, byte_pos+bytes) + i = i or 1 + j = j or i + + if i > j then + return + end + + local ch, bytes + + if byte_pos then + bytes = utf8charbytes(str, byte_pos) + ch = sub(str, byte_pos, byte_pos - 1 + bytes) + else + ch, byte_pos = utf8sub(str, i, i), 0 + bytes = #ch + end + + local unicode + + if bytes == 1 then + unicode = byte(ch) + end + if bytes == 2 then + local byte0, byte1 = byte(ch, 1, 2) + local code0, code1 = byte0 - 0xC0, byte1 - 0x80 + unicode = code0 * shift_6 + code1 + end + if bytes == 3 then + local byte0, byte1, byte2 = byte(ch, 1, 3) + local code0, code1, code2 = byte0 - 0xE0, byte1 - 0x80, byte2 - 0x80 + unicode = code0 * shift_12 + code1 * shift_6 + code2 + end + if bytes == 4 then + local byte0, byte1, byte2, byte3 = byte(ch, 1, 4) + local code0, code1, code2, code3 = byte0 - 0xF0, byte1 - 0x80, byte2 - 0x80, byte3 - 0x80 + unicode = code0 * shift_18 + code1 * shift_12 + code2 * shift_6 + code3 + end + + return unicode, utf8unicode(str, i + 1, j, byte_pos + bytes) end -- Returns an iterator which returns the next substring and its byte interval local function utf8gensub(str, sub_len) - sub_len = sub_len or 1 - local byte_pos = 1 - local length = #str - return function(skip) - if skip then byte_pos = byte_pos + skip end - local char_count = 0 - local start = byte_pos - repeat - if byte_pos > length then return end - char_count = char_count + 1 - local bytes = utf8charbytes(str,byte_pos) - byte_pos = byte_pos+bytes - - until char_count == sub_len - - local last = byte_pos-1 - local slice = sub(str,start,last) - return slice, start, last - end + sub_len = sub_len or 1 + local byte_pos = 1 + local length = #str + return function(skip) + if skip then + byte_pos = byte_pos + skip + end + local char_count = 0 + local start = byte_pos + repeat + if byte_pos > length then + return + end + char_count = char_count + 1 + local bytes = utf8charbytes(str, byte_pos) + byte_pos = byte_pos + bytes + + until char_count == sub_len + + local last = byte_pos - 1 + local slice = sub(str, start, last) + return slice, start, last + end end local function binsearch(sortedTable, item, comp) - local head, tail = 1, #sortedTable - local mid = math.floor((head + tail)/2) - if not comp then - while (tail - head) > 1 do - if sortedTable[tonumber(mid)] > item then - tail = mid - else - head = mid - end - mid = math.floor((head + tail)/2) - end - end - if sortedTable[tonumber(head)] == item then - return true, tonumber(head) - elseif sortedTable[tonumber(tail)] == item then - return true, tonumber(tail) - else - return false - end + local head, tail = 1, #sortedTable + local mid = math.floor((head + tail) / 2) + if not comp then + while (tail - head) > 1 do + if sortedTable[tonumber(mid)] > item then + tail = mid + else + head = mid + end + mid = math.floor((head + tail) / 2) + end + end + if sortedTable[tonumber(head)] == item then + return true, tonumber(head) + elseif sortedTable[tonumber(tail)] == item then + return true, tonumber(tail) + else + return false + end end local function classMatchGenerator(class, plain) - local codes = {} - local ranges = {} - local ignore = false - local range = false - local firstletter = true - local unmatch = false - - local it = utf8gensub(class) - - local skip - for c, _, be in it do - skip = be - if not ignore and not plain then - if c == "%" then - ignore = true - elseif c == "-" then - table.insert(codes, utf8unicode(c)) - range = true - elseif c == "^" then - if not firstletter then - error('!!!') - else - unmatch = true - end - elseif c == ']' then - break - else - if not range then - table.insert(codes, utf8unicode(c)) - else - table.remove(codes) -- removing '-' - table.insert(ranges, {table.remove(codes), utf8unicode(c)}) - range = false - end - end - elseif ignore and not plain then - if c == 'a' then -- %a: represents all letters. (ONLY ASCII) - table.insert(ranges, {65, 90}) -- A - Z - table.insert(ranges, {97, 122}) -- a - z - elseif c == 'c' then -- %c: represents all control characters. - table.insert(ranges, {0, 31}) - table.insert(codes, 127) - elseif c == 'd' then -- %d: represents all digits. - table.insert(ranges, {48, 57}) -- 0 - 9 - elseif c == 'g' then -- %g: represents all printable characters except space. - table.insert(ranges, {1, 8}) - table.insert(ranges, {14, 31}) - table.insert(ranges, {33, 132}) - table.insert(ranges, {134, 159}) - table.insert(ranges, {161, 5759}) - table.insert(ranges, {5761, 8191}) - table.insert(ranges, {8203, 8231}) - table.insert(ranges, {8234, 8238}) - table.insert(ranges, {8240, 8286}) - table.insert(ranges, {8288, 12287}) - elseif c == 'l' then -- %l: represents all lowercase letters. (ONLY ASCII) - table.insert(ranges, {97, 122}) -- a - z - elseif c == 'p' then -- %p: represents all punctuation characters. (ONLY ASCII) - table.insert(ranges, {33, 47}) - table.insert(ranges, {58, 64}) - table.insert(ranges, {91, 96}) - table.insert(ranges, {123, 126}) - elseif c == 's' then -- %s: represents all space characters. - table.insert(ranges, {9, 13}) - table.insert(codes, 32) - table.insert(codes, 133) - table.insert(codes, 160) - table.insert(codes, 5760) - table.insert(ranges, {8192, 8202}) - table.insert(codes, 8232) - table.insert(codes, 8233) - table.insert(codes, 8239) - table.insert(codes, 8287) - table.insert(codes, 12288) - elseif c == 'u' then -- %u: represents all uppercase letters. (ONLY ASCII) - table.insert(ranges, {65, 90}) -- A - Z - elseif c == 'w' then -- %w: represents all alphanumeric characters. (ONLY ASCII) - table.insert(ranges, {48, 57}) -- 0 - 9 - table.insert(ranges, {65, 90}) -- A - Z - table.insert(ranges, {97, 122}) -- a - z - elseif c == 'x' then -- %x: represents all hexadecimal digits. - table.insert(ranges, {48, 57}) -- 0 - 9 - table.insert(ranges, {65, 70}) -- A - F - table.insert(ranges, {97, 102}) -- a - f - else - if not range then - table.insert(codes, utf8unicode(c)) - else - table.remove(codes) -- removing '-' - table.insert(ranges, {table.remove(codes), utf8unicode(c)}) - range = false - end - end - ignore = false - else - if not range then - table.insert(codes, utf8unicode(c)) - else - table.remove(codes) -- removing '-' - table.insert(ranges, {table.remove(codes), utf8unicode(c)}) - range = false - end - ignore = false - end - - firstletter = false - end - - table.sort(codes) - - local function inRanges(charCode) - for _,r in ipairs(ranges) do - if r[1] <= charCode and charCode <= r[2] then - return true - end - end - return false - end - if not unmatch then - return function(charCode) - return binsearch(codes, charCode) or inRanges(charCode) - end, skip - else - return function(charCode) - return charCode ~= -1 and not (binsearch(codes, charCode) or inRanges(charCode)) - end, skip - end + local codes = {} + local ranges = {} + local ignore = false + local range = false + local firstletter = true + local unmatch = false + + local it = utf8gensub(class) + + local skip + for c, _, be in it do + skip = be + if not ignore and not plain then + if c == "%" then + ignore = true + elseif c == "-" then + table.insert(codes, utf8unicode(c)) + range = true + elseif c == "^" then + if not firstletter then + error("!!!") + else + unmatch = true + end + elseif c == "]" then + break + else + if not range then + table.insert(codes, utf8unicode(c)) + else + table.remove(codes) -- removing '-' + table.insert(ranges, { table.remove(codes), utf8unicode(c) }) + range = false + end + end + elseif ignore and not plain then + if c == "a" then -- %a: represents all letters. (ONLY ASCII) + table.insert(ranges, { 65, 90 }) -- A - Z + table.insert(ranges, { 97, 122 }) -- a - z + elseif c == "c" then -- %c: represents all control characters. + table.insert(ranges, { 0, 31 }) + table.insert(codes, 127) + elseif c == "d" then -- %d: represents all digits. + table.insert(ranges, { 48, 57 }) -- 0 - 9 + elseif c == "g" then -- %g: represents all printable characters except space. + table.insert(ranges, { 1, 8 }) + table.insert(ranges, { 14, 31 }) + table.insert(ranges, { 33, 132 }) + table.insert(ranges, { 134, 159 }) + table.insert(ranges, { 161, 5759 }) + table.insert(ranges, { 5761, 8191 }) + table.insert(ranges, { 8203, 8231 }) + table.insert(ranges, { 8234, 8238 }) + table.insert(ranges, { 8240, 8286 }) + table.insert(ranges, { 8288, 12287 }) + elseif c == "l" then -- %l: represents all lowercase letters. (ONLY ASCII) + table.insert(ranges, { 97, 122 }) -- a - z + elseif c == "p" then -- %p: represents all punctuation characters. (ONLY ASCII) + table.insert(ranges, { 33, 47 }) + table.insert(ranges, { 58, 64 }) + table.insert(ranges, { 91, 96 }) + table.insert(ranges, { 123, 126 }) + elseif c == "s" then -- %s: represents all space characters. + table.insert(ranges, { 9, 13 }) + table.insert(codes, 32) + table.insert(codes, 133) + table.insert(codes, 160) + table.insert(codes, 5760) + table.insert(ranges, { 8192, 8202 }) + table.insert(codes, 8232) + table.insert(codes, 8233) + table.insert(codes, 8239) + table.insert(codes, 8287) + table.insert(codes, 12288) + elseif c == "u" then -- %u: represents all uppercase letters. (ONLY ASCII) + table.insert(ranges, { 65, 90 }) -- A - Z + elseif c == "w" then -- %w: represents all alphanumeric characters. (ONLY ASCII) + table.insert(ranges, { 48, 57 }) -- 0 - 9 + table.insert(ranges, { 65, 90 }) -- A - Z + table.insert(ranges, { 97, 122 }) -- a - z + elseif c == "x" then -- %x: represents all hexadecimal digits. + table.insert(ranges, { 48, 57 }) -- 0 - 9 + table.insert(ranges, { 65, 70 }) -- A - F + table.insert(ranges, { 97, 102 }) -- a - f + else + if not range then + table.insert(codes, utf8unicode(c)) + else + table.remove(codes) -- removing '-' + table.insert(ranges, { table.remove(codes), utf8unicode(c) }) + range = false + end + end + ignore = false + else + if not range then + table.insert(codes, utf8unicode(c)) + else + table.remove(codes) -- removing '-' + table.insert(ranges, { table.remove(codes), utf8unicode(c) }) + range = false + end + ignore = false + end + + firstletter = false + end + + table.sort(codes) + + local function inRanges(charCode) + for _, r in ipairs(ranges) do + if r[1] <= charCode and charCode <= r[2] then + return true + end + end + return false + end + if not unmatch then + return function(charCode) + return binsearch(codes, charCode) or inRanges(charCode) + end, + skip + else + return function(charCode) + return charCode ~= -1 and not (binsearch(codes, charCode) or inRanges(charCode)) + end, + skip + end end --[[ @@ -605,311 +619,317 @@ local function utf8subWithBytes (s, i, j, sb) end ]] -local cache = setmetatable({},{ - __mode = 'kv' +local cache = setmetatable({}, { + __mode = "kv", }) -local cachePlain = setmetatable({},{ - __mode = 'kv' +local cachePlain = setmetatable({}, { + __mode = "kv", }) local function matcherGenerator(regex, plain) - local matcher = { - functions = {}, - captures = {} - } - if not plain then - cache[regex] = matcher - else - cachePlain[regex] = matcher - end - local function simple(func) - return function(cC) - if func(cC) then - matcher:nextFunc() - matcher:nextStr() - else - matcher:reset() - end - end - end - local function star(func) - return function(cC) - if func(cC) then - matcher:fullResetOnNextFunc() - matcher:nextStr() - else - matcher:nextFunc() - end - end - end - local function minus(func) - return function(cC) - if func(cC) then - matcher:fullResetOnNextStr() - end - matcher:nextFunc() - end - end - local function question(func) - return function(cC) - if func(cC) then - matcher:fullResetOnNextFunc() - matcher:nextStr() - end - matcher:nextFunc() - end - end - - local function capture(id) - return function(_) - local l = matcher.captures[id][2] - matcher.captures[id][1] - local captured = utf8sub(matcher.string, matcher.captures[id][1], matcher.captures[id][2]) - local check = utf8sub(matcher.string, matcher.str, matcher.str + l) - if captured == check then - for _ = 0, l do - matcher:nextStr() - end - matcher:nextFunc() - else - matcher:reset() - end - end - end - local function captureStart(id) - return function(_) - matcher.captures[id][1] = matcher.str - matcher:nextFunc() - end - end - local function captureStop(id) - return function(_) - matcher.captures[id][2] = matcher.str - 1 - matcher:nextFunc() - end - end - - local function balancer(str) - local sum = 0 - local bc, ec = utf8sub(str, 1, 1), utf8sub(str, 2, 2) - local skip = len(bc) + len(ec) - bc, ec = utf8unicode(bc), utf8unicode(ec) - return function(cC) - if cC == ec and sum > 0 then - sum = sum - 1 - if sum == 0 then - matcher:nextFunc() - end - matcher:nextStr() - elseif cC == bc then - sum = sum + 1 - matcher:nextStr() - else - if sum == 0 or cC == -1 then - sum = 0 - matcher:reset() - else - matcher:nextStr() - end - end - end, skip - end - - matcher.functions[1] = function(_) - matcher:fullResetOnNextStr() - matcher.seqStart = matcher.str - matcher:nextFunc() - if (matcher.str > matcher.startStr and matcher.fromStart) or matcher.str >= matcher.stringLen then - matcher.stop = true - matcher.seqStart = nil - end - end - - local lastFunc - local ignore = false - local skip = nil - local it = (function() - local gen = utf8gensub(regex) - return function() - return gen(skip) - end - end)() - local cs = {} - for c, bs, be in it do - skip = nil - if plain then - table.insert(matcher.functions, simple(classMatchGenerator(c, plain))) - else - if ignore then - if find('123456789', c, 1, true) then - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - lastFunc = nil - end - table.insert(matcher.functions, capture(tonumber(c))) - elseif c == 'b' then - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - lastFunc = nil - end - local b - b, skip = balancer(sub(regex, be + 1, be + 9)) - table.insert(matcher.functions, b) - else - lastFunc = classMatchGenerator('%' .. c) - end - ignore = false - else - if c == '*' then - if lastFunc then - table.insert(matcher.functions, star(lastFunc)) - lastFunc = nil - else - error('invalid regex after ' .. sub(regex, 1, bs)) - end - elseif c == '+' then - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - table.insert(matcher.functions, star(lastFunc)) - lastFunc = nil - else - error('invalid regex after ' .. sub(regex, 1, bs)) - end - elseif c == '-' then - if lastFunc then - table.insert(matcher.functions, minus(lastFunc)) - lastFunc = nil - else - error('invalid regex after ' .. sub(regex, 1, bs)) - end - elseif c == '?' then - if lastFunc then - table.insert(matcher.functions, question(lastFunc)) - lastFunc = nil - else - error('invalid regex after ' .. sub(regex, 1, bs)) - end - elseif c == '^' then - if bs == 1 then - matcher.fromStart = true - else - error('invalid regex after ' .. sub(regex, 1, bs)) - end - elseif c == '$' then - if be == len(regex) then - matcher.toEnd = true - else - error('invalid regex after ' .. sub(regex, 1, bs)) - end - elseif c == '[' then - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - end - lastFunc, skip = classMatchGenerator(sub(regex, be + 1)) - elseif c == '(' then - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - lastFunc = nil - end - table.insert(matcher.captures, {}) - table.insert(cs, #matcher.captures) - table.insert(matcher.functions, captureStart(cs[#cs])) - if sub(regex, be + 1, be + 1) == ')' then matcher.captures[#matcher.captures].empty = true end - elseif c == ')' then - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - lastFunc = nil - end - local cap = table.remove(cs) - if not cap then - error('invalid capture: "(" missing') - end - table.insert(matcher.functions, captureStop(cap)) - elseif c == '.' then - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - end - lastFunc = function(cC) return cC ~= -1 end - elseif c == '%' then - ignore = true - else - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - end - lastFunc = classMatchGenerator(c) - end - end - end - end - if #cs > 0 then - error('invalid capture: ")" missing') - end - if lastFunc then - table.insert(matcher.functions, simple(lastFunc)) - end - - table.insert(matcher.functions, function() - if matcher.toEnd and matcher.str ~= matcher.stringLen then - matcher:reset() - else - matcher.stop = true - end - end) - - matcher.nextFunc = function(self) - self.func = self.func + 1 - end - matcher.nextStr = function(self) - self.str = self.str + 1 - end - matcher.strReset = function(self) - local oldReset = self.reset - local str = self.str - self.reset = function(s) - s.str = str - s.reset = oldReset - end - end - matcher.fullResetOnNextFunc = function(self) - local oldReset = self.reset - local func = self.func +1 - local str = self.str - self.reset = function(s) - s.func = func - s.str = str - s.reset = oldReset - end - end - matcher.fullResetOnNextStr = function(self) - local oldReset = self.reset - local str = self.str + 1 - local func = self.func - self.reset = function(s) - s.func = func - s.str = str - s.reset = oldReset - end - end - - matcher.process = function(self, str, start) - - self.func = 1 - start = start or 1 - self.startStr = (start >= 0) and start or utf8len(str) + start + 1 - self.seqStart = self.startStr - self.str = self.startStr - self.stringLen = utf8len(str) + 1 - self.string = str - self.stop = false - - self.reset = function(s) - s.func = 1 - end - - -- local lastPos = self.str - -- local lastByte - local ch - while not self.stop do - if self.str < self.stringLen then - --[[ if lastPos < self.str then + local matcher = { + functions = {}, + captures = {}, + } + if not plain then + cache[regex] = matcher + else + cachePlain[regex] = matcher + end + local function simple(func) + return function(cC) + if func(cC) then + matcher:nextFunc() + matcher:nextStr() + else + matcher:reset() + end + end + end + local function star(func) + return function(cC) + if func(cC) then + matcher:fullResetOnNextFunc() + matcher:nextStr() + else + matcher:nextFunc() + end + end + end + local function minus(func) + return function(cC) + if func(cC) then + matcher:fullResetOnNextStr() + end + matcher:nextFunc() + end + end + local function question(func) + return function(cC) + if func(cC) then + matcher:fullResetOnNextFunc() + matcher:nextStr() + end + matcher:nextFunc() + end + end + + local function capture(id) + return function(_) + local l = matcher.captures[id][2] - matcher.captures[id][1] + local captured = utf8sub(matcher.string, matcher.captures[id][1], matcher.captures[id][2]) + local check = utf8sub(matcher.string, matcher.str, matcher.str + l) + if captured == check then + for _ = 0, l do + matcher:nextStr() + end + matcher:nextFunc() + else + matcher:reset() + end + end + end + local function captureStart(id) + return function(_) + matcher.captures[id][1] = matcher.str + matcher:nextFunc() + end + end + local function captureStop(id) + return function(_) + matcher.captures[id][2] = matcher.str - 1 + matcher:nextFunc() + end + end + + local function balancer(str) + local sum = 0 + local bc, ec = utf8sub(str, 1, 1), utf8sub(str, 2, 2) + local skip = len(bc) + len(ec) + bc, ec = utf8unicode(bc), utf8unicode(ec) + return function(cC) + if cC == ec and sum > 0 then + sum = sum - 1 + if sum == 0 then + matcher:nextFunc() + end + matcher:nextStr() + elseif cC == bc then + sum = sum + 1 + matcher:nextStr() + else + if sum == 0 or cC == -1 then + sum = 0 + matcher:reset() + else + matcher:nextStr() + end + end + end, + skip + end + + matcher.functions[1] = function(_) + matcher:fullResetOnNextStr() + matcher.seqStart = matcher.str + matcher:nextFunc() + if + (matcher.str > matcher.startStr and matcher.fromStart) or matcher.str >= matcher.stringLen + then + matcher.stop = true + matcher.seqStart = nil + end + end + + local lastFunc + local ignore = false + local skip = nil + local it = (function() + local gen = utf8gensub(regex) + return function() + return gen(skip) + end + end)() + local cs = {} + for c, bs, be in it do + skip = nil + if plain then + table.insert(matcher.functions, simple(classMatchGenerator(c, plain))) + else + if ignore then + if find("123456789", c, 1, true) then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + lastFunc = nil + end + table.insert(matcher.functions, capture(tonumber(c))) + elseif c == "b" then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + lastFunc = nil + end + local b + b, skip = balancer(sub(regex, be + 1, be + 9)) + table.insert(matcher.functions, b) + else + lastFunc = classMatchGenerator("%" .. c) + end + ignore = false + else + if c == "*" then + if lastFunc then + table.insert(matcher.functions, star(lastFunc)) + lastFunc = nil + else + error("invalid regex after " .. sub(regex, 1, bs)) + end + elseif c == "+" then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + table.insert(matcher.functions, star(lastFunc)) + lastFunc = nil + else + error("invalid regex after " .. sub(regex, 1, bs)) + end + elseif c == "-" then + if lastFunc then + table.insert(matcher.functions, minus(lastFunc)) + lastFunc = nil + else + error("invalid regex after " .. sub(regex, 1, bs)) + end + elseif c == "?" then + if lastFunc then + table.insert(matcher.functions, question(lastFunc)) + lastFunc = nil + else + error("invalid regex after " .. sub(regex, 1, bs)) + end + elseif c == "^" then + if bs == 1 then + matcher.fromStart = true + else + error("invalid regex after " .. sub(regex, 1, bs)) + end + elseif c == "$" then + if be == len(regex) then + matcher.toEnd = true + else + error("invalid regex after " .. sub(regex, 1, bs)) + end + elseif c == "[" then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + end + lastFunc, skip = classMatchGenerator(sub(regex, be + 1)) + elseif c == "(" then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + lastFunc = nil + end + table.insert(matcher.captures, {}) + table.insert(cs, #matcher.captures) + table.insert(matcher.functions, captureStart(cs[#cs])) + if sub(regex, be + 1, be + 1) == ")" then + matcher.captures[#matcher.captures].empty = true + end + elseif c == ")" then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + lastFunc = nil + end + local cap = table.remove(cs) + if not cap then + error('invalid capture: "(" missing') + end + table.insert(matcher.functions, captureStop(cap)) + elseif c == "." then + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + end + lastFunc = function(cC) + return cC ~= -1 + end + elseif c == "%" then + ignore = true + else + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + end + lastFunc = classMatchGenerator(c) + end + end + end + end + if #cs > 0 then + error('invalid capture: ")" missing') + end + if lastFunc then + table.insert(matcher.functions, simple(lastFunc)) + end + + table.insert(matcher.functions, function() + if matcher.toEnd and matcher.str ~= matcher.stringLen then + matcher:reset() + else + matcher.stop = true + end + end) + + matcher.nextFunc = function(self) + self.func = self.func + 1 + end + matcher.nextStr = function(self) + self.str = self.str + 1 + end + matcher.strReset = function(self) + local oldReset = self.reset + local str = self.str + self.reset = function(s) + s.str = str + s.reset = oldReset + end + end + matcher.fullResetOnNextFunc = function(self) + local oldReset = self.reset + local func = self.func + 1 + local str = self.str + self.reset = function(s) + s.func = func + s.str = str + s.reset = oldReset + end + end + matcher.fullResetOnNextStr = function(self) + local oldReset = self.reset + local str = self.str + 1 + local func = self.func + self.reset = function(s) + s.func = func + s.str = str + s.reset = oldReset + end + end + + matcher.process = function(self, str, start) + self.func = 1 + start = start or 1 + self.startStr = (start >= 0) and start or utf8len(str) + start + 1 + self.seqStart = self.startStr + self.str = self.startStr + self.stringLen = utf8len(str) + 1 + self.string = str + self.stop = false + + self.reset = function(s) + s.func = 1 + end + + -- local lastPos = self.str + -- local lastByte + local ch + while not self.stop do + if self.str < self.stringLen then + --[[ if lastPos < self.str then print('last byte', lastByte) ch, lastByte = utf8subWithBytes(str, 1, self.str - lastPos - 1, lastByte) ch, lastByte = utf8subWithBytes(str, 1, 1, lastByte) @@ -918,114 +938,113 @@ local function matcherGenerator(regex, plain) ch, lastByte = utf8subWithBytes(str, self.str, self.str) end lastPos = self.str ]] - ch = utf8sub(str, self.str,self.str) - --print('char', ch, utf8unicode(ch)) - self.functions[self.func](utf8unicode(ch)) - else - self.functions[self.func](-1) - end - end - - if self.seqStart then - local captures = {} - for _,pair in pairs(self.captures) do - if pair.empty then - table.insert(captures, pair[1]) - else - table.insert(captures, utf8sub(str, pair[1], pair[2])) - end - end - return self.seqStart, self.str - 1, unpack(captures) - end -end - -return matcher + ch = utf8sub(str, self.str, self.str) + --print('char', ch, utf8unicode(ch)) + self.functions[self.func](utf8unicode(ch)) + else + self.functions[self.func](-1) + end + end + + if self.seqStart then + local captures = {} + for _, pair in pairs(self.captures) do + if pair.empty then + table.insert(captures, pair[1]) + else + table.insert(captures, utf8sub(str, pair[1], pair[2])) + end + end + return self.seqStart, self.str - 1, unpack(captures) + end + end + + return matcher end -- string.find local function utf8find(str, regex, init, plain) -local matcher = cache[regex] or matcherGenerator(regex, plain) -return matcher:process(str, init) + local matcher = cache[regex] or matcherGenerator(regex, plain) + return matcher:process(str, init) end -- string.match local function utf8match(str, regex, init) -init = init or 1 -local found = {utf8find(str, regex, init)} -if found[1] then - if found[3] then - return unpack(found, 3) - end - return utf8sub(str, found[1], found[2]) -end + init = init or 1 + local found = { utf8find(str, regex, init) } + if found[1] then + if found[3] then + return unpack(found, 3) + end + return utf8sub(str, found[1], found[2]) + end end -- string.gmatch local function utf8gmatch(str, regex, all) -regex = (utf8sub(regex,1,1) ~= '^') and regex or '%' .. regex -local lastChar = 1 -return function() - local found = {utf8find(str, regex, lastChar)} - if found[1] then - lastChar = found[2] + 1 - if found[all and 1 or 3] then - return unpack(found, all and 1 or 3) - end - return utf8sub(str, found[1], found[2]) - end -end + regex = (utf8sub(regex, 1, 1) ~= "^") and regex or "%" .. regex + local lastChar = 1 + return function() + local found = { utf8find(str, regex, lastChar) } + if found[1] then + lastChar = found[2] + 1 + if found[all and 1 or 3] then + return unpack(found, all and 1 or 3) + end + return utf8sub(str, found[1], found[2]) + end + end end local function replace(repl, args) -local ret = '' -if type(repl) == 'string' then - local ignore = false - local num - for c in utf8gensub(repl) do - if not ignore then - if c == '%' then - ignore = true - else - ret = ret .. c - end - else - num = tonumber(c) - if num then - ret = ret .. args[num] - else - ret = ret .. c - end - ignore = false - end - end -elseif type(repl) == 'table' then - ret = repl[args[1] or args[0]] or '' -elseif type(repl) == 'function' then - if #args > 0 then - ret = repl(unpack(args, 1)) or '' - else - ret = repl(args[0]) or '' - end -end -return ret + local ret = "" + if type(repl) == "string" then + local ignore = false + local num + for c in utf8gensub(repl) do + if not ignore then + if c == "%" then + ignore = true + else + ret = ret .. c + end + else + num = tonumber(c) + if num then + ret = ret .. args[num] + else + ret = ret .. c + end + ignore = false + end + end + elseif type(repl) == "table" then + ret = repl[args[1] or args[0]] or "" + elseif type(repl) == "function" then + if #args > 0 then + ret = repl(unpack(args, 1)) or "" + else + ret = repl(args[0]) or "" + end + end + return ret end -- string.gsub local function utf8gsub(str, regex, repl, limit) -limit = limit or -1 -local ret = '' -local prevEnd = 1 -local it = utf8gmatch(str, regex, true) -local found = {it()} -local n = 0 -while #found > 0 and limit ~= n do - local args = {[0] = utf8sub(str, found[1], found[2]), unpack(found, 3)} - ret = ret .. utf8sub(str, prevEnd, found[1] - 1) - .. replace(repl, args) - prevEnd = found[2] + 1 - n = n + 1 - found = {it()} -end -return ret .. utf8sub(str, prevEnd), n + limit = limit or -1 + local ret = "" + local prevEnd = 1 + local it = utf8gmatch(str, regex, true) + local found = { it() } + local n = 0 + while #found > 0 and limit ~= n do + local args = { [0] = utf8sub(str, found[1], found[2]), unpack(found, 3) } + ret = ret .. utf8sub(str, prevEnd, found[1] - 1) .. replace(repl, args) + prevEnd = found[2] + 1 + n = n + 1 + found = { it() } + end + return ret .. utf8sub(str, prevEnd), n end -- EXPORT @@ -1033,52 +1052,52 @@ end local M = {} function M.len(s) - return utf8len(s) + return utf8len(s) end function M.sub(s, i, j) - return utf8sub(s, i, j) + return utf8sub(s, i, j) end function M.reverse(s) - return utf8reverse(s) + return utf8reverse(s) end function M.char(unicode) - return utf8char(unicode) + return utf8char(unicode) end function M.unicode(s, i, j) - return utf8unicode(s, i, j) + return utf8unicode(s, i, j) end function M.gensub(s, sub_len) - return utf8gensub(s, sub_len) + return utf8gensub(s, sub_len) end function M.byte(s, i, j) - return utf8unicode(s, i, j) + return utf8unicode(s, i, j) end function M.find(str, regex, init, plain) - return utf8find(str, regex, init, plain) + return utf8find(str, regex, init, plain) end function M.match(str, regex, init) - return utf8match(str, regex, init) + return utf8match(str, regex, init) end function M.gmatch(str, regex, all) - return utf8gmatch(str, regex, all) + return utf8gmatch(str, regex, all) end function M.gsub(str, regex, repl, limit) - return utf8gsub(str, regex, repl, limit) + return utf8gsub(str, regex, repl, limit) end function M.dump(s) - return dump(s) + return dump(s) end function M.format(s) - return format(s) + return format(s) end function M.lower(s) - return lower(s) + return lower(s) end function M.upper(s) - return upper(s) + return upper(s) end function M.rep(s) - return rep(s) + return rep(s) end return M diff --git a/lua/fzf-lua/libuv.lua b/lua/fzf-lua/libuv.lua index 4d253a60e..843e05290 100644 --- a/lua/fzf-lua/libuv.lua +++ b/lua/fzf-lua/libuv.lua @@ -11,7 +11,9 @@ local base64 = require("fzf-lua.lib.base64") local serpent = require("fzf-lua.lib.serpent") local function process_kill(pid, signal) - if not pid or not tonumber(pid) then return false end + if not pid or not tonumber(pid) then + return false + end if type(uv.os_getpriority(pid)) == "number" then uv.kill(pid, signal or 9) return true @@ -59,14 +61,20 @@ M.spawn = function(opts, fn_transform, fn_done) local write_cb_count, on_exit_called = 0, nil local prev_line_content = nil - if opts.fn_transform then fn_transform = opts.fn_transform end + if opts.fn_transform then + fn_transform = opts.fn_transform + end local finish = function(code, sig, from, pid) -- Uncomment to debug pipe closure timing issues (#1521) -- output_pipe:close(function() print("closed o") end) -- error_pipe:close(function() print("closed e") end) - if not output_pipe:is_closing() then output_pipe:close() end - if not error_pipe:is_closing() then error_pipe:close() end + if not output_pipe:is_closing() then + output_pipe:close() + end + if not error_pipe:is_closing() then + error_pipe:close() + end if opts.cb_finish then opts.cb_finish(code, sig, from, pid) end @@ -123,7 +131,9 @@ M.spawn = function(opts, fn_transform, fn_done) end) -- save current process pid - if opts.cb_pid then opts.cb_pid(pid) end + if opts.cb_pid then + opts.cb_pid(pid) + end local function write_cb(data) write_cb_count = write_cb_count + 1 @@ -166,7 +176,9 @@ M.spawn = function(opts, fn_transform, fn_done) local nlines = 0 local start_idx = 1 local t_st = opts.profiler and uv.hrtime() - if t_st then write_cb(string.format("[DEBUG] start: %.0f (ns)" .. EOL, t_st)) end + if t_st then + write_cb(string.format("[DEBUG] start: %.0f (ns)" .. EOL, t_st)) + end repeat local nl_idx = data:find("\n", start_idx, true) if nl_idx then @@ -201,11 +213,19 @@ M.spawn = function(opts, fn_transform, fn_done) -- calling 'write_cb' for every line after 'fn_transform', we therefore only use -- `process1` when using "mini.icons" as `vim.filetype.match` causes a signigicant -- delay and having to wait for all lines to be processed has an apparent lag - if #lines > 0 then write_cb(table.concat(lines, EOL) .. EOL) end + if #lines > 0 then + write_cb(table.concat(lines, EOL) .. EOL) + end if t_st then local t_e = vim.uv.hrtime() - write_cb(string.format("[DEBUG] finish:%.0f (ns) %d lines took %.0f (ms)" .. EOL, - t_e, nlines, (t_e - t_st) / 1e6)) + write_cb( + string.format( + "[DEBUG] finish:%.0f (ns) %d lines took %.0f (ms)" .. EOL, + t_e, + nlines, + (t_e - t_st) / 1e6 + ) + ) end end end @@ -293,7 +313,9 @@ M.spawn_stdio = function(opts, fn_transform_str, fn_preprocess_str, fn_postproce ---@param str string|table ---@return string|table local base64_conditional_decode = function(str) - if opts._base64 == false or type(str) ~= "string" then return str end + if opts._base64 == false or type(str) ~= "string" then + return str + end local ok, decoded = pcall(base64.decode, str) return ok and decoded or str end @@ -301,10 +323,14 @@ M.spawn_stdio = function(opts, fn_transform_str, fn_preprocess_str, fn_postproce ---@param fn_str string ---@return function? local function load_fn(fn_str) - if type(fn_str) ~= "string" then return end + if type(fn_str) ~= "string" then + return + end local fn_loaded = nil local fn = loadstring(fn_str) - if fn then fn_loaded = fn() end + if fn then + fn_loaded = fn() + end if type(fn_loaded) ~= "function" then fn_loaded = nil end @@ -330,12 +356,11 @@ M.spawn_stdio = function(opts, fn_transform_str, fn_preprocess_str, fn_postproce -- rendering issues on Mac (#316, #287) and Linux (#414) -- switch 'stderr' stream to 'line' buffering -- https://www.lua.org/manual/5.2/manual.html#pdf-file%3asetvbuf - io.stderr:setvbuf "line" + io.stderr:setvbuf("line") -- redirect 'stderr' to 'stdout' on Macs by default -- only takes effect if 'opts.stderr' was not set - if opts.stderr_to_stdout == nil and - uv.os_uname().sysname == "Darwin" then + if opts.stderr_to_stdout == nil and uv.os_uname().sysname == "Darwin" then opts.stderr_to_stdout = true end @@ -351,9 +376,10 @@ M.spawn_stdio = function(opts, fn_transform_str, fn_preprocess_str, fn_postproce local fn_preprocess = load_fn(fn_preprocess_str) local fn_postprocess = load_fn(fn_postprocess_str) - -- run the preprocessing fn - if fn_preprocess then fn_preprocess(opts) end + if fn_preprocess then + fn_preprocess(opts) + end if opts.cmd and opts.cmd:match("%-%-color[=%s]+never") then -- perf: skip stripping ansi coloring in `make_file.entry` @@ -383,12 +409,16 @@ M.spawn_stdio = function(opts, fn_transform_str, fn_preprocess_str, fn_postproce end local function exit(exit_code, msg) - if msg then stderr_write(msg) end + if msg then + stderr_write(msg) + end os.exit(exit_code) end local function pipe_open(pipename) - if not pipename then return end + if not pipename then + return + end local fd = uv.fs_open(pipename, "w", -1) if type(fd) ~= "number" then exit(1, ("error opening '%s': %s" .. EOL):format(pipename, fd)) @@ -405,18 +435,21 @@ M.spawn_stdio = function(opts, fn_transform_str, fn_preprocess_str, fn_postproce end local function pipe_write(pipe, data, cb) - if not pipe or pipe:is_closing() then return end - pipe:write(data, - function(err) - -- if the user cancels the call prematurely with - -- , err will be either EPIPE or ECANCELED - -- don't really need to do anything since the - -- processes will be killed anyways with os.exit() - if err then - stderr_write(("pipe:write error: %s" .. EOL):format(err)) - end - if cb then cb(err) end - end) + if not pipe or pipe:is_closing() then + return + end + pipe:write(data, function(err) + -- if the user cancels the call prematurely with + -- , err will be either EPIPE or ECANCELED + -- don't really need to do anything since the + -- processes will be killed anyways with os.exit() + if err then + stderr_write(("pipe:write error: %s" .. EOL):format(err)) + end + if cb then + cb(err) + end + end) end if type(opts.stderr) == "string" then @@ -426,71 +459,71 @@ M.spawn_stdio = function(opts, fn_transform_str, fn_preprocess_str, fn_postproce stdout = pipe_open(opts.stdout) end - local on_finish = opts.on_finish or - function(code) - pipe_close(stdout) - pipe_close(stderr) - if fn_postprocess then - vim.schedule(function() - fn_postprocess(opts) - exit(code) - end) - else + local on_finish = opts.on_finish + or function(code) + pipe_close(stdout) + pipe_close(stderr) + if fn_postprocess then + vim.schedule(function() + fn_postprocess(opts) exit(code) - end + end) + else + exit(code) end + end - local on_write = opts.on_write or - function(data, cb) - if stdout then - pipe_write(stdout, data, cb) + local on_write = opts.on_write + or function(data, cb) + if stdout then + pipe_write(stdout, data, cb) + else + -- on success: rc=true, err=nil + -- on failure: rc=nil, err="Broken pipe" + -- cb with an err ends the process + local rc, err = io.stdout:write(data) + if not rc then + stderr_write(("io.stdout:write error: %s" .. EOL):format(err)) + cb(err or true) else - -- on success: rc=true, err=nil - -- on failure: rc=nil, err="Broken pipe" - -- cb with an err ends the process - local rc, err = io.stdout:write(data) - if not rc then - stderr_write(("io.stdout:write error: %s" .. EOL):format(err)) - cb(err or true) - else - cb(nil) - end + cb(nil) end end + end - local on_err = opts.on_err or - function(data) - if stderr then - pipe_write(stderr, data) - elseif opts.stderr ~= false then - if opts.stderr_to_stdout then - io.stdout:write(data) - else - io.stderr:write(data) - end + local on_err = opts.on_err + or function(data) + if stderr then + pipe_write(stderr, data) + elseif opts.stderr ~= false then + if opts.stderr_to_stdout then + io.stdout:write(data) + else + io.stderr:write(data) end end + end return M.spawn({ - cwd = opts.cwd, - cmd = opts.cmd, - cb_finish = on_finish, - cb_write = on_write, - cb_err = on_err, - process1 = opts.process1, - profiler = opts.profiler, - EOL = EOL, - }, - fn_transform and function(x) - return fn_transform(x, opts) - end) + cwd = opts.cwd, + cmd = opts.cmd, + cb_finish = on_finish, + cb_write = on_write, + cb_err = on_err, + process1 = opts.process1, + profiler = opts.profiler, + EOL = EOL, + }, fn_transform and function(x) + return fn_transform(x, opts) + end) end - M.is_escaped = function(s, is_win) local m -- test spec override - if is_win == nil then is_win = _is_win end + if is_win == nil then + is_win = _is_win + end if is_win then m = s:match([[^".*"$]]) or s:match([[^%^".*%^"$]]) else @@ -584,7 +617,7 @@ M.shellescape = function(s, win_style) -- although we currently only transfer 1 caret, the below -- can handle any number of carets with the regex [[\-%^-"]] local carets = x:match("%^+") or "" - x = carets .. string.rep([[\]], #x - #(carets)) .. x:gsub("%^+", "") + x = carets .. string.rep([[\]], #x - #carets) .. x:gsub("%^+", "") return x end) -- escape all windows metacharacters but quotes @@ -646,13 +679,18 @@ end -- isn't a backslash, test with: -- fzf --disabled --height 30% --preview-window up --preview "echo {q}" M.unescape_fzf = function(s, fzf_version, is_win) - if is_win == nil then is_win = _is_win end - if not is_win then return s end - if tonumber(fzf_version) and tonumber(fzf_version) >= 0.52 then return s end + if is_win == nil then + is_win = _is_win + end + if not is_win then + return s + end + if tonumber(fzf_version) and tonumber(fzf_version) >= 0.52 then + return s + end local ret = s:gsub("\\+[^\\]", function(x) local bslash_num = #x:match([[\+]]) - return string.rep([[\]], - bslash_num == 1 and bslash_num or bslash_num / 2) .. x:sub(-1) + return string.rep([[\]], bslash_num == 1 and bslash_num or bslash_num / 2) .. x:sub(-1) end) return ret end @@ -663,9 +701,15 @@ end -- {q} being sent via the reload action as the initial command -- TODO: better solution for these stupid hacks (upstream issues?) M.escape_fzf = function(s, fzf_version, is_win) - if is_win == nil then is_win = _is_win end - if not is_win then return s end - if tonumber(fzf_version) and tonumber(fzf_version) >= 0.52 then return s end + if is_win == nil then + is_win = _is_win + end + if not is_win then + return s + end + if tonumber(fzf_version) and tonumber(fzf_version) >= 0.52 then + return s + end local ret = s:gsub("\\+[^\\]", function(x) local bslash_num = #x:match([[\+]]) return string.rep([[\]], bslash_num * 2) .. x:sub(-1) @@ -694,7 +738,9 @@ M.wrap_spawn_stdio = function(opts, fn_transform, fn_preprocess, fn_postprocess) local nvim_bin = os.getenv("FZF_LUA_NVIM_BIN") or vim.v.progpath local cmd_str = ("%s -u NONE -l %s %s"):format( M.shellescape(_is_win and vim.fs.normalize(nvim_bin) or nvim_bin), - M.shellescape(vim.fn.fnamemodify(_is_win and vim.fs.normalize(__FILE__) or __FILE__, ":h") .. "/spawn.lua"), + M.shellescape( + vim.fn.fnamemodify(_is_win and vim.fs.normalize(__FILE__) or __FILE__, ":h") .. "/spawn.lua" + ), M.shellescape(("return %s,%s,%s,%s"):format(opts, fn_transform, fn_preprocess, fn_postprocess)) ) return cmd_str diff --git a/lua/fzf-lua/make_entry.lua b/lua/fzf-lua/make_entry.lua index d42e04231..cc1712b1b 100644 --- a/lua/fzf-lua/make_entry.lua +++ b/lua/fzf-lua/make_entry.lua @@ -1,17 +1,19 @@ local M = {} local uv = vim.uv or vim.loop -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local libuv = require "fzf-lua.libuv" -local devicons = require "fzf-lua.devicons" +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local libuv = require("fzf-lua.libuv") +local devicons = require("fzf-lua.devicons") local config = nil -- attempt to load the current config -- should fail if we're running headless do local ok, module = pcall(require, "fzf-lua.config") - if ok then config = module end + if ok then + config = module + end end local function load_config_section(s, datatype, optional) @@ -44,8 +46,9 @@ local function load_config_section(s, datatype, optional) ---@diagnostic disable-next-line: undefined-field if _G._debug == "v" or _G._debug == "verbose" then ---@diagnostic disable-next-line: undefined-field - io.stdout:write(("[DEBUG] [load_config] %s = %s" .. (_G._EOL or "\n")) - :format(s, not ok and errmsg or res)) + io.stdout:write( + ("[DEBUG] [load_config] %s = %s" .. (_G._EOL or "\n")):format(s, not ok and errmsg or res) + ) end if not ok and not optional then io.stderr:write(("Error loading remote config section '%s': %s\n"):format(s, errmsg)) @@ -58,17 +61,22 @@ end if _G._fzf_lua_is_headless then local _config = { globals = { git = {}, files = {}, grep = {} } } _config.globals.git.icons = load_config_section("globals.git.icons", "table") or {} - _config.globals.files.git_status_cmd = - load_config_section("globals.files.git_status_cmd", "table") - or { "git", "-c", "color.status=false", "--no-optional-locks", "status", "--porcelain=v1" } + _config.globals.files.git_status_cmd = load_config_section( + "globals.files.git_status_cmd", + "table" + ) or { "git", "-c", "color.status=false", "--no-optional-locks", "status", "--porcelain=v1" } -- prioritize `opts.rg_glob_fn` over globals - _config.globals.grep.rg_glob_fn = - load_config_section("__resume_data.opts.rg_glob_fn", "function", true) or - load_config_section("globals.grep.rg_glob_fn", "function", true) + _config.globals.grep.rg_glob_fn = load_config_section( + "__resume_data.opts.rg_glob_fn", + "function", + true + ) or load_config_section("globals.grep.rg_glob_fn", "function", true) _config.globals.nbsp = load_config_section("globals.nbsp", "string") - if _config.globals.nbsp then utils.nbsp = _config.globals.nbsp end + if _config.globals.nbsp then + utils.nbsp = _config.globals.nbsp + end config = _config end @@ -76,14 +84,18 @@ end M.get_diff_files = function(opts) local diff_files = {} local cmd = opts.git_status_cmd or config.globals.files.git_status_cmd - if not cmd then return {} end + if not cmd then + return {} + end local start = uv.hrtime() local ok, status, err = pcall(utils.io_systemlist, path.git_cwd(cmd, opts)) local seconds = (uv.hrtime() - start) / 1e9 if seconds >= 0.5 and opts.silent ~= true then - local exec_str = string.format([[require"fzf-lua".utils.warn(]] .. - [["'git status' took %.2f seconds, consider using `git_icons=false` in this repository or use `silent=true` to supress this message.")]] - , seconds) + local exec_str = string.format( + [[require"fzf-lua".utils.warn(]] + .. [["'git status' took %.2f seconds, consider using `git_icons=false` in this repository or use `silent=true` to supress this message.")]], + seconds + ) if not _G._fzf_lua_is_headless then loadstring(exec_str)() else @@ -139,7 +151,7 @@ end M.rg_insert_args = function(cmd, args, relocate_pattern) local patterns = {} for _, a in ipairs({ - { "%s+%-e", "-e" }, + { "%s+%-e", "-e" }, { "%s+%-%-", "--" }, }) do -- if pattern was specified search for `-e ` @@ -204,7 +216,7 @@ M.preprocess = function(opts) -- For custom command transformations (#1927) opts.fn_transform_cmd = - load_config_section("__resume_data.opts.fn_transform_cmd", "function", true) + load_config_section("__resume_data.opts.fn_transform_cmd", "function", true) -- did the caller request rg with glob support? -- manipulation needs to be done before the argv replacement @@ -231,11 +243,10 @@ M.preprocess = function(opts) -- nifty hack to avoid having to double escape quotations -- see my comment inside 'live_grep' initial_command code if opts.argv_expr then - opts.cmd = opts.cmd:gsub("{argv.*}", - function(x) - local idx = x:match("{argv(.*)}") - return libuv.shellescape(argv(idx, not opts.rg_glob and opts.debug)) - end) + opts.cmd = opts.cmd:gsub("{argv.*}", function(x) + local idx = x:match("{argv(.*)}") + return libuv.shellescape(argv(idx, not opts.rg_glob and opts.debug)) + end) end if utils.__IS_WINDOWS and opts.cmd:match("!") then @@ -295,20 +306,25 @@ M.postprocess = function(opts) end M.lcol = function(entry, opts) - if not entry then return nil end - local hl_colnr = utils.tbl_contains(opts._cached_hls or {}, "path_colnr") - and opts.hls.path_colnr or "blue" + if not entry then + return nil + end + local hl_colnr = utils.tbl_contains(opts._cached_hls or {}, "path_colnr") and opts.hls.path_colnr + or "blue" local hl_linenr = utils.tbl_contains(opts._cached_hls or {}, "path_linenr") - and opts.hls.path_linenr or "green" + and opts.hls.path_linenr + or "green" local filename = entry.filename or vim.api.nvim_buf_get_name(entry.bufnr) - return string.format("%s:%s%s%s", + return string.format( + "%s:%s%s%s", -- uncomment to test URIs -- "file://" .. filename, filename, --utils.ansi_codes.magenta(filename), tonumber(entry.lnum) == nil and "" or (utils.ansi_codes[hl_linenr](tostring(entry.lnum)) .. ":"), tonumber(entry.col) == nil and "" or (utils.ansi_codes[hl_colnr](tostring(entry.col)) .. ":"), type(entry.text) ~= "string" and "" - or (" " .. (opts and opts.trim_entry and vim.trim(entry.text) or entry.text))) + or (" " .. (opts and opts.trim_entry and vim.trim(entry.text) or entry.text)) + ) end ---@param x string @@ -379,15 +395,20 @@ M.file = function(x, opts) -- save a copy for git indicator and icon lookups local origpath = filepath if opts.path_shorten then - filepath = path.shorten(filepath, tonumber(opts.path_shorten), + filepath = path.shorten( + filepath, + tonumber(opts.path_shorten), -- On Windows we want to shorten using the separator used by the `cwd` arg -- otherwise we might have issues "lenghening" as in the case of git which -- uses normalized paths (using /) for `rev-parse --show-toplevel` and `ls-files` - utils.__IS_WINDOWS and opts.cwd and path.separator(opts.cwd)) + utils.__IS_WINDOWS + and opts.cwd + and path.separator(opts.cwd) + ) end if opts.git_icons then local diff_info = opts.diff_files - and opts.diff_files[utils._if_win(path.normalize(origpath), origpath)] + and opts.diff_files[utils._if_win(path.normalize(origpath), origpath)] local indicators = diff_info and diff_info[1] or " " for i = 1, #indicators do icon = indicators:sub(i, i) @@ -420,7 +441,7 @@ M.file = function(x, opts) -- filename is ansi escape colored, replace the inner string (#819) -- escape `%` in path, since `string.gsub` also use it in target (#1443) and file_part:gsub(utils.lua_regex_escape(stripped_filepath), (filepath:gsub("%%", "%%%%"))) - or filepath + or filepath end -- multiline is only enabled with grep-like output PATH:LINE:COL: if opts.multiline and rest_of_line then @@ -429,12 +450,9 @@ M.file = function(x, opts) -- PATH:LINE:TEXT and PATH:LINE:COL:TEXT local ansi_num = "[%[%d;m]" local filespec = rest_of_line:match(string.format("^:%s-:%s-:", ansi_num, ansi_num)) - or rest_of_line:match(string.format("^:%s-:", ansi_num)) + or rest_of_line:match(string.format("^:%s-:", ansi_num)) if filespec then - rest_of_line = filespec - .. "\n" - .. string.rep(" ", 4) - .. rest_of_line:sub(#filespec + 1) + rest_of_line = filespec .. "\n" .. string.rep(" ", 4) .. rest_of_line:sub(#filespec + 1) end end ret[#ret + 1] = rest_of_line @@ -444,7 +462,9 @@ end M.tag = function(x, opts) local name, file, text = x:match("([^\t]+)\t([^\t]+)\t(.*)") - if not file or not name or not text then return x end + if not file or not name or not text then + return x + end text = text:match([[(.*);"]]) or text -- remove ctag comments -- unescape ctags special chars -- '\/' -> '/' @@ -462,13 +482,15 @@ M.tag = function(x, opts) line = text:match("%d+") end line = line and #line > 0 and tonumber(line) - return string.format("%-" .. tostring(align) .. "s%s%s%s: %s", + return string.format( + "%-" .. tostring(align) .. "s%s%s%s: %s", name, utils.nbsp, M.file(file, opts), not line and "" or ":" .. utils.ansi_codes.green(tostring(line)), utils.ansi_codes.blue(tag) - ), line + ), + line end M.git_status = function(x, opts) @@ -483,7 +505,9 @@ M.git_status = function(x, opts) return icon end -- unrecognizable format, return - if not x or #x < 4 then return x end + if not x or #x < 4 then + return x + end -- strip ansi coloring or the pattern matching fails -- when git config has `color.status=always` (#706) x = utils.strip_ansi_coloring(x) @@ -498,13 +522,19 @@ M.git_status = function(x, opts) end f1 = f1 and M.file(f1, opts) -- accommodate 'file_ignore_patterns' - if not f1 then return end + if not f1 then + return + end f2 = f2 and M.file(f2, opts) local staged = git_iconify(x:sub(1, 1):gsub("?", " "), true) local unstaged = git_iconify(x:sub(2, 2)) local entry = ("%s%s%s%s%s"):format( - staged, utils.nbsp, unstaged, utils.nbsp .. utils.nbsp, - (f2 and ("%s -> %s"):format(f1, f2) or f1)) + staged, + utils.nbsp, + unstaged, + utils.nbsp .. utils.nbsp, + (f2 and ("%s -> %s"):format(f1, f2) or f1) + ) return entry end @@ -523,7 +553,9 @@ M.git_hunk = function(x, opts) -- index 3354405..799e467 100644 -- --- a/lua/fzf-lua/defaults.lua -- +++ b/lua/fzf-lua/defaults.lua - if l:match("^diff") then S.i = 0 end + if l:match("^diff") then + S.i = 0 + end if S.i < 3 then return end @@ -557,7 +589,9 @@ end M.zoxide = function(x, opts) local score, dir = x:match("(%d+%.%d+)%s+(.-)$") - if not score then return x end + if not score then + return x + end if opts.cwd then dir = path.relative_to(dir, opts.cwd) end diff --git a/lua/fzf-lua/path.lua b/lua/fzf-lua/path.lua index 31aefbb4e..13c213e66 100644 --- a/lua/fzf-lua/path.lua +++ b/lua/fzf-lua/path.lua @@ -1,6 +1,6 @@ local uv = vim.uv or vim.loop -local utils = require "fzf-lua.utils" -local libuv = require "fzf-lua.libuv" +local utils = require("fzf-lua.utils") +local libuv = require("fzf-lua.libuv") local string_sub = string.sub local string_byte = string.byte @@ -73,17 +73,15 @@ end ---@param path string ---@return boolean M.is_absolute = function(path) - return utils._if_win( - string_byte(path, 2) == M.colon_byte, - string_byte(path, 1) == M.fslash_byte) + return utils._if_win(string_byte(path, 2) == M.colon_byte, string_byte(path, 1) == M.fslash_byte) end ---@param path string ---@return boolean M.has_cwd_prefix = function(path) return #path > 1 - and string_byte(path, 1) == M.dot_byte - and M.byte_is_separator(string_byte(path, 2)) + and string_byte(path, 1) == M.dot_byte + and M.byte_is_separator(string_byte(path, 2)) end ---@param path string @@ -174,11 +172,15 @@ function M.is_relative_to(path, relative_to) repeat ridx = ridx + 1 until not M.byte_is_separator(string.byte(relative_to, ridx)) - elseif utils.__IS_WINDOWS and pbyte and rbyte + elseif + utils.__IS_WINDOWS + and pbyte + and rbyte -- case insensitive matching on windows and string.char(pbyte):lower() == string.char(rbyte):lower() - -- byte matching on Unix/BSD - or pbyte == rbyte then + -- byte matching on Unix/BSD + or pbyte == rbyte + then -- character matches, move to next pidx = pidx + 1 ridx = ridx + 1 @@ -251,7 +253,9 @@ end ---@param path string? ---@return string? function M.HOME_to_tilde(path) - if not path then return end + if not path then + return + end if utils.__IS_WINDOWS then local home = M.HOME() if path:sub(1, #home):lower() == home:lower() then @@ -264,8 +268,7 @@ function M.HOME_to_tilde(path) end local function find_next_separator(str, start_idx) - local SEPARATOR_BYTES = utils._if_win( - { M.fslash_byte, M.bslash_byte }, { M.fslash_byte }) + local SEPARATOR_BYTES = utils._if_win({ M.fslash_byte, M.bslash_byte }, { M.fslash_byte }) for i = start_idx or 1, #str do for _, byte in ipairs(SEPARATOR_BYTES) do if string_byte(str, i) == byte then @@ -333,7 +336,9 @@ function M.shorten(path, max_len, sep) part = utf8_sub(path, start_idx, end_idx + 1) end table.insert(parts, part) - if i then start_idx = i + 1 end + if i then + start_idx = i + 1 + end until not i return table.concat(parts, sep) end @@ -356,13 +361,17 @@ function M.lengthen(path) -- replace separator with wildcard + separator glob_expr = glob_expr_prefix .. glob_expr:gsub(separator, "%*" .. separator) return vim.fn.glob(glob_expr):match("[^\n]+") - -- or string.format("", path) - or string.format("", glob_expr) + -- or string.format("", path) + or string.format("", glob_expr) end local function lastIndexOf(haystack, needle) local i = haystack:match(".*" .. needle .. "()") - if i == nil then return nil else return i - 1 end + if i == nil then + return nil + else + return i - 1 + end end local function stripBeforeLastOccurrenceOf(str, sep) @@ -379,10 +388,9 @@ function M.entry_to_ctag(entry, noesc) if ctag and not noesc then -- required escapes for vim.fn.search() -- \ ] ~ * - ctag = ctag:gsub("[\\%]~*]", - function(x) - return "\\" .. x - end) + ctag = ctag:gsub("[\\%]~*]", function(x) + return "\\" .. x + end) end return ctag end @@ -403,8 +411,8 @@ function M.entry_to_location(entry, opts) start = { line = line - 1, character = col - 1, - } - } + }, + }, } end @@ -452,7 +460,9 @@ function M.entry_to_file(entry, opts, force_uri) return M.entry_to_location(stripped, opts) end local s = utils.strsplit(stripped, ":") - if not s[1] then return {} end + if not s[1] then + return {} + end if utils.__IS_WINDOWS and M.is_absolute(stripped) then -- adjust split for "C:\..." s[1] = s[1] .. ":" .. s[2] @@ -460,7 +470,7 @@ function M.entry_to_file(entry, opts, force_uri) end local file = s[1] local line = tonumber(s[2]) - local col = tonumber(s[3]) + local col = tonumber(s[3]) -- if the filename contains ':' we will have the wrong filename. -- test for existence on the longest possible match on the file -- system so we can accept files that end with ':', for example: @@ -495,29 +505,32 @@ function M.entry_to_file(entry, opts, force_uri) end return { stripped = stripped, - bufnr = tonumber(bufnr), - bufname = bufnr and vim.api.nvim_buf_is_valid(tonumber(bufnr)) - and vim.api.nvim_buf_get_name(tonumber(bufnr)), + bufnr = tonumber(bufnr), + bufname = bufnr and vim.api.nvim_buf_is_valid(tonumber(bufnr)) and vim.api.nvim_buf_get_name( + tonumber(bufnr) + ), terminal = terminal, - path = file, - line = tonumber(line) or 0, - col = tonumber(col) or 0, - ctag = opts._ctag and M.entry_to_ctag(stripped) or nil, + path = file, + line = tonumber(line) or 0, + col = tonumber(col) or 0, + ctag = opts._ctag and M.entry_to_ctag(stripped) or nil, } end function M.git_cwd(cmd, opts) local git_args = { - { "cwd", "-C" }, - { "git_dir", "--git-dir" }, + { "cwd", "-C" }, + { "git_dir", "--git-dir" }, { "git_worktree", "--work-tree" }, - { "git_config", "-c", noexpand = true }, + { "git_config", "-c", noexpand = true }, } -- NOTE: we copy the opts due to a bug with Windows network drives starting with "\\" -- as `vim.fn.expand` would reduce the double slash to a single slash modifying the -- original `opts.cwd` ref (#1429) local o = {} - for _, a in ipairs(git_args) do o[a[1]] = opts[a[1]] end + for _, a in ipairs(git_args) do + o[a[1]] = opts[a[1]] + end if type(cmd) == "string" then local args = "" for _, a in ipairs(git_args) do @@ -550,7 +563,9 @@ function M.git_root(opts, noerr) local cmd = M.git_cwd({ "git", "rev-parse", "--show-toplevel" }, opts) local output, err = utils.io_systemlist(cmd) if err ~= 0 then - if not noerr then utils.info(unpack(output)) end + if not noerr then + utils.info(unpack(output)) + end return nil end return output[1] @@ -565,7 +580,9 @@ function M.keymap_to_entry(str, opts) t = true, } local mode, keymap = string.match(str, "^(.-)│(.-)│") - if not mode or not keymap then return {} end + if not mode or not keymap then + return {} + end mode, keymap = vim.trim(mode), vim.trim(keymap) mode = valid_modes[mode] and mode or "" -- only valid modes local out, vmap, cmd = nil, nil, string.format("verbose %smap %s", mode, keymap) @@ -573,7 +590,9 @@ function M.keymap_to_entry(str, opts) -- "No mapping found" pcall(vim.api.nvim_buf_call, opts.__CTX.bufnr, function() out = utils.strsplit(vim.fn.execute(cmd), "\n") - _, vmap = next(vim.tbl_map(function(x) return #x > 0 and x or nil end, out)) + _, vmap = next(vim.tbl_map(function(x) + return #x > 0 and x or nil + end, out)) end) local entry for i = #out, 1, -1 do @@ -600,11 +619,15 @@ end M._env = setmetatable({}, { __index = function(_, index) return os.getenv(index) - end + end, }) -M._nvim_buf_get_lines = function() return {} end -M._nvim_buf_line_count = function() return 0 end +M._nvim_buf_get_lines = function() + return {} +end +M._nvim_buf_line_count = function() + return 0 +end function M.ft_match(args) if not args or not args.filename then @@ -630,7 +653,9 @@ function M.ft_match(args) vim.api.nvim_buf_line_count = _nvim_buf_line_count vim.fn.fnamemodify = _fnamemodify vim.env = _env - if ok then return ft, on_detect end + if ok then + return ft, on_detect + end end function M.ft_match_fast_event(args) diff --git a/lua/fzf-lua/previewer/builtin.lua b/lua/fzf-lua/previewer/builtin.lua index 74bf757ad..ea0e5b974 100644 --- a/lua/fzf-lua/previewer/builtin.lua +++ b/lua/fzf-lua/previewer/builtin.lua @@ -1,19 +1,20 @@ -local path = require "fzf-lua.path" -local shell = require "fzf-lua.shell" -local utils = require "fzf-lua.utils" -local libuv = require "fzf-lua.libuv" -local Object = require "fzf-lua.class" +local path = require("fzf-lua.path") +local shell = require("fzf-lua.shell") +local utils = require("fzf-lua.utils") +local libuv = require("fzf-lua.libuv") +local Object = require("fzf-lua.class") local uv = vim.uv or vim.loop local api = vim.api local fn = vim.fn - local TSContext = {} ---@param opts? TSContext.UserConfig function TSContext.setup(opts) - if TSContext._setup then return true end + if TSContext._setup then + return true + end if not package.loaded["treesitter-context"] then return false end @@ -34,7 +35,9 @@ function TSContext.setup(opts) end function TSContext.deregister() - if not TSContext._setup then return end + if not TSContext._setup then + return + end for winid, _ in pairs(TSContext._winids) do TSContext.close(winid) end @@ -49,13 +52,17 @@ end ---@param winid integer function TSContext.is_attached(winid) - if not TSContext._setup then return false end + if not TSContext._setup then + return false + end return TSContext._winids[tostring(winid)] end ---@param winid integer function TSContext.close(winid) - if not TSContext._setup then return end + if not TSContext._setup then + return + end require("treesitter-context.render").close(tonumber(winid)) TSContext._winids[tostring(winid)] = nil end @@ -63,7 +70,9 @@ end ---@param winid integer ---@param bufnr integer function TSContext.toggle(winid, bufnr) - if not TSContext._setup then return end + if not TSContext._setup then + return + end if TSContext.is_attached(winid) then TSContext.close(winid) else @@ -72,14 +81,18 @@ function TSContext.toggle(winid, bufnr) end function TSContext.inc_dec_maxlines(num, winid, bufnr) - if not TSContext._setup or not tonumber(num) then return end + if not TSContext._setup or not tonumber(num) then + return + end local config = require("treesitter-context.config") local max_lines = config.max_lines or 0 config.max_lines = math.max(0, max_lines + tonumber(num)) utils.info(string.format("treesitter-context `max_lines` set to %d.", config.max_lines)) if TSContext.is_attached(winid) then for _, t in ipairs({ 0, 20 }) do - vim.defer_fn(function() TSContext.update(winid, bufnr) end, t) + vim.defer_fn(function() + TSContext.update(winid, bufnr) + end, t) end end end @@ -90,7 +103,9 @@ end ---@param opts? TSContext.UserConfig function TSContext.update(winid, bufnr, opts) opts = opts or {} - if not TSContext.setup(opts) then return end + if not TSContext.setup(opts) then + return + end assert(bufnr == vim.api.nvim_win_get_buf(winid)) local render = require("treesitter-context.render") local context_ranges, context_lines = require("treesitter-context.context").get(winid) @@ -102,7 +117,11 @@ function TSContext.update(winid, bufnr, opts) if vim.api.nvim_buf_is_valid(bufnr) and vim.api.nvim_win_is_valid(winid) then -- ensure context win is above local fix = function(win, zindex) - if win and api.nvim_win_is_valid(win) and api.nvim_win_get_config(win).zindex ~= zindex then + if + win + and api.nvim_win_is_valid(win) + and api.nvim_win_get_config(win).zindex ~= zindex + then api.nvim_win_set_config(win, { zindex = zindex }) -- noautocmd don't ignore WinResized/WinScrolled if fn.exists("+eventignorewin") == 1 and vim.wo[win][0].eventignorewin == "" then @@ -112,11 +131,15 @@ function TSContext.update(winid, bufnr, opts) end api.nvim_win_call(winid, function() render.open(winid, context_ranges, context_lines) - TSContext.window_contexts = TSContext.window_contexts or - utils.upvfind(render.open, "window_contexts") - if not TSContext.window_contexts then return end + TSContext.window_contexts = TSContext.window_contexts + or utils.upvfind(render.open, "window_contexts") + if not TSContext.window_contexts then + return + end local window_context = TSContext.window_contexts[winid] - if not window_context then return end + if not window_context then + return + end fix(window_context.context_winid, TSContext.zindex) fix(window_context.gutter_winid, TSContext.zindex) end) @@ -153,15 +176,16 @@ function Previewer.base:new(o, opts, fzf_win) o = o or {} self.type = "builtin" - self.opts = opts; + self.opts = opts self.win = fzf_win self.delay = self.win.winopts.preview.delay or 100 self.title = self.win.winopts.preview.title self.title_pos = self.win.winopts.preview.title_pos self.title_fnamemodify = o.title_fnamemodify self.render_markdown = type(o.render_markdown) == "table" and o.render_markdown or {} - self.render_markdown.filetypes = - type(self.render_markdown.filetypes) == "table" and self.render_markdown.filetypes or {} + self.render_markdown.filetypes = type(self.render_markdown.filetypes) == "table" + and self.render_markdown.filetypes + or {} self.snacks_image = type(o.snacks_image) == "table" and o.snacks_image or {} self.winopts = self.win.winopts.preview.winopts self.syntax = default(o.syntax, true) @@ -183,17 +207,18 @@ function Previewer.base:new(o, opts, fzf_win) end -- validate the ueberzug image scaler local uz_scalers = { - ["crop"] = "crop", - ["distort"] = "distort", - ["contain"] = "contain", - ["fit_contain"] = "fit_contain", - ["cover"] = "cover", + ["crop"] = "crop", + ["distort"] = "distort", + ["contain"] = "contain", + ["fit_contain"] = "fit_contain", + ["cover"] = "cover", ["forced_cover"] = "forced_cover", } self.ueberzug_scaler = o.ueberzug_scaler and uz_scalers[o.ueberzug_scaler] if o.ueberzug_scaler and not self.ueberzug_scaler then - utils.warn(("Invalid ueberzug image scaler '%s', option will be omitted.") - :format(o.ueberzug_scaler)) + utils.warn( + ("Invalid ueberzug image scaler '%s', option will be omitted."):format(o.ueberzug_scaler) + ) end -- cached buffers self.cached_bufnrs = {} @@ -247,7 +272,9 @@ function Previewer.base:set_style_winopts() end function Previewer.base:preview_is_terminal() - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end return utils.getwininfo(self.win.preview_winid).terminal == 1 end @@ -263,7 +290,9 @@ end ---@param del_cached boolean? function Previewer.base:safe_buf_delete(bufnr, del_cached) -- can be nil after closing preview with - if not bufnr then return end + if not bufnr then + return + end assert(type(bufnr) == "number" and bufnr > 0) -- NOTE: listed buffers map key must use 'tostring' if self.listed_buffers[tostring(bufnr)] then @@ -288,10 +317,14 @@ end ---@param newbuf integer ---@param min_winopts boolean? function Previewer.base:set_preview_buf(newbuf, min_winopts) - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end -- Set the preview window to the new buffer local curbuf = vim.api.nvim_win_get_buf(self.win.preview_winid) - if curbuf == newbuf then return end + if curbuf == newbuf then + return + end -- Something went terribly wrong assert(curbuf ~= newbuf) utils.win_set_buf_noautocmd(self.win.preview_winid, newbuf) @@ -320,7 +353,9 @@ end ---@param min_winopts boolean? ---@return table? cached function Previewer.base:cache_buffer(bufnr, key, min_winopts) - if not key then return end + if not key then + return + end if not bufnr then -- can happen with slow loading buffers such as image previews -- with viu while spamming f5/f6 to rotate the preview window @@ -356,15 +391,18 @@ end ---@param newbuf boolean function Previewer.base:clear_preview_buf(newbuf) local retbuf = nil - if ((self.win and self.win._reuse) or newbuf) - -- Attach a temp buffer to the window when reusing (`ctrl-g`) - -- so we don't invalidate the window when deting the buffer - -- in `safe_buf_delete` call below - -- We don't use 'self.win:validate_preview()' because we want - -- to detach the buffer even when 'self.win.closing = true' - and self.win and self.win.preview_winid - and tonumber(self.win.preview_winid) > 0 - and api.nvim_win_is_valid(self.win.preview_winid) then + if + ((self.win and self.win._reuse) or newbuf) + -- Attach a temp buffer to the window when reusing (`ctrl-g`) + -- so we don't invalidate the window when deting the buffer + -- in `safe_buf_delete` call below + -- We don't use 'self.win:validate_preview()' because we want + -- to detach the buffer even when 'self.win.closing = true' + and self.win + and self.win.preview_winid + and tonumber(self.win.preview_winid) > 0 + and api.nvim_win_is_valid(self.win.preview_winid) + then -- attach a temp buffer to the window -- so we can safely delete the buffer -- ('nvim_buf_delete' removes the attached win) @@ -398,8 +436,12 @@ function Previewer.base:populate_preview_buf(_) end -- for lint ---@param entry_str string? function Previewer.base:display_entry(entry_str) - if not entry_str then return end - if not self.win or not self.win:validate_preview() then return end + if not entry_str then + return + end + if not self.win or not self.win:validate_preview() then + return + end -- verify backup the current window options -- will store only of `winopts_orig` is nil @@ -413,7 +455,9 @@ function Previewer.base:display_entry(entry_str) end local populate_preview_buf = function(entry_str_) - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end -- specialized previewer populate function ---@cast self fzf-lua.previewer.BufferOrFile base class def don't make sense here @@ -447,7 +491,9 @@ function Previewer.base:cmdline(_) local entry, query, idx = unpack(items, 1, 3) -- NOTE: see comment regarding {n} in `core.convert_exec_silent_actions` -- convert empty string to nil - if not tonumber(idx) then entry = nil end + if not tonumber(idx) then + entry = nil + end -- on windows, query may not be expanded to a string: #1887 self.opts._last_query = query or "" self:display_entry(entry) @@ -469,7 +515,8 @@ function Previewer.base:zero(_) -- https://github.com/junegunn/fzf/issues/3516 -- self._zero_lock = self._zero_lock or path.normalize(vim.fn.tempname()) - local act = string.format("execute-silent(mkdir %s && %s)", + local act = string.format( + "execute-silent(mkdir %s && %s)", libuv.shellescape(self._zero_lock), shell.raw_action(function(_, _, _) vim.defer_fn(function() @@ -481,7 +528,8 @@ function Previewer.base:zero(_) self.last_entry = nil vim.fn.delete(self._zero_lock, "d") end, self.delay) - end, "", self.opts.debug)) + end, "", self.opts.debug) + ) return act end @@ -496,31 +544,38 @@ end ---@param direction '"top"'|'"bottom"'|'"half-page-up"'|'"half-page-down"'|'"page-up"'|'"page-down"'|'"line-up"'|'"line-down"'|'"reset"' function Previewer.base:scroll(direction) local preview_winid = self.win.preview_winid - if not self.preview_bufnr or preview_winid < 0 or not direction then return end - if not api.nvim_win_is_valid(preview_winid) then return end + if not self.preview_bufnr or preview_winid < 0 or not direction then + return + end + if not api.nvim_win_is_valid(preview_winid) then + return + end -- map direction to scroll commands ('g8' on char to display) local input = ({ - ["top"] = "gg", - ["bottom"] = "G", - ["half-page-up"] = ("%c"):format(0x15), -- [[]] + ["top"] = "gg", + ["bottom"] = "G", + ["half-page-up"] = ("%c"):format(0x15), -- [[]] ["half-page-down"] = ("%c"):format(0x04), -- [[]] - ["page-up"] = ("%c"):format(0x02), -- [[]] - ["page-down"] = ("%c"):format(0x06), -- [[]] + ["page-up"] = ("%c"):format(0x02), -- [[]] + ["page-down"] = ("%c"):format(0x06), -- [[]] -- ^Y/^E doesn't seem to work, "Mgk" also doesn't (#2111) -- TODO: Can't scroll above line 2? - ["line-up"] = (function() + ["line-up"] = (function() local wi = utils.getwininfo(preview_winid) - return wi.topline <= 2 and "gg" or function() - api.nvim_win_set_cursor(0, { wi.topline, 1 }) - vim.cmd("norm! gk") - end + return wi.topline <= 2 and "gg" + or function() + api.nvim_win_set_cursor(0, { wi.topline, 1 }) + vim.cmd("norm! gk") + end end)(), - ["line-down"] = "Mgj", - ["reset"] = true, -- dummy for exit condition + ["line-down"] = "Mgj", + ["reset"] = true, -- dummy for exit condition })[direction] - if not input then return end + if not input then + return + end if direction == "reset" then pcall(vim.api.nvim_win_call, preview_winid, function() @@ -534,7 +589,7 @@ function Previewer.base:scroll(direction) end) else pcall(vim.api.nvim_win_call, preview_winid, function() - if type(input) == "function" then + if type(input) == "function" then input() else vim.cmd([[norm! ]] .. input) @@ -567,7 +622,9 @@ end function Previewer.base:ts_ctx_toggle() local bufnr, winid = self.preview_bufnr, self.win.preview_winid - if winid < 0 or not api.nvim_win_is_valid(winid) then return end + if winid < 0 or not api.nvim_win_is_valid(winid) then + return + end if self.treesitter.context then self.treesitter._context = self.treesitter.context self.treesitter.context = nil @@ -580,7 +637,9 @@ end function Previewer.base:ts_ctx_inc_dec_maxlines(num) local bufnr, winid = self.preview_bufnr, self.win.preview_winid - if winid < 0 or not api.nvim_win_is_valid(winid) then return end + if winid < 0 or not api.nvim_win_is_valid(winid) then + return + end TSContext.inc_dec_maxlines(num, winid, bufnr) end @@ -633,49 +692,65 @@ function Previewer.buffer_or_file:should_load_buffer(entry) -- we don't have a previous entry to compare to or `do_not_cache` is set meaning -- it's a terminal command (chafa, viu, ueberzug) which requires a reload -- return 'true' so the buffer will be loaded in ::populate_preview_buf - if not self.loaded_entry or self.loaded_entry.do_not_cache then return true end - if (entry.bufnr and entry.bufnr == self.loaded_entry.bufnr) or - (not entry.bufnr and entry.path and entry.path == self.loaded_entry.path) then + if not self.loaded_entry or self.loaded_entry.do_not_cache then + return true + end + if + (entry.bufnr and entry.bufnr == self.loaded_entry.bufnr) + or (not entry.bufnr and entry.path and entry.path == self.loaded_entry.path) + then return false end return true end function Previewer.buffer_or_file:start_ueberzug() - if self._ueberzug_fifo then return self._ueberzug_fifo end + if self._ueberzug_fifo then + return self._ueberzug_fifo + end self._ueberzug_fifo = path.join({ vim.fn.fnamemodify(vim.fn.tempname(), ":h"), - string.format("fzf-lua-%d-ueberzug", vim.fn.getpid()) + string.format("fzf-lua-%d-ueberzug", vim.fn.getpid()), }) utils.io_system({ "mkfifo", self._ueberzug_fifo }) - self._ueberzug_job = vim.fn.jobstart({ "sh", "-c", - string.format( - "tail -f %s | ueberzug layer --parser json", - libuv.shellescape(self._ueberzug_fifo)) - }, { - on_exit = function(_, rc, _) - if rc ~= 0 and rc ~= 143 then - utils.warn(("ueberzug exited with error %d"):format(rc) .. - ", run ':messages' to see the detailed error.") - end - end, - on_stderr = function(_, data, _) - for _, l in ipairs(data or {}) do - if #l > 0 then - utils.info("ueberzug: " .. l) + self._ueberzug_job = vim.fn.jobstart( + { + "sh", + "-c", + string.format( + "tail -f %s | ueberzug layer --parser json", + libuv.shellescape(self._ueberzug_fifo) + ), + }, + { + on_exit = function(_, rc, _) + if rc ~= 0 and rc ~= 143 then + utils.warn( + ("ueberzug exited with error %d"):format(rc) + .. ", run ':messages' to see the detailed error." + ) end - end - -- populate the preview buffer with the error message - if self.preview_bufnr and self.preview_bufnr > 0 and - vim.api.nvim_buf_is_valid(self.preview_bufnr) then - local lines = vim.api.nvim_buf_get_lines(self.preview_bufnr, 0, -1, false) + end, + on_stderr = function(_, data, _) for _, l in ipairs(data or {}) do - table.insert(lines, l) + if #l > 0 then + utils.info("ueberzug: " .. l) + end end - vim.api.nvim_buf_set_lines(self.preview_bufnr, 0, -1, false, lines) - end - end - } + -- populate the preview buffer with the error message + if + self.preview_bufnr + and self.preview_bufnr > 0 + and vim.api.nvim_buf_is_valid(self.preview_bufnr) + then + local lines = vim.api.nvim_buf_get_lines(self.preview_bufnr, 0, -1, false) + for _, l in ipairs(data or {}) do + table.insert(lines, l) + end + vim.api.nvim_buf_set_lines(self.preview_bufnr, 0, -1, false, lines) + end + end, + } ) self._ueberzug_pid = vim.fn.jobpid(self._ueberzug_job) return self._ueberzug_fifo @@ -697,7 +772,9 @@ function Previewer.buffer_or_file:stop_ueberzug() end function Previewer.buffer_or_file:populate_terminal_cmd(tmpbuf, cmd, entry) - if not cmd then return end + if not cmd then + return + end cmd = type(cmd) == "table" and utils.deepcopy(cmd) or { cmd } if not cmd[1] or vim.fn.executable(cmd[1]) ~= 1 then return false @@ -716,19 +793,21 @@ function Previewer.buffer_or_file:populate_terminal_cmd(tmpbuf, cmd, entry) self:set_preview_buf(tmpbuf, true) if cmd[1]:match("ueberzug") then local fifo = self:start_ueberzug() - if not fifo then return end + if not fifo then + return + end local wincfg = vim.api.nvim_win_get_config(self.win.preview_winid) local winpos = vim.api.nvim_win_get_position(self.win.preview_winid) local params = { - action = "add", + action = "add", identifier = "preview", - x = winpos[2] + 1, - y = winpos[1] + 2, - width = wincfg.width - 2, - height = wincfg.height - 2, - scaler = self.ueberzug_scaler, - path = path.is_absolute(entry.path) and entry.path or - path.join({ self.opts.cwd or uv.cwd(), entry.path }), + x = winpos[2] + 1, + y = winpos[1] + 2, + width = wincfg.width - 2, + height = wincfg.height - 2, + scaler = self.ueberzug_scaler, + path = path.is_absolute(entry.path) and entry.path + or path.join({ self.opts.cwd or uv.cwd(), entry.path }), } local json = vim.json.encode(params) -- both 'fs_open|write|close' and 'vim.fn.system' work. @@ -765,7 +844,7 @@ function Previewer.buffer_or_file:populate_terminal_cmd(tmpbuf, cmd, entry) self:preview_buf_post(entry, true) self._job_id = nil end - end + end, }) end) end @@ -779,21 +858,23 @@ end ---@return string function Previewer.buffer_or_file:key_from_entry(entry) assert(entry) - return entry.bufnr and string.format("bufnr:%d", entry.bufnr) - or entry.uri - or entry.path + return entry.bufnr and string.format("bufnr:%d", entry.bufnr) or entry.uri or entry.path end ---@param entry fzf-lua.buffer_or_file.Entry ---@return fzf-lua.buffer_or_file.Bcache? function Previewer.buffer_or_file:get_bcache(entry) - if entry.do_not_cache then return end + if entry.do_not_cache then + return + end 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)) - if not cached then return end + if not cached then + return + end if not cached.tick then -- in case cache don't have "tick" assert(cached.tick == entry.tick) return cached @@ -807,11 +888,15 @@ end ---@param entry_str string function Previewer.buffer_or_file:populate_preview_buf(entry_str) - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end -- stop ueberzug shell job self:stop_ueberzug() local entry = self:parse_entry(entry_str) - if utils.tbl_isempty(entry) then return end + if utils.tbl_isempty(entry) then + return + end local cached = self:get_bcache(entry) local invalid_cached = cached and cached.invalid and cached entry.cached = cached @@ -819,8 +904,10 @@ function Previewer.buffer_or_file:populate_preview_buf(entry_str) assert(cached.bufnr == self.preview_bufnr) -- same file/buffer as previous entry no need to reload content -- only call post to set cursor location - cached.invalid_pos = ((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])) + cached.invalid_pos = ( + (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]) + ) if type(self.cached_bufnrs[tostring(self.preview_bufnr)]) == "table" and cached.invalid_pos then -- entry is within the same buffer but line|col has changed -- clear cached buffer position so we scroll to entry's line|col @@ -862,9 +949,15 @@ function Previewer.buffer_or_file:populate_preview_buf(entry_str) else -- in case of an error display the stacktrace in the preview buffer 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)) + 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 + ) + ) table.insert(lines, 2, "") local tmpbuf = invalid_cached and invalid_cached.bufnr or self:get_tmp_buffer() vim.api.nvim_buf_set_lines(tmpbuf, 0, -1, false, lines) @@ -913,8 +1006,10 @@ function Previewer.buffer_or_file:populate_preview_buf(entry_str) lines = { "Preview is not supported for binary files." } elseif tonumber(self.limit_b) > 0 and fs_stat.size > self.limit_b then lines = { - ("Preview file size limit (>%dMB) reached, file size %dMB.") - :format(self.limit_b / (1024 * 1024), fs_stat.size / (1024 * 1024)), + ("Preview file size limit (>%dMB) reached, file size %dMB."):format( + self.limit_b / (1024 * 1024), + fs_stat.size / (1024 * 1024) + ), -- "(configured via 'previewers.builtin.limit_b')" } end @@ -928,33 +1023,39 @@ function Previewer.buffer_or_file:populate_preview_buf(entry_str) end end -- read the file into the buffer - utils.read_file_async(entry.path, vim.schedule_wrap(function(data) - local lines = vim.split(data, "[\r]?\n") - - -- if file ends in new line, don't write an empty string as the last - -- line. - if data:sub(#data, #data) == "\n" or data:sub(#data - 1, #data) == "\r\n" then - table.remove(lines) - end - vim.api.nvim_buf_set_lines(tmpbuf, 0, -1, false, lines) - -- swap preview buffer with new one - self:set_preview_buf(tmpbuf) - self:preview_buf_post(entry) - end)) + utils.read_file_async( + entry.path, + vim.schedule_wrap(function(data) + local lines = vim.split(data, "[\r]?\n") + + -- if file ends in new line, don't write an empty string as the last + -- line. + if data:sub(#data, #data) == "\n" or data:sub(#data - 1, #data) == "\r\n" then + table.remove(lines) + end + vim.api.nvim_buf_set_lines(tmpbuf, 0, -1, false, lines) + -- swap preview buffer with new one + self:set_preview_buf(tmpbuf) + self:preview_buf_post(entry) + end) + ) end end -- Attach ts highlighter, neovim >= v0.9 local ts_attach = function(bufnr, ft) -- ts is already attach, see $VIMRUNTIME/lua/vim/treesitter/highlighter.lua - if vim.b[bufnr].ts_highlight then return true end + if vim.b[bufnr].ts_highlight then + return true + end local lang = vim.treesitter.language.get_lang(ft) local loaded = lang and utils.has_ts_parser(lang) if lang and loaded then local ok, err = pcall(vim.treesitter.start, bufnr, lang) if not ok then - utils.warn(string.format( - "unable to attach treesitter highlighter for filetype '%s': %s", ft, err)) + utils.warn( + string.format("unable to attach treesitter highlighter for filetype '%s': %s", ft, err) + ) end return ok end @@ -962,13 +1063,16 @@ end function Previewer.base:update_ts_context() local bufnr = self.preview_bufnr - if not bufnr or not package.loaded["treesitter-context"] then return end + if not bufnr or not package.loaded["treesitter-context"] then + return + end local ft = vim.b[bufnr] and vim.b[bufnr]._ft - if not ft - or not self.win - or not self.win:validate_preview() - or not self.treesitter.enabled - or not self.treesitter.context + if + not ft + or not self.win + or not self.win:validate_preview() + or not self.treesitter.enabled + or not self.treesitter.context then return end @@ -977,25 +1081,35 @@ function Previewer.base:update_ts_context() -- https://github.com/neovim/neovim/commit/45e606b1fddbfeee8fe28385b5371ca6f2fba71b -- For more info see #1922 local lang = vim.treesitter.language.get_lang(ft) - if not utils.has_ts_parser(lang) then return end + if not utils.has_ts_parser(lang) then + return + end local parser = vim.treesitter.get_parser(self.preview_bufnr, lang) local context_updated TSContext.zindex = self.win.winopts.zindex + 20 for _, t in ipairs({ 0, 20, 50, 100 }) do vim.defer_fn(function() - if context_updated - or not tonumber(self.preview_bufnr) - or not vim.api.nvim_buf_is_valid(self.preview_bufnr) + if + context_updated + or not tonumber(self.preview_bufnr) + or not vim.api.nvim_buf_is_valid(self.preview_bufnr) then return end if parser:is_valid(true) then context_updated = true - TSContext.update(self.win.preview_winid, self.preview_bufnr, vim.tbl_extend("force", - type(self.treesitter.context) == "table" and self.treesitter.context or {}, { - -- `multiwindow` must be set regardless of user options - multiwindow = true, - })) + TSContext.update( + self.win.preview_winid, + self.preview_bufnr, + vim.tbl_extend( + "force", + type(self.treesitter.context) == "table" and self.treesitter.context or {}, + { + -- `multiwindow` must be set regardless of user options + multiwindow = true, + } + ) + ) end end, t) end @@ -1004,10 +1118,7 @@ end function Previewer.base:update_render_markdown() local bufnr, winid = self.preview_bufnr, self.win.preview_winid local ft = vim.b[bufnr] and vim.b[bufnr]._ft - if not ft - or not self.render_markdown.enabled - or not self.render_markdown.filetypes[ft] - then + if not ft or not self.render_markdown.enabled or not self.render_markdown.filetypes[ft] then return end if package.loaded["render-markdown"] then @@ -1017,8 +1128,10 @@ function Previewer.base:update_render_markdown() --- --- Use `strict:render(bufnr, 1000)` to stop rendering if --- line count >= 1000. - local strict = package.loaded["markview"].strict_render; - if strict then strict:render(bufnr); end + local strict = package.loaded["markview"].strict_render + if strict then + strict:render(bufnr) + end end end @@ -1036,18 +1149,22 @@ function Previewer.base:attach_snacks_image_inline() ---@diagnostic disable-next-line: undefined-field local simg = (_G.Snacks or {}).image local bufnr, preview_winid = self.preview_bufnr, self.win.preview_winid - if not simg - or not self.snacks_image.enabled - or not self.snacks_image.render_inline - or not simg.supports_terminal() - or not simg.terminal.env().placeholders - or vim.b[bufnr].snacks_image_attached then + if + not simg + or not self.snacks_image.enabled + or not self.snacks_image.render_inline + or not simg.supports_terminal() + or not simg.terminal.env().placeholders + or vim.b[bufnr].snacks_image_attached + then return end -- restore default winblend when on unsupport ft local ft = vim.b[bufnr]._ft - if not ft then return end + if not ft then + return + end _G._fzf_lua_snacks_langs = _G._fzf_lua_snacks_langs or simg.langs() if not vim.tbl_contains(_G._fzf_lua_snacks_langs, vim.treesitter.language.get_lang(ft)) then vim.wo[preview_winid].winblend = self.winblend @@ -1062,13 +1179,18 @@ function Previewer.base:attach_snacks_image_inline() end function Previewer.buffer_or_file:do_syntax(entry) - if not self.preview_bufnr then return end - if not entry or not entry.path then return end + if not self.preview_bufnr then + return + end + if not entry or not entry.path then + return + end local bufnr = self.preview_bufnr local preview_winid = self.win.preview_winid - if not api.nvim_buf_is_valid(bufnr) - or vim.bo[bufnr].filetype ~= "" - or fn.bufwinid(bufnr) ~= preview_winid + if + not api.nvim_buf_is_valid(bufnr) + or vim.bo[bufnr].filetype ~= "" + or fn.bufwinid(bufnr) ~= preview_winid then return end @@ -1091,12 +1213,15 @@ function Previewer.buffer_or_file:do_syntax(entry) syntax_limit_reached = 2 end if syntax_limit_reached > 0 and self.opts.silent == false then - utils.info(string.format( - "syntax disabled for '%s' (%s), consider increasing '%s(%d)'", entry.path, - syntax_limit_reached == 1 and ("%d lines"):format(lcount) or ("%db"):format(bytes), - syntax_limit_reached == 1 and "syntax_limit_l" or "syntax_limit_b", - syntax_limit_reached == 1 and self.syntax_limit_l or self.syntax_limit_b - )) + utils.info( + string.format( + "syntax disabled for '%s' (%s), consider increasing '%s(%d)'", + entry.path, + syntax_limit_reached == 1 and ("%d lines"):format(lcount) or ("%db"):format(bytes), + syntax_limit_reached == 1 and "syntax_limit_l" or "syntax_limit_b", + syntax_limit_reached == 1 and self.syntax_limit_l or self.syntax_limit_b + ) + ) end if syntax_limit_reached ~= 0 then @@ -1118,7 +1243,9 @@ function Previewer.buffer_or_file:do_syntax(entry) -- nvim_buf_call has less side-effects than window switch -- doautocmd filetypedetect BufRead (vim.filetype.match + ftdetect) + do_modeline local ok, _ = pcall(api.nvim_buf_call, bufnr, function() - utils.eventignore(function() vim.cmd("filetype detect") end, preview_winid, "FileType") + utils.eventignore(function() + vim.cmd("filetype detect") + end, preview_winid, "FileType") end) if not ok then utils.warn(("':filetype detect' failed for '%s'"):format(entry.path or "")) @@ -1126,7 +1253,9 @@ function Previewer.buffer_or_file:do_syntax(entry) return vim.bo[bufnr].filetype end)() - if ft == "" then return end + if ft == "" then + return + end -- Use buf local var as setting ft might have unintended consequences -- used in `update_render_markdown`, `attach_snacks_image` @@ -1134,14 +1263,22 @@ function Previewer.buffer_or_file:do_syntax(entry) local ts_enabled = (function() -- disable treesitter on minified (long line) file - if (bytes / lcount) > self._ts_limit_b_per_line then return false end - if not self.treesitter or - self.treesitter.enabled == false or - self.treesitter.disabled == true or - (type(self.treesitter.enabled) == "table" and - not utils.tbl_contains(self.treesitter.enabled, ft)) or - (type(self.treesitter.disabled) == "table" and - utils.tbl_contains(self.treesitter.disabled, ft)) then + if (bytes / lcount) > self._ts_limit_b_per_line then + return false + end + if + not self.treesitter + or self.treesitter.enabled == false + or self.treesitter.disabled == true + or (type(self.treesitter.enabled) == "table" and not utils.tbl_contains( + self.treesitter.enabled, + ft + )) + or ( + type(self.treesitter.disabled) == "table" + and utils.tbl_contains(self.treesitter.disabled, ft) + ) + then return false end return true @@ -1149,7 +1286,9 @@ function Previewer.buffer_or_file:do_syntax(entry) local ts_success = ts_enabled and ts_attach(bufnr, ft) if not ts_success then - pcall(function() vim.bo[bufnr].syntax = ft end) + pcall(function() + vim.bo[bufnr].syntax = ft + end) return end @@ -1157,13 +1296,12 @@ function Previewer.buffer_or_file:do_syntax(entry) end function Previewer.base:maybe_set_cursorline(win, pos) - if not pos then return end + if not pos then + return + end local wininfo = utils.getwininfo(win) local cursorline = false - if wininfo - and pos[1] >= wininfo.topline - and pos[1] <= wininfo.botline - then + if wininfo and pos[1] >= wininfo.topline and pos[1] <= wininfo.botline then -- reset cursor pos even when it's already there, no bigggie -- local curpos = vim.api.nvim_win_get_cursor(win) vim.api.nvim_win_set_cursor(win, pos) @@ -1177,7 +1315,8 @@ end function Previewer.buffer_or_file:set_cursor_hl(entry) local mgrep, glob_args = require("fzf-lua.providers.grep"), nil local regex = self.opts.__ACT_TO == mgrep.grep and self.opts._last_query - or self.opts.__ACT_TO == mgrep.live_grep and self.opts.search or nil + or self.opts.__ACT_TO == mgrep.live_grep and self.opts.search + or nil if regex and self.opts.fn_transform_cmd then local _, query = self.opts.fn_transform_cmd(regex, self.opts.cmd, self.opts) regex = query or regex @@ -1200,15 +1339,19 @@ function Previewer.buffer_or_file:set_cursor_hl(entry) -- If called from tags previewer, can happen when using ctags cmd -- "ctags -R --c++-kinds=+p --fields=+iaS --extras=+q --excmd=combine" regex = regex and #regex > 0 and utils.regex_to_magic(regex) - or entry.ctag and utils.ctag_to_magic(entry.ctag) + or entry.ctag and utils.ctag_to_magic(entry.ctag) pcall(vim.api.nvim_win_call, self.win.preview_winid, function() local cached_pos = self.cached_bufnrs[tostring(self.preview_bufnr)] - if type(cached_pos) ~= "table" then cached_pos = nil end + if type(cached_pos) ~= "table" then + cached_pos = nil + end local lnum, col = tonumber(entry.line), tonumber(entry.col) or 0 if not lnum or lnum < 1 then -- set win option is slow with bigfile - if vim.wo.cursorline then vim.wo.cursorline = false end + if vim.wo.cursorline then + vim.wo.cursorline = false + end self.orig_pos = { 1, 0 } api.nvim_win_set_cursor(self.win.preview_winid, cached_pos or self.orig_pos) return @@ -1233,12 +1376,17 @@ function Previewer.buffer_or_file:set_cursor_hl(entry) regex_end = tonumber(regex_end) and regex_end - regex_start regex_start = tonumber(regex_start) and regex_start + math.max(1, col) or 0 elseif self.opts.silent ~= true then - utils.warn(string.format( - [[Unable to init vim.regex with "%s", %s. . Add 'silent=true' to hide this message.]], - regex, reg)) + utils.warn( + string.format( + [[Unable to init vim.regex with "%s", %s. . Add 'silent=true' to hide this message.]], + regex, + reg + ) + ) end if regex_start > 0 then - self.match_id = fn.matchaddpos(self.win.hls.search, { { lnum, regex_start, regex_end } }, 11) + self.match_id = + fn.matchaddpos(self.win.hls.search, { { lnum, regex_start, regex_end } }, 11) end end @@ -1252,7 +1400,9 @@ function Previewer.buffer_or_file:set_cursor_hl(entry) end function Previewer.buffer_or_file:update_title(entry) - if not self.title then return end + if not self.title then + return + end local filepath = entry.path if filepath then if filepath:match("^%[DEBUG]") then @@ -1278,7 +1428,9 @@ end ---@param entry fzf-lua.buffer_or_file.Entry function Previewer.buffer_or_file:preview_buf_post(entry, min_winopts) - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end if not self:preview_is_terminal() then -- set cursor highlights for line|col or tag self:set_cursor_hl(entry) @@ -1351,7 +1503,9 @@ function Previewer.help_tags:parse_entry(entry_str) if uv.fs_stat(tagfile) then for line in io.lines(tagfile) do local res = line:match("^" .. vim.pesc(tag) .. "\t[^\t]+\t/(.*)") - if res then return res end + if res then + return res + end end end end @@ -1366,8 +1520,8 @@ end function Previewer.help_tags:gen_winopts() local winopts = { - wrap = self.win.preview_wrap, - number = false + wrap = self.win.preview_wrap, + number = false, } return vim.tbl_extend("keep", winopts, self.winopts) end @@ -1397,9 +1551,9 @@ end function Previewer.man_pages:gen_winopts() local winopts = { - wrap = self.win.preview_wrap, + wrap = self.win.preview_wrap, cursorline = false, - number = false + number = false, } return vim.tbl_extend("keep", winopts, self.winopts) end @@ -1419,7 +1573,9 @@ end function Previewer.man_pages:populate_preview_buf(entry_str) local entry = self:parse_entry(entry_str) local cmd = self.cmd:format(entry) - if type(cmd) == "string" then cmd = { "sh", "-c", cmd } end + if type(cmd) == "string" then + cmd = { "sh", "-c", cmd } + end local output, _ = utils.io_systemlist(cmd) local tmpbuf = self:get_tmp_buffer() -- vim.api.nvim_buf_set_option(tmpbuf, 'modifiable', true) @@ -1441,7 +1597,9 @@ end function Previewer.marks:parse_entry(entry_str) local bufnr = nil local mark, lnum, col, filepath = entry_str:match("(.)%s+(%d+)%s+(%d+)%s+(.*)") - if not mark then return {} end + if not mark then + return {} + end -- try to acquire position from sending buffer -- if this succeeds (line>0) the mark is inside @@ -1466,9 +1624,9 @@ function Previewer.marks:parse_entry(entry_str) end return { bufnr = bufnr, - path = filepath, - line = tonumber(lnum) or 1, - col = tonumber(col) or 1, + path = filepath, + line = tonumber(lnum) or 1, + col = tonumber(col) or 1, } end @@ -1498,9 +1656,9 @@ function Previewer.jumps:parse_entry(entry_str) end return { bufnr = bufnr, - path = filepath, - line = tonumber(lnum) or 1, - col = tonumber(col) + 1 or 1, + path = filepath, + line = tonumber(lnum) or 1, + col = tonumber(col) + 1 or 1, } end @@ -1543,8 +1701,8 @@ end function Previewer.highlights:gen_winopts() local winopts = { - wrap = self.win.preview_wrap, - number = false + wrap = self.win.preview_wrap, + number = false, } return vim.tbl_extend("keep", winopts, self.winopts) end @@ -1564,12 +1722,12 @@ end function Previewer.highlights:populate_preview_buf(entry_str) if not self.tmpbuf then - local output = vim.split(vim.fn.execute "highlight", "\n") + local output = vim.split(vim.fn.execute("highlight"), "\n") local hl_groups = {} for _, v in ipairs(output) do if v ~= "" then if v:sub(1, 1) == " " then - local part_of_old = v:match "%s+(.*)" + local part_of_old = v:match("%s+(.*)") hl_groups[#hl_groups] = hl_groups[#hl_groups] .. part_of_old else table.insert(hl_groups, v) @@ -1628,9 +1786,9 @@ end function Previewer.quickfix:gen_winopts() local winopts = { - wrap = self.win.preview_wrap, + wrap = self.win.preview_wrap, cursorline = false, - number = false + number = false, } return vim.tbl_extend("keep", winopts, self.winopts) end @@ -1652,17 +1810,23 @@ function Previewer.quickfix:populate_preview_buf(entry_str) local qf_list = self.opts._is_loclist and vim.fn.getloclist(self.win.src_winid, { all = "", nr = tonumber(nr) }) - or vim.fn.getqflist({ all = "", nr = tonumber(nr) }) + or vim.fn.getqflist({ all = "", nr = tonumber(nr) }) if utils.tbl_isempty(qf_list) or utils.tbl_isempty(qf_list.items) then return end local lines = {} for _, e in ipairs(qf_list.items) do - table.insert(lines, string.format("%s|%d col %d|%s", - path.HOME_to_tilde(path.relative_to( - vim.api.nvim_buf_get_name(e.bufnr), uv.cwd())), - e.lnum, e.col, e.text)) + table.insert( + lines, + string.format( + "%s|%d col %d|%s", + path.HOME_to_tilde(path.relative_to(vim.api.nvim_buf_get_name(e.bufnr), uv.cwd())), + e.lnum, + e.col, + e.text + ) + ) end self.tmpbuf = self:get_tmp_buffer() vim.api.nvim_buf_set_lines(self.tmpbuf, 0, -1, false, lines) @@ -1687,17 +1851,21 @@ function Previewer.autocmds:gen_winopts() end -- set wrap and no cursorline/numbers for vimL commands local winopts = { - wrap = true, + wrap = true, cursorline = false, - number = false + number = false, } return vim.tbl_extend("keep", winopts, self.winopts) end function Previewer.autocmds:populate_preview_buf(entry_str) - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end local entry = self:parse_entry(entry_str) - if utils.tbl_isempty(entry) then return end + if utils.tbl_isempty(entry) then + return + end self._is_vimL_command = false if entry.path == "" then self._is_vimL_command = true @@ -1728,7 +1896,9 @@ function Previewer.keymaps:parse_entry(entry_str) end function Previewer.keymaps:populate_preview_buf(entry_str) - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end local entry = self:parse_entry(entry_str) if entry.vmap then -- keymap is vimL, there is no source file info @@ -1808,9 +1978,13 @@ function Previewer.nvim_options:parse_entry(entry_str) end function Previewer.nvim_options:populate_preview_buf(entry_str) - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end local entry = self:parse_entry(entry_str) - if utils.tbl_isempty(entry) then return end + if utils.tbl_isempty(entry) then + return + end local header = { "Value: " .. entry.value, diff --git a/lua/fzf-lua/previewer/codeaction.lua b/lua/fzf-lua/previewer/codeaction.lua index 48fbed2c6..48e3aed26 100644 --- a/lua/fzf-lua/previewer/codeaction.lua +++ b/lua/fzf-lua/previewer/codeaction.lua @@ -1,5 +1,5 @@ -local utils = require "fzf-lua.utils" -local shell = require "fzf-lua.shell" +local utils = require("fzf-lua.utils") +local shell = require("fzf-lua.shell") local native = require("fzf-lua.previewer.fzf") local builtin = require("fzf-lua.previewer.builtin") @@ -33,10 +33,8 @@ local function diff_text_edits(text_edits, bufnr, offset_encoding, diff_opts) vim.lsp.util.apply_text_edits(text_edits, tmpbuf, offset_encoding) local new_lines = get_lines(tmpbuf) vim.api.nvim_buf_delete(tmpbuf, { force = true }) - local diff = vim.diff( - table.concat(orig_lines, eol) .. eol, - table.concat(new_lines, eol) .. eol, - diff_opts) + local diff = + vim.diff(table.concat(orig_lines, eol) .. eol, table.concat(new_lines, eol) .. eol, diff_opts) -- Windows: some LSPs use "\n" for EOL (e.g clangd) -- remove both "\n" and "\r\n" (#1172) return utils.strsplit(vim.trim(diff), "\r?\n") @@ -124,7 +122,7 @@ end local function diff_tuple(err, tuple, diff_opts) if err then return { - string.format('"codeAction/resolve" failed with error %d: %s', err.code, err.message) + string.format('"codeAction/resolve" failed with error %d: %s', err.code, err.message), } end local action = tuple[2] @@ -136,9 +134,11 @@ local function diff_tuple(err, tuple, diff_opts) return { string.format( "Code action preview is only available for document/workspace edits (%s).", - command and type(command.command) == "string" - and string.format("command:%s", command.command) - or string.format("kind:%s", action.kind)) + command + and type(command.command) == "string" + and string.format("command:%s", command.command) + or string.format("kind:%s", action.kind) + ), } end end @@ -171,10 +171,10 @@ local function preview_action_tuple(self, idx, callback) local bufnr = assert(choice.ctx.bufnr, "Must have buffer number") local reg = client.dynamic_capabilities:get(ms.textDocument_codeAction, { bufnr = bufnr }) return utils.tbl_get(reg or {}, "registerOptions", "resolveProvider") - or client:supports_method(ms.codeAction_resolve) + or client:supports_method(ms.codeAction_resolve) end)() - -- prior to nvim 0.10 we could check `client.server_capabilities` - or utils.tbl_get(client.server_capabilities, "codeActionProvider", "resolveProvider") + -- prior to nvim 0.10 we could check `client.server_capabilities` + or utils.tbl_get(client.server_capabilities, "codeActionProvider", "resolveProvider") if not action.edit and client and supports_resolve then -- Action is not a workspace edit, attempt to resolve the code action -- in case it resolves to a workspace edit @@ -187,7 +187,7 @@ local function preview_action_tuple(self, idx, callback) err = err, -- Due to a bug in `typescript-tools.nvim` only the first call to `codeAction/resolve` -- returns a valid action (non-nil), return nil tuple if the action is nil (#949) - tuple = resolved_action and { client_id, resolved_action } or nil + tuple = resolved_action and { client_id, resolved_action } or nil, } self._resolved_actions[idx] = resolved -- HACK: due to upstream bug with jdtls calling resolve messes @@ -218,7 +218,6 @@ local function preview_action_tuple(self, idx, callback) end end - M.builtin = builtin.base:extend() M.builtin.preview_action_tuple = preview_action_tuple @@ -236,25 +235,34 @@ end function M.builtin:gen_winopts() local winopts = { - wrap = false, + wrap = false, cursorline = false, - number = false + number = false, } return vim.tbl_extend("keep", winopts, self.winopts) end function M.builtin:populate_preview_buf(entry_str) - if not self.win or not self.win:validate_preview() then return end + if not self.win or not self.win:validate_preview() then + return + end local idx = tonumber(entry_str:match("^%s*(%d+)%.")) assert(type(idx) == "number") - local lines = self:preview_action_tuple(idx, + local lines = self:preview_action_tuple( + idx, -- use the async version for "codeAction/resolve" function(err, resolved_tuple) if vim.api.nvim_buf_is_valid(self.tmpbuf) then - vim.api.nvim_buf_set_lines(self.tmpbuf, 0, -1, false, - diff_tuple(err, resolved_tuple, self.diff_opts)) + vim.api.nvim_buf_set_lines( + self.tmpbuf, + 0, + -1, + false, + diff_tuple(err, resolved_tuple, self.diff_opts) + ) end - end) + end + ) self.tmpbuf = self:get_tmp_buffer() vim.api.nvim_buf_set_lines(self.tmpbuf, 0, -1, false, lines) vim.bo[self.tmpbuf].filetype = "git" diff --git a/lua/fzf-lua/previewer/fzf.lua b/lua/fzf-lua/previewer/fzf.lua index 268cb50de..d43d1af53 100644 --- a/lua/fzf-lua/previewer/fzf.lua +++ b/lua/fzf-lua/previewer/fzf.lua @@ -1,9 +1,9 @@ local uv = vim.uv or vim.loop -local path = require "fzf-lua.path" -local shell = require "fzf-lua.shell" -local utils = require "fzf-lua.utils" -local libuv = require "fzf-lua.libuv" -local Object = require "fzf-lua.class" +local path = require("fzf-lua.path") +local shell = require("fzf-lua.shell") +local utils = require("fzf-lua.utils") +local libuv = require("fzf-lua.libuv") +local Object = require("fzf-lua.class") local Previewer = {} @@ -12,14 +12,14 @@ Previewer.base = Object:extend() -- Previewer base object function Previewer.base:new(o, opts) o = o or {} - self.type = "cmd"; - self.cmd = o.cmd; + self.type = "cmd" + self.cmd = o.cmd if type(self.cmd) == "function" then self.cmd = self.cmd() end - self.args = o.args or ""; + self.args = o.args or "" self.preview_offset = o.preview_offset - self.opts = opts; + self.opts = opts return self end @@ -72,8 +72,7 @@ function Previewer.cmd:new(o, opts) end function Previewer.cmd:format_cmd(cmd, args, action, extra_args) - return string.format([[%s %s %s "$(%s)"]], - cmd, args or "", extra_args or "", action) + return string.format([[%s %s %s "$(%s)"]], cmd, args or "", extra_args or "", action) end function Previewer.cmd:cmdline(o) @@ -144,10 +143,11 @@ local grep_tag = function(file, tag) local line = 1 local filepath = file local pattern = utils.rg_escape(vim.trim(tag)) - if not pattern or not filepath then return line end - local grep_cmd = vim.fn.executable("rg") == 1 - and { "rg", "--line-number" } - or { "grep", "-n", "-P" } + if not pattern or not filepath then + return line + end + local grep_cmd = vim.fn.executable("rg") == 1 and { "rg", "--line-number" } + or { "grep", "-n", "-P" } -- ctags uses '$' at the end of short patterns -- 'rg|grep' does not match these properly when -- 'fileformat' isn't set to 'unix', when set to @@ -198,9 +198,13 @@ function Previewer.cmd_async:parse_entry_and_verify(entrystr) else -- verify the file exists on disk and is accessible if #filepath == 0 or not uv.fs_stat(filepath) then - errcmd = "echo " .. libuv.shellescape( - string.format("'%s: NO SUCH FILE OR ACCESS DENIED", - filepath and #filepath > 0 and filepath or "")) + errcmd = "echo " + .. libuv.shellescape( + string.format( + "'%s: NO SUCH FILE OR ACCESS DENIED", + filepath and #filepath > 0 and filepath or "" + ) + ) end end return filepath, entry, errcmd @@ -211,8 +215,7 @@ function Previewer.cmd_async:cmdline(o) local act = shell.raw_preview_action_cmd(function(items) self._last_query = items[2] or "" local filepath, _, errcmd = self:parse_entry_and_verify(items[1]) - local cmd = errcmd or ("%s %s %s"):format( - self.cmd, self.args, libuv.shellescape(filepath)) + local cmd = errcmd or ("%s %s %s"):format(self.cmd, self.args, libuv.shellescape(filepath)) return cmd end, "{} {q}", self.opts.debug) return act @@ -270,13 +273,18 @@ function Previewer.bat_async:cmdline(o) local end_line = start_line + fzf_lines - 1 line_range = ("--line-range=%d:%d"):format(start_line, end_line) end - local cmd = errcmd or ("%s %s %s %s %s %s"):format( - self.cmd, self.args, - self.theme and string.format([[--theme="%s"]], self.theme) or "", - tonumber(entry.line) and tonumber(entry.line) > 0 - and string.format("--highlight-line=%d", entry.line) or "", - line_range, - libuv.shellescape(filepath)) + local cmd = errcmd + or ("%s %s %s %s %s %s"):format( + self.cmd, + self.args, + self.theme and string.format([[--theme="%s"]], self.theme) or "", + tonumber(entry.line) + and tonumber(entry.line) > 0 + and string.format("--highlight-line=%d", entry.line) + or "", + line_range, + libuv.shellescape(filepath) + ) return cmd end, "{} {q}", self.opts.debug) return act @@ -298,9 +306,10 @@ function Previewer.git_diff:new(o, opts) local icons_overrides = o._fn_git_icons and o._fn_git_icons() self.git_icons = {} for _, i in ipairs({ "D", "M", "R", "A", "C", "T", "?" }) do - self.git_icons[i] = - icons_overrides and icons_overrides[i] and - utils.lua_regex_escape(icons_overrides[i].icon) or i + self.git_icons[i] = icons_overrides + and icons_overrides[i] + and utils.lua_regex_escape(icons_overrides[i].icon) + or i end end return self @@ -314,16 +323,18 @@ function Previewer.git_diff:cmdline(o) return end local is_deleted = items[1]:match(self.git_icons["D"] .. utils.nbsp) ~= nil - local is_modified = items[1]:match("[" .. - self.git_icons["M"] .. - self.git_icons["R"] .. - self.git_icons["A"] .. - self.git_icons["T"] .. - "]" .. utils.nbsp) ~= nil - local is_untracked = items[1]:match("[" .. - self.git_icons["?"] .. - self.git_icons["C"] .. - "]" .. utils.nbsp) ~= nil + local is_modified = items[1]:match( + "[" + .. self.git_icons["M"] + .. self.git_icons["R"] + .. self.git_icons["A"] + .. self.git_icons["T"] + .. "]" + .. utils.nbsp + ) ~= nil + local is_untracked = items[1]:match( + "[" .. self.git_icons["?"] .. self.git_icons["C"] .. "]" .. utils.nbsp + ) ~= nil local file = items[1] if file:match("%s%->%s") then -- for renames, we take only the last part (#864) @@ -343,11 +354,14 @@ function Previewer.git_diff:cmdline(o) cmd = self.cmd_untracked end end - if not cmd then return "" end - if type(cmd) == "table" then return table.concat(cmd, " ") end + if not cmd then + return "" + end + if type(cmd) == "table" then + return table.concat(cmd, " ") + end local pager = "" - if self.pager and #self.pager > 0 and - vim.fn.executable(self.pager:match("[^%s]+")) == 1 then + if self.pager and #self.pager > 0 and vim.fn.executable(self.pager:match("[^%s]+")) == 1 then -- style 2: as we are unable to use %var% within a "cmd /c" without !var! expansion -- https://superuser.com/questions/223104/setting-and-using-variable-within-same-command-line-in-windows-cmd-ex pager = "| " .. utils._if_win_normalize_vars(self.pager, 2) @@ -368,9 +382,9 @@ function Previewer.git_diff:cmdline(o) cmd = string.format("%s %s", cmd, fname_escaped) end local env = { - ["LINES"] = fzf_lines, - ["COLUMNS"] = fzf_columns, - ["FZF_PREVIEW_LINES"] = fzf_lines, + ["LINES"] = fzf_lines, + ["COLUMNS"] = fzf_columns, + ["FZF_PREVIEW_LINES"] = fzf_lines, ["FZF_PREVIEW_COLUMNS"] = fzf_columns, } local setenv = utils.shell_setenv_str(env) @@ -409,9 +423,9 @@ end function Previewer.help_tags:new(o, opts) Previewer.help_tags.super.new(self, o, opts) - self.cmd = self.cmd or vim.fn.executable("bat") == 1 - and "bat -p -l help --color=always %s" - or "cat %s" + self.cmd = self.cmd + or vim.fn.executable("bat") == 1 and "bat -p -l help --color=always %s" + or "cat %s" return self end diff --git a/lua/fzf-lua/previewer/init.lua b/lua/fzf-lua/previewer/init.lua index f824d6316..5d9e4577e 100644 --- a/lua/fzf-lua/previewer/init.lua +++ b/lua/fzf-lua/previewer/init.lua @@ -1,30 +1,70 @@ local Previewer = {} Previewer.fzf = {} -Previewer.fzf.cmd = function() return require "fzf-lua.previewer.fzf".cmd end -Previewer.fzf.bat = function() return require "fzf-lua.previewer.fzf".bat end -Previewer.fzf.head = function() return require "fzf-lua.previewer.fzf".head end -Previewer.fzf.cmd_async = function() return require "fzf-lua.previewer.fzf".cmd_async end -Previewer.fzf.bat_async = function() return require "fzf-lua.previewer.fzf".bat_async end -Previewer.fzf.git_diff = function() return require "fzf-lua.previewer.fzf".git_diff end -Previewer.fzf.man_pages = function() return require "fzf-lua.previewer.fzf".man_pages end -Previewer.fzf.help_tags = function() return require "fzf-lua.previewer.fzf".help_tags end -Previewer.fzf.codeaction = function() return require "fzf-lua.previewer.codeaction".native end +Previewer.fzf.cmd = function() + return require("fzf-lua.previewer.fzf").cmd +end +Previewer.fzf.bat = function() + return require("fzf-lua.previewer.fzf").bat +end +Previewer.fzf.head = function() + return require("fzf-lua.previewer.fzf").head +end +Previewer.fzf.cmd_async = function() + return require("fzf-lua.previewer.fzf").cmd_async +end +Previewer.fzf.bat_async = function() + return require("fzf-lua.previewer.fzf").bat_async +end +Previewer.fzf.git_diff = function() + return require("fzf-lua.previewer.fzf").git_diff +end +Previewer.fzf.man_pages = function() + return require("fzf-lua.previewer.fzf").man_pages +end +Previewer.fzf.help_tags = function() + return require("fzf-lua.previewer.fzf").help_tags +end +Previewer.fzf.codeaction = function() + return require("fzf-lua.previewer.codeaction").native +end Previewer.builtin = {} Previewer.builtin.buffer_or_file = function() - return require "fzf-lua.previewer.builtin".buffer_or_file -end -Previewer.builtin.help_tags = function() return require "fzf-lua.previewer.builtin".help_tags end -Previewer.builtin.man_pages = function() return require "fzf-lua.previewer.builtin".man_pages end -Previewer.builtin.marks = function() return require "fzf-lua.previewer.builtin".marks end -Previewer.builtin.jumps = function() return require "fzf-lua.previewer.builtin".jumps end -Previewer.builtin.tags = function() return require "fzf-lua.previewer.builtin".tags end -Previewer.builtin.quickfix = function() return require "fzf-lua.previewer.builtin".quickfix end -Previewer.builtin.highlights = function() return require "fzf-lua.previewer.builtin".highlights end -Previewer.builtin.autocmds = function() return require "fzf-lua.previewer.builtin".autocmds end -Previewer.builtin.keymaps = function() return require "fzf-lua.previewer.builtin".keymaps end -Previewer.builtin.nvim_options = function() return require "fzf-lua.previewer.builtin".nvim_options end -Previewer.builtin.codeaction = function() return require "fzf-lua.previewer.codeaction".builtin end + return require("fzf-lua.previewer.builtin").buffer_or_file +end +Previewer.builtin.help_tags = function() + return require("fzf-lua.previewer.builtin").help_tags +end +Previewer.builtin.man_pages = function() + return require("fzf-lua.previewer.builtin").man_pages +end +Previewer.builtin.marks = function() + return require("fzf-lua.previewer.builtin").marks +end +Previewer.builtin.jumps = function() + return require("fzf-lua.previewer.builtin").jumps +end +Previewer.builtin.tags = function() + return require("fzf-lua.previewer.builtin").tags +end +Previewer.builtin.quickfix = function() + return require("fzf-lua.previewer.builtin").quickfix +end +Previewer.builtin.highlights = function() + return require("fzf-lua.previewer.builtin").highlights +end +Previewer.builtin.autocmds = function() + return require("fzf-lua.previewer.builtin").autocmds +end +Previewer.builtin.keymaps = function() + return require("fzf-lua.previewer.builtin").keymaps +end +Previewer.builtin.nvim_options = function() + return require("fzf-lua.previewer.builtin").nvim_options +end +Previewer.builtin.codeaction = function() + return require("fzf-lua.previewer.codeaction").builtin +end return Previewer diff --git a/lua/fzf-lua/profiles/border-fused.lua b/lua/fzf-lua/profiles/border-fused.lua index 558e9372c..0dc637d45 100644 --- a/lua/fzf-lua/profiles/border-fused.lua +++ b/lua/fzf-lua/profiles/border-fused.lua @@ -1,12 +1,12 @@ -local _single = { "┌", "─", "┐", "│", "┘", "─", "└", "│" } +local _single = { "┌", "─", "┐", "│", "┘", "─", "└", "│" } local _rounded = { "╭", "─", "╮", "│", "╯", "─", "╰", "│" } -local _border = true and _rounded or _single +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) + border = function(_, m) assert(m.type == "nvim" and m.name == "fzf") if m.nwin == 1 then -- No preview, return the border whole diff --git a/lua/fzf-lua/profiles/borderless-full.lua b/lua/fzf-lua/profiles/borderless-full.lua index 7e33f69ee..ff3656861 100644 --- a/lua/fzf-lua/profiles/borderless-full.lua +++ b/lua/fzf-lua/profiles/borderless-full.lua @@ -1,13 +1,13 @@ local hls = { - bg = "PmenuSbar", - sel = "PmenuSel", - title = "IncSearch" + bg = "PmenuSbar", + sel = "PmenuSel", + title = "IncSearch", } return { { "default-title" }, -- base profile - desc = "borderless and not so minimalistic", - winopts = { - border = { " ", " ", " ", " ", "", "", "", " " }, -- "solid-top" (+side margins) + desc = "borderless and not so minimalistic", + winopts = { + border = { " ", " ", " ", " ", "", "", "", " " }, -- "solid-top" (+side margins) preview = { border = "solid", scrollbar = "float", @@ -15,19 +15,19 @@ return { title_pos = "center", }, }, - hls = { - title = hls.title, - border = hls.bg, - preview_title = hls.title, + hls = { + title = hls.title, + border = hls.bg, + preview_title = hls.title, preview_border = hls.bg, - scrollfloat_e = "", - scrollfloat_f = hls.sel, + scrollfloat_e = "", + scrollfloat_f = hls.sel, }, fzf_colors = { ["gutter"] = { "bg", hls.bg }, - ["bg"] = { "bg", hls.bg }, - ["bg+"] = { "bg", hls.sel }, - ["fg+"] = { "fg", hls.sel }, + ["bg"] = { "bg", hls.bg }, + ["bg+"] = { "bg", hls.sel }, + ["fg+"] = { "fg", hls.sel }, }, - grep = { rg_glob = true }, + grep = { rg_glob = true }, } diff --git a/lua/fzf-lua/profiles/borderless.lua b/lua/fzf-lua/profiles/borderless.lua index 532242fe4..bb0533409 100644 --- a/lua/fzf-lua/profiles/borderless.lua +++ b/lua/fzf-lua/profiles/borderless.lua @@ -1,33 +1,33 @@ local hls = { - bg = "PmenuSbar", + bg = "PmenuSbar", sel = "PmenuSel", } return { { "default-prompt" }, -- base profile - desc = "borderless and minimalistic", - fzf_opts = {}, - winopts = { - border = "none", + desc = "borderless and minimalistic", + fzf_opts = {}, + winopts = { + border = "none", preview = { border = "none", scrollbar = "border", }, }, - hls = { - border = hls.bg, + hls = { + border = hls.bg, preview_border = hls.bg, - preview_title = hls.sel, - scrollfloat_f = hls.sel, + preview_title = hls.sel, + scrollfloat_f = hls.sel, scrollborder_f = hls.bg, }, fzf_colors = { ["gutter"] = { "bg", hls.bg }, - ["bg"] = { "bg", hls.bg }, - ["bg+"] = { "bg", hls.sel }, - ["fg+"] = { "fg", hls.sel }, + ["bg"] = { "bg", hls.bg }, + ["bg+"] = { "bg", hls.sel }, + ["fg+"] = { "fg", hls.sel }, -- ["fg+"] = { "fg", "", "reverse:-1" }, }, - defaults = { + defaults = { git_icons = false, file_icons = false, }, diff --git a/lua/fzf-lua/profiles/default-prompt.lua b/lua/fzf-lua/profiles/default-prompt.lua index 21c74ceb3..474c5d71c 100644 --- a/lua/fzf-lua/profiles/default-prompt.lua +++ b/lua/fzf-lua/profiles/default-prompt.lua @@ -2,68 +2,68 @@ local function prompt(str, opts) return vim.tbl_deep_extend("keep", opts or {}, { prompt = str .. "> " }) end return { - desc = "defaults using prompt for picker info", - winopts = { title_pos = "center", preview = { title_pos = "center" } }, + desc = "defaults using prompt for picker info", + winopts = { title_pos = "center", preview = { title_pos = "center" } }, -- Uses `cwd_prompt` by default -- files = prompt("Files"), - buffers = prompt("Buffers"), - tabs = prompt("Tabs"), - lines = prompt("Lines"), - blines = prompt("BLines"), - treesitter = prompt("Treesitter"), - grep = prompt("Grep"), - grep_curbuf = prompt("BGrep"), - git = { - files = prompt("GitFiles"), - status = prompt("GitStatus"), - commits = prompt("GitCommits"), + buffers = prompt("Buffers"), + tabs = prompt("Tabs"), + lines = prompt("Lines"), + blines = prompt("BLines"), + treesitter = prompt("Treesitter"), + grep = prompt("Grep"), + grep_curbuf = prompt("BGrep"), + git = { + files = prompt("GitFiles"), + status = prompt("GitStatus"), + commits = prompt("GitCommits"), bcommits = prompt("GitBCommits"), - blame = prompt("GitBlame"), + blame = prompt("GitBlame"), branches = prompt("GitBranches"), - stash = prompt("GitStash"), + stash = prompt("GitStash"), }, - args = prompt("Args"), - oldfiles = prompt("Oldfiles"), - quickfix = prompt("Quickfix"), - quickfix_stack = prompt("Quickfix Stack"), - loclist = prompt("Location"), - loclist_stack = prompt("Location Stack"), - tags = prompt("Tags"), - btags = prompt("BTags"), - colorschemes = prompt("Colorschemes"), + args = prompt("Args"), + oldfiles = prompt("Oldfiles"), + quickfix = prompt("Quickfix"), + quickfix_stack = prompt("Quickfix Stack"), + loclist = prompt("Location"), + loclist_stack = prompt("Location Stack"), + tags = prompt("Tags"), + btags = prompt("BTags"), + colorschemes = prompt("Colorschemes"), awesome_colorschemes = prompt("Awesome Colorschemes"), - highlights = prompt("Highlights"), - helptags = prompt("Help"), - manpages = prompt("Man"), - lsp = { + highlights = prompt("Highlights"), + helptags = prompt("Help"), + manpages = prompt("Man"), + lsp = { prompt_postfix = "> ", - symbols = { prompt_postfix = "> " }, - finder = prompt("LSP Finder"), - code_actions = prompt("Code Actions"), + symbols = { prompt_postfix = "> " }, + finder = prompt("LSP Finder"), + code_actions = prompt("Code Actions"), }, - diagnostics = prompt("Diagnostics"), - builtin = prompt("Builtin"), - profiles = prompt("Profiles"), - marks = prompt("Marks"), - jumps = prompt("Jumps"), - tagstack = prompt("Tagstack"), - commands = prompt("Commands"), - autocmds = prompt("Autocmds"), - command_history = prompt("Command history"), - search_history = prompt("Search history"), - registers = prompt("Registers"), - keymaps = prompt("Keymaps"), - nvim_options = prompt("Nvim Options"), - spell_suggest = prompt("Spell Suggestions"), - filetypes = prompt("Filetypes"), - packadd = prompt("Packadd"), - menus = prompt("Menus"), - tmux = prompt("Tmux Buffers"), - dap = { - commands = prompt("DAP Commands"), + diagnostics = prompt("Diagnostics"), + builtin = prompt("Builtin"), + profiles = prompt("Profiles"), + marks = prompt("Marks"), + jumps = prompt("Jumps"), + tagstack = prompt("Tagstack"), + commands = prompt("Commands"), + autocmds = prompt("Autocmds"), + command_history = prompt("Command history"), + search_history = prompt("Search history"), + registers = prompt("Registers"), + keymaps = prompt("Keymaps"), + nvim_options = prompt("Nvim Options"), + spell_suggest = prompt("Spell Suggestions"), + filetypes = prompt("Filetypes"), + packadd = prompt("Packadd"), + menus = prompt("Menus"), + tmux = prompt("Tmux Buffers"), + dap = { + commands = prompt("DAP Commands"), configurations = prompt("DAP Configurations"), - variables = prompt("DAP Variables"), - frames = prompt("DAP Frames"), - breakpoints = prompt("DAP Breakpoints"), + variables = prompt("DAP Variables"), + frames = prompt("DAP Frames"), + breakpoints = prompt("DAP Breakpoints"), }, } diff --git a/lua/fzf-lua/profiles/default-title.lua b/lua/fzf-lua/profiles/default-title.lua index 01ac73d06..fbaac65bb 100644 --- a/lua/fzf-lua/profiles/default-title.lua +++ b/lua/fzf-lua/profiles/default-title.lua @@ -3,71 +3,71 @@ local function title(str, opts) winopts = { -- title = { { " " .. str .. " ", "IncSearch" } }, title = " " .. str .. " ", - } + }, }) end return { - desc = "defaults using title for picker info", - winopts = { title_pos = "center", preview = { title_pos = "center" } }, - files = title("Files"), - buffers = title("Buffers"), - tabs = title("Tabs"), - lines = title("Lines"), - blines = title("Buffer Lines"), - treesitter = title("Treesitter"), - grep = title("Grep"), - grep_curbuf = title("Buffer Grep"), - git = { - files = title("Git Files"), - status = title("Git Status"), - commits = title("Git Commits"), + desc = "defaults using title for picker info", + winopts = { title_pos = "center", preview = { title_pos = "center" } }, + files = title("Files"), + buffers = title("Buffers"), + tabs = title("Tabs"), + lines = title("Lines"), + blines = title("Buffer Lines"), + treesitter = title("Treesitter"), + grep = title("Grep"), + grep_curbuf = title("Buffer Grep"), + git = { + files = title("Git Files"), + status = title("Git Status"), + commits = title("Git Commits"), bcommits = title("Git BCommits"), - blame = title("Git Blame"), + blame = title("Git Blame"), branches = title("Git Branches"), - stash = title("Git Stash"), + stash = title("Git Stash"), }, - args = title("Args"), - oldfiles = title("Oldfiles"), - quickfix = title("Quickfix List"), - quickfix_stack = title("Quickfix List Stack"), - loclist = title("Location List"), - loclist_stack = title("Location List Stack"), - tags = title("Tags"), - btags = title("Buffer Tags"), - colorschemes = title("Colorschemes"), + args = title("Args"), + oldfiles = title("Oldfiles"), + quickfix = title("Quickfix List"), + quickfix_stack = title("Quickfix List Stack"), + loclist = title("Location List"), + loclist_stack = title("Location List Stack"), + tags = title("Tags"), + btags = title("Buffer Tags"), + colorschemes = title("Colorschemes"), awesome_colorschemes = title("Awesome Colorschemes"), - highlights = title("Highlights"), - helptags = title("Neovim Help"), - manpages = title("Man Pages"), - lsp = { + highlights = title("Highlights"), + helptags = title("Neovim Help"), + manpages = title("Man Pages"), + lsp = { title_prefix = "LSP", - symbols = { title_prefix = "LSP" }, - finder = title("LSP Finder"), + symbols = { title_prefix = "LSP" }, + finder = title("LSP Finder"), code_actions = title("Code Actions"), }, - diagnostics = title("Diagnostics"), - builtin = title("FzfLua Builtin"), - profiles = title("FzfLua Profiles"), - marks = title("Marks"), - jumps = title("Jumps"), - tagstack = title("Tagstack"), - commands = title("Commands"), - autocmds = title("Autocmds"), - command_history = title("Command history"), - search_history = title("Search history"), - registers = title("Registers"), - keymaps = title("Keymaps"), - nvim_options = title("Nvim Options"), - spell_suggest = title("Spell Suggestions"), - filetypes = title("Filetypes"), - packadd = title("Packadd"), - menus = title("Menus"), - tmux = title("Tmux Buffers"), - dap = { - commands = title("DAP Commands"), + diagnostics = title("Diagnostics"), + builtin = title("FzfLua Builtin"), + profiles = title("FzfLua Profiles"), + marks = title("Marks"), + jumps = title("Jumps"), + tagstack = title("Tagstack"), + commands = title("Commands"), + autocmds = title("Autocmds"), + command_history = title("Command history"), + search_history = title("Search history"), + registers = title("Registers"), + keymaps = title("Keymaps"), + nvim_options = title("Nvim Options"), + spell_suggest = title("Spell Suggestions"), + filetypes = title("Filetypes"), + packadd = title("Packadd"), + menus = title("Menus"), + tmux = title("Tmux Buffers"), + dap = { + commands = title("DAP Commands"), configurations = title("DAP Configurations"), - variables = title("DAP Variables"), - frames = title("DAP Frames"), - breakpoints = title("DAP Breakpoints"), + variables = title("DAP Variables"), + frames = title("DAP Frames"), + breakpoints = title("DAP Breakpoints"), }, } diff --git a/lua/fzf-lua/profiles/hide.lua b/lua/fzf-lua/profiles/hide.lua index 9f40981e5..ee61df95b 100644 --- a/lua/fzf-lua/profiles/hide.lua +++ b/lua/fzf-lua/profiles/hide.lua @@ -1,16 +1,16 @@ local uv = vim.uv or vim.loop local fzf = require("fzf-lua") -local shell = require "fzf-lua.shell" +local shell = require("fzf-lua.shell") return { - desc = "hide interface instead of abort", - keymap = { + desc = "hide interface instead of abort", + keymap = { builtin = { true, -- NOTE: we use a custom callback that also sends esc to fzf -- so we can store the last query on the execute-silent callback -- [""] = "hide", - [""] = "abort" - } + [""] = "abort", + }, }, defaults = { enrich = function(opts) @@ -53,14 +53,15 @@ return { } opts.actions = vim.tbl_map(function(act) act = type(act) == "function" and { fn = act } or act - act = type(act) == "table" and type(act[1]) == "function" - and { fn = act[1], reuse = true } or act + act = type(act) == "table" and type(act[1]) == "function" and { fn = act[1], reuse = true } + or act assert(type(act) == "table" and type(act.fn) == "function" or not act) - if type(act) == "table" and - not act.exec_silent - and not act.reload - and not act.noclose - and not act.reuse + if + type(act) == "table" + and not act.exec_silent + and not act.reload + and not act.noclose + and not act.reuse then local fn = act.fn act.exec_silent = true @@ -84,14 +85,15 @@ return { return act end, opts.actions) -- Hijack the resize event to reload buffer/tab list on unhide - opts.keymap.fzf.resize = "transform:" .. shell.raw_action(function(_, _, _) - if opts._unhide_called then - opts._unhide_called = nil - if opts.__reload_cmd then - return string.format("reload:%s", opts.__reload_cmd) + opts.keymap.fzf.resize = "transform:" + .. shell.raw_action(function(_, _, _) + if opts._unhide_called then + opts._unhide_called = nil + if opts.__reload_cmd then + return string.format("reload:%s", opts.__reload_cmd) + end end - end - end, "{q}", opts.debug) + end, "{q}", opts.debug) return opts end, }, diff --git a/lua/fzf-lua/profiles/ivy.lua b/lua/fzf-lua/profiles/ivy.lua index cb4ce6d1c..302838167 100644 --- a/lua/fzf-lua/profiles/ivy.lua +++ b/lua/fzf-lua/profiles/ivy.lua @@ -1,4 +1,4 @@ -local M = { +local M = { { "default-title" }, -- base profile desc = "UI at the bottom of the screen", winopts = { @@ -36,11 +36,11 @@ local M = { return b end end, - } + }, }, } -local up = { +local up = { row = 1, col = 0, width = 1, @@ -52,10 +52,10 @@ local up = { }, } -M.blines = { winopts = up, previewer = { toggle_behavior = "extend" } } -M.lines = M.blines -M.grep = M.blines +M.blines = { winopts = up, previewer = { toggle_behavior = "extend" } } +M.lines = M.blines +M.grep = M.blines M.grep_curbuf = M.blines -M.git = { blame = { winopts = up } } +M.git = { blame = { winopts = up } } return M diff --git a/lua/fzf-lua/profiles/max-perf.lua b/lua/fzf-lua/profiles/max-perf.lua index 1e599d23f..98060430f 100644 --- a/lua/fzf-lua/profiles/max-perf.lua +++ b/lua/fzf-lua/profiles/max-perf.lua @@ -10,12 +10,11 @@ return { btags = { previewer = "bat" }, files = { fzf_opts = { ["--ansi"] = false } }, grep = { - fzf_opts = { ["--ansi"] = false }, - rg_glob = false, -- will trigger `opts.requires_processing` + fzf_opts = { ["--ansi"] = false }, + rg_glob = false, -- will trigger `opts.requires_processing` grep_opts = require("fzf-lua.utils").is_darwin() and "--color=never --binary-files=without-match --line-number --recursive --extended-regexp -e" - or "--color=never --binary-files=without-match --line-number --recursive --perl-regexp -e", - rg_opts = - " --color=never --column --line-number --no-heading --smart-case --max-columns=4096 -e", + or "--color=never --binary-files=without-match --line-number --recursive --perl-regexp -e", + rg_opts = " --color=never --column --line-number --no-heading --smart-case --max-columns=4096 -e", }, } diff --git a/lua/fzf-lua/profiles/telescope.lua b/lua/fzf-lua/profiles/telescope.lua index 2f56367e2..752519ebb 100644 --- a/lua/fzf-lua/profiles/telescope.lua +++ b/lua/fzf-lua/profiles/telescope.lua @@ -7,35 +7,35 @@ end return { { "default-title" }, -- base profile - desc = "match telescope default highlights|keybinds", - fzf_opts = { ["--layout"] = "default", ["--marker"] = "+" }, - winopts = { - width = 0.8, - height = 0.9, + desc = "match telescope default highlights|keybinds", + fzf_opts = { ["--layout"] = "default", ["--marker"] = "+" }, + winopts = { + width = 0.8, + height = 0.9, preview = { - hidden = false, - vertical = "up:45%", - horizontal = "right:50%", - layout = "flex", + hidden = false, + vertical = "up:45%", + horizontal = "right:50%", + layout = "flex", flip_columns = 120, - delay = 10, - winopts = { number = false }, + delay = 10, + winopts = { number = false }, }, }, - hls = { - normal = hl_validate "TelescopeNormal", - border = hl_validate "TelescopeBorder", - title = hl_validate "TelescopePromptTitle", - help_normal = hl_validate "TelescopeNormal", - help_border = hl_validate "TelescopeBorder", - preview_normal = hl_validate "TelescopeNormal", - preview_border = hl_validate "TelescopeBorder", - preview_title = hl_validate "TelescopePreviewTitle", + hls = { + normal = hl_validate("TelescopeNormal"), + border = hl_validate("TelescopeBorder"), + title = hl_validate("TelescopePromptTitle"), + help_normal = hl_validate("TelescopeNormal"), + help_border = hl_validate("TelescopeBorder"), + preview_normal = hl_validate("TelescopeNormal"), + preview_border = hl_validate("TelescopeBorder"), + preview_title = hl_validate("TelescopePreviewTitle"), -- builtin preview only - cursor = hl_validate "Cursor", - cursorline = hl_validate "TelescopeSelection", - cursorlinenr = hl_validate "TelescopeSelection", - search = hl_validate "IncSearch", + cursor = hl_validate("Cursor"), + cursorline = hl_validate("TelescopeSelection"), + cursorlinenr = hl_validate("TelescopeSelection"), + search = hl_validate("IncSearch"), }, fzf_colors = { ["fg"] = { "fg", "TelescopeNormal" }, @@ -53,7 +53,7 @@ return { ["marker"] = { "fg", "TelescopeSelectionCaret" }, ["header"] = { "fg", "TelescopeTitle" }, }, - keymap = { + keymap = { builtin = { true, [""] = "preview-page-down", @@ -66,18 +66,18 @@ return { ["ctrl-q"] = "select-all+accept", }, }, - actions = { + actions = { files = { - ["enter"] = actions.file_edit_or_qf, + ["enter"] = actions.file_edit_or_qf, ["ctrl-x"] = actions.file_split, ["ctrl-v"] = actions.file_vsplit, ["ctrl-t"] = actions.file_tabedit, - ["alt-q"] = actions.file_sel_to_qf, + ["alt-q"] = actions.file_sel_to_qf, }, }, - buffers = { + buffers = { keymap = { builtin = { [""] = false } }, actions = { ["ctrl-x"] = false, ["ctrl-d"] = { actions.buf_del, actions.resume } }, }, - defaults = { git_icons = false }, + defaults = { git_icons = false }, } diff --git a/lua/fzf-lua/providers/buffers.lua b/lua/fzf-lua/providers/buffers.lua index 3f1f2a1cd..c0e6f10ea 100644 --- a/lua/fzf-lua/providers/buffers.lua +++ b/lua/fzf-lua/providers/buffers.lua @@ -1,12 +1,12 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local shell = require "fzf-lua.shell" -local config = require "fzf-lua.config" -local base64 = require "fzf-lua.lib.base64" -local devicons = require "fzf-lua.devicons" -local make_entry = require "fzf-lua.make_entry" +local core = require("fzf-lua.core") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local shell = require("fzf-lua.shell") +local config = require("fzf-lua.config") +local base64 = require("fzf-lua.lib.base64") +local devicons = require("fzf-lua.devicons") +local make_entry = require("fzf-lua.make_entry") local M = {} @@ -32,33 +32,33 @@ local filter_buffers = function(opts, unfiltered) max_bufnr = math.max(max_bufnr, b) return b end, opts.buffers) - or vim.tbl_filter(function(b) - local buf_valid = vim.api.nvim_buf_is_valid(b) - if not buf_valid then - excluded[b] = true - elseif not opts.show_unlisted and b ~= core.CTX().bufnr and vim.fn.buflisted(b) ~= 1 then - excluded[b] = true - elseif not opts.show_unloaded and not vim.api.nvim_buf_is_loaded(b) then - excluded[b] = true - elseif opts.ignore_current_buffer and b == core.CTX().bufnr then - excluded[b] = true - elseif opts.current_tab_only and not curtab_bufnrs[b] then - excluded[b] = true - elseif opts.no_term_buffers and utils.is_term_buffer(b) then - excluded[b] = true - elseif opts.cwd_only and not path.is_relative_to(vim.api.nvim_buf_get_name(b), uv.cwd()) then - excluded[b] = true - elseif opts.cwd and not path.is_relative_to(vim.api.nvim_buf_get_name(b), opts.cwd) then - excluded[b] = true - end - if buf_valid and vim.api.nvim_get_option_value("ft", { buf = b }) == "qf" then - excluded[b] = not opts.show_quickfix and true or nil - end - if not excluded[b] and b > max_bufnr then - max_bufnr = b - end - return not excluded[b] - end, unfiltered) + or vim.tbl_filter(function(b) + local buf_valid = vim.api.nvim_buf_is_valid(b) + if not buf_valid then + excluded[b] = true + elseif not opts.show_unlisted and b ~= core.CTX().bufnr and vim.fn.buflisted(b) ~= 1 then + excluded[b] = true + elseif not opts.show_unloaded and not vim.api.nvim_buf_is_loaded(b) then + excluded[b] = true + elseif opts.ignore_current_buffer and b == core.CTX().bufnr then + excluded[b] = true + elseif opts.current_tab_only and not curtab_bufnrs[b] then + excluded[b] = true + elseif opts.no_term_buffers and utils.is_term_buffer(b) then + excluded[b] = true + elseif opts.cwd_only and not path.is_relative_to(vim.api.nvim_buf_get_name(b), uv.cwd()) then + excluded[b] = true + elseif opts.cwd and not path.is_relative_to(vim.api.nvim_buf_get_name(b), opts.cwd) then + excluded[b] = true + end + if buf_valid and vim.api.nvim_get_option_value("ft", { buf = b }) == "qf" then + excluded[b] = not opts.show_quickfix and true or nil + end + if not excluded[b] and b > max_bufnr then + max_bufnr = b + end + return not excluded[b] + end, unfiltered) return bufnrs, excluded, max_bufnr end @@ -67,10 +67,9 @@ end local getbuf = function(buf) return { bufnr = buf, - flag = (buf == core.CTX().bufnr and "%") - or (buf == core.CTX().alt_bufnr and "#") or " ", + flag = (buf == core.CTX().bufnr and "%") or (buf == core.CTX().alt_bufnr and "#") or " ", info = utils.getbufinfo(buf), - readonly = vim.bo[buf].readonly + readonly = vim.bo[buf].readonly, } end @@ -126,7 +125,6 @@ local populate_buffer_entries = function(opts, bufnrs, winid) return buffers end - local function gen_buffer_entry(opts, buf, max_bufnr, cwd, prefix) -- local hidden = buf.info.hidden == 1 and 'h' or 'a' local hidden = "" @@ -143,9 +141,15 @@ local function gen_buffer_entry(opts, buf, max_bufnr, cwd, prefix) return path.tail(bname) else bname = make_entry.lcol({ filename = bname, lnum = buf.info.lnum }, opts):gsub(":$", "") - return make_entry.file(bname, vim.tbl_extend("force", opts, - -- No support for git_icons, file_icons are added later - { cwd = cwd or opts.cwd or uv.cwd(), file_icons = false, git_icons = false })) + return make_entry.file( + bname, + vim.tbl_extend( + "force", + opts, + -- No support for git_icons, file_icons are added later + { cwd = cwd or opts.cwd or uv.cwd(), file_icons = false, git_icons = false } + ) + ) end end)() if buf.flag == "%" then @@ -155,20 +159,23 @@ local function gen_buffer_entry(opts, buf, max_bufnr, cwd, prefix) else flags = utils.nbsp .. flags end - local bufnrstr = string.format("%s%s%s", leftbr, - utils.ansi_codes[opts.hls.buf_nr](tostring(buf.bufnr)), rightbr) + local bufnrstr = + string.format("%s%s%s", leftbr, utils.ansi_codes[opts.hls.buf_nr](tostring(buf.bufnr)), rightbr) local buficon = "" local hl = "" if opts.file_icons then - buficon, hl = devicons.get_devicon(buf.info.name, + buficon, hl = devicons.get_devicon( + buf.info.name, -- shell-like icon for terminal buffers - utils.is_term_bufname(buf.info.name) and "sh" or nil) + utils.is_term_bufname(buf.info.name) and "sh" or nil + ) if hl and opts.color_icons then buficon = utils.ansi_from_rgb(hl, buficon) end end local max_bufnr_w = 3 + #tostring(max_bufnr) + utils.ansi_escseq_len(bufnrstr) - local item_str = string.format("%s%s%s%s%s%s%s%s", + local item_str = string.format( + "%s%s%s%s%s%s%s%s", prefix or "", string.format("%-" .. tostring(max_bufnr_w) .. "s", bufnrstr), utils.nbsp, @@ -176,29 +183,33 @@ local function gen_buffer_entry(opts, buf, max_bufnr, cwd, prefix) utils.nbsp, buficon, utils.nbsp, - bufname) + bufname + ) return item_str end M.buffers = function(opts) opts = config.normalize_opts(opts, "buffers") - if not opts then return end - - opts.__fn_reload = opts.__fn_reload or function(_) - return function(cb) - local filtered, _, max_bufnr = filter_buffers(opts, core.CTX().buflist) - - if next(filtered) then - local buffers = populate_buffer_entries(opts, filtered) - for _, bufinfo in pairs(buffers) do - local ok, entry = pcall(gen_buffer_entry, opts, bufinfo, max_bufnr) - assert(ok and entry) - cb(entry) + if not opts then + return + end + + opts.__fn_reload = opts.__fn_reload + or function(_) + return function(cb) + local filtered, _, max_bufnr = filter_buffers(opts, core.CTX().buflist) + + if next(filtered) then + local buffers = populate_buffer_entries(opts, filtered) + for _, bufinfo in pairs(buffers) do + local ok, entry = pcall(gen_buffer_entry, opts, bufinfo, max_bufnr) + assert(ok and entry) + cb(entry) + end end + cb(nil) end - cb(nil) end - end -- build the "reload" cmd and remove '-- {+}' from the initial cmd local contents, id = shell.reload_action_cmd(opts, "") @@ -212,8 +223,8 @@ M.buffers = function(opts) end if opts.fzf_opts["--header-lines"] == nil then - opts.fzf_opts["--header-lines"] = - (not opts.ignore_current_buffer and opts.sort_lastused) and "1" + opts.fzf_opts["--header-lines"] = (not opts.ignore_current_buffer and opts.sort_lastused) + and "1" end opts = core.set_header(opts, opts.headers or { "actions", "cwd" }) @@ -238,18 +249,23 @@ M.blines = function(opts) M.buffer_lines(opts) end - M.buffer_lines = function(opts) - if not opts then return end + if not opts then + return + end - opts.fn_pre_fzf = function() core.CTX({ includeBuflist = true }) end + opts.fn_pre_fzf = function() + core.CTX({ includeBuflist = true }) + end opts.fn_pre_fzf() local contents = function(cb) local function add_entry(x, co) cb(x, function(err) coroutine.resume(co) - if err then cb(nil) end + if err then + cb(nil) + end end) coroutine.yield() end @@ -257,8 +273,10 @@ M.buffer_lines = function(opts) coroutine.wrap(function() local co = coroutine.running() - local buffers = filter_buffers(opts, - opts.current_buffer_only and { core.CTX().bufnr } or core.CTX().buflist) + 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) @@ -297,8 +315,9 @@ M.buffer_lines = function(opts) coroutine.yield() local bname, bicon = (function() - if not opts.show_bufname - or tonumber(opts.show_bufname) and tonumber(opts.show_bufname) > vim.o.columns + if + not opts.show_bufname + or tonumber(opts.show_bufname) and tonumber(opts.show_bufname) > vim.o.columns then return end @@ -338,18 +357,24 @@ M.buffer_lines = function(opts) lnum = lnum + start_line - 1 -- 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) + 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) @@ -362,7 +387,9 @@ end M.tabs = function(opts) opts = config.normalize_opts(opts, "tabs") - if not opts then return end + if not opts then + return + end local opt_hl = function(t, k, default_msg, default_hl) local hl = default_hl @@ -377,7 +404,7 @@ M.tabs = function(opts) end if type(opts[k][2]) == "string" then hl = function(s) - return utils.ansi_from_hl(opts[k][2], s); + return utils.ansi_from_hl(opts[k][2], s) end end elseif type(opts[k]) == "function" then @@ -388,88 +415,109 @@ M.tabs = function(opts) if opts.locate and utils.has(opts, "fzf", { 0, 36 }) then -- Set cursor to current buffer - utils.map_set(opts, "keymap.fzf.load", - "transform:" .. FzfLua.shell.raw_action(function(_, _, _) - local pos = 0 - for tabnr, tabh in ipairs(vim.api.nvim_list_tabpages()) do - pos = pos + 1 - for _, w in ipairs(vim.api.nvim_tabpage_list_wins(tabh)) do - local b = filter_buffers(opts, { vim.api.nvim_win_get_buf(w) })[1] - if b then - pos = pos + 1 - if tabnr == core.CTX().tabnr and w == core.CTX().winid then - return string.format("pos(%d)", pos) - end + utils.map_set(opts, "keymap.fzf.load", "transform:" .. FzfLua.shell.raw_action(function(_, _, _) + local pos = 0 + for tabnr, tabh in ipairs(vim.api.nvim_list_tabpages()) do + pos = pos + 1 + for _, w in ipairs(vim.api.nvim_tabpage_list_wins(tabh)) do + local b = filter_buffers(opts, { vim.api.nvim_win_get_buf(w) })[1] + if b then + pos = pos + 1 + if tabnr == core.CTX().tabnr and w == core.CTX().winid then + return string.format("pos(%d)", pos) end end end - end, "", opts.debug)) - end - - opts.__fn_reload = opts.__fn_reload or function(_) - -- we do not return the populate function with cb directly to avoid - -- E5560: nvim_exec must not be called in a lua loop callback - local entries = {} - local populate = function(cb) - local max_bufnr = (function() - local ret = 0 - for _, t in ipairs(vim.api.nvim_list_tabpages()) do - for _, w in ipairs(vim.api.nvim_tabpage_list_wins(t)) do - local b = vim.api.nvim_win_get_buf(w) - if b > ret then ret = b end - end - end - return ret - end)() - - for tabnr, tabh in ipairs(vim.api.nvim_list_tabpages()) do - (function() - if opts.current_tab_only and tabh ~= core.CTX().tabh then return end - - local tab_cwd = vim.fn.getcwd(-1, tabnr) - local tab_cwd_tilde = path.HOME_to_tilde(tab_cwd) - local title, fn_title_hl = opt_hl(tabnr, "tab_title", - function(s) - return string.format("%s%s#%d%s", s, utils.nbsp, tabnr, - (uv.cwd() == tab_cwd and "" or string.format(": %s", tab_cwd_tilde))) - end, - utils.ansi_codes[opts.hls.tab_title]) - - local marker, fn_marker_hl = opt_hl(tabnr, "tab_marker", - function(s) return s end, - utils.ansi_codes[opts.hls.tab_marker]) - - local tab_cwd_tilde_base64 = base64.encode(tab_cwd_tilde) - if not opts.current_tab_only then - cb(string.format("%s:%d:%d:0)%s%s %s", - tab_cwd_tilde_base64, - tabnr, - tabh, - utils.nbsp, - fn_title_hl(title), - (tabh == core.CTX().tabh) and fn_marker_hl(marker) or "")) - end + end + end, "", opts.debug)) + end - for _, w in ipairs(vim.api.nvim_tabpage_list_wins(tabh)) do - if tabh ~= core.CTX().tabh or core.CTX().curtab_wins[tostring(w)] then - local b = filter_buffers(opts, { vim.api.nvim_win_get_buf(w) })[1] - if b then - local prefix = string.format("%s:%d:%d:%d)%s%s%s", - tab_cwd_tilde_base64, tabnr, tabh, w, utils.nbsp, utils.nbsp, utils.nbsp) - local bufinfo = populate_buffer_entries({}, { b }, w)[1] - cb(gen_buffer_entry(opts, bufinfo, max_bufnr, tab_cwd, prefix)) + opts.__fn_reload = opts.__fn_reload + or function(_) + -- we do not return the populate function with cb directly to avoid + -- E5560: nvim_exec must not be called in a lua loop callback + local entries = {} + local populate = function(cb) + local max_bufnr = (function() + local ret = 0 + for _, t in ipairs(vim.api.nvim_list_tabpages()) do + for _, w in ipairs(vim.api.nvim_tabpage_list_wins(t)) do + local b = vim.api.nvim_win_get_buf(w) + if b > ret then + ret = b end end end + return ret end)() + + for tabnr, tabh in ipairs(vim.api.nvim_list_tabpages()) do + (function() + if opts.current_tab_only and tabh ~= core.CTX().tabh then + return + end + + local tab_cwd = vim.fn.getcwd(-1, tabnr) + local tab_cwd_tilde = path.HOME_to_tilde(tab_cwd) + local title, fn_title_hl = opt_hl(tabnr, "tab_title", function(s) + return string.format( + "%s%s#%d%s", + s, + utils.nbsp, + tabnr, + (uv.cwd() == tab_cwd and "" or string.format(": %s", tab_cwd_tilde)) + ) + end, utils.ansi_codes[opts.hls.tab_title]) + + local marker, fn_marker_hl = opt_hl(tabnr, "tab_marker", function(s) + return s + end, utils.ansi_codes[opts.hls.tab_marker]) + + local tab_cwd_tilde_base64 = base64.encode(tab_cwd_tilde) + if not opts.current_tab_only then + cb( + string.format( + "%s:%d:%d:0)%s%s %s", + tab_cwd_tilde_base64, + tabnr, + tabh, + utils.nbsp, + fn_title_hl(title), + (tabh == core.CTX().tabh) and fn_marker_hl(marker) or "" + ) + ) + end + + for _, w in ipairs(vim.api.nvim_tabpage_list_wins(tabh)) do + if tabh ~= core.CTX().tabh or core.CTX().curtab_wins[tostring(w)] then + local b = filter_buffers(opts, { vim.api.nvim_win_get_buf(w) })[1] + if b then + local prefix = string.format( + "%s:%d:%d:%d)%s%s%s", + tab_cwd_tilde_base64, + tabnr, + tabh, + w, + utils.nbsp, + utils.nbsp, + utils.nbsp + ) + local bufinfo = populate_buffer_entries({}, { b }, w)[1] + cb(gen_buffer_entry(opts, bufinfo, max_bufnr, tab_cwd, prefix)) + end + end + end + end)() + end + cb(nil) end - cb(nil) + populate(function(e) + if e then + table.insert(entries, e) + end + end) + return entries end - populate(function(e) - if e then table.insert(entries, e) end - end) - return entries - end -- build the "reload" cmd and remove '-- {+}' from the initial cmd local contents, id = shell.reload_action_cmd(opts, "") @@ -488,10 +536,11 @@ M.tabs = function(opts) core.fzf_exec(contents, opts) end - M.treesitter = function(opts) opts = config.normalize_opts(opts, "treesitter") - if not opts then return end + if not opts then + return + end local __has_ts, _ = pcall(require, "nvim-treesitter") if not __has_ts then @@ -510,8 +559,9 @@ M.treesitter = function(opts) local ft = vim.bo[opts.bufnr].ft local lang = ts.language.get_lang(ft) or ft if not utils.has_ts_parser(lang) then - utils.info(string.format("No treesitter parser found for '%s' (bufnr=%d).", - opts._bufname, opts.bufnr)) + utils.info( + string.format("No treesitter parser found for '%s' (bufnr=%d).", opts._bufname, opts.bufnr) + ) return end @@ -521,13 +571,19 @@ M.treesitter = function(opts) end local parser = ts.get_parser(opts.bufnr) - if not parser then return end + if not parser then + return + end parser:parse() local root = parser:trees()[1]:root() - if not root then return end + if not root then + return + end local query = (ts.query.get(lang, "locals")) - if not query then return end + if not query then + return + end local get = function(bufnr) local definitions = {} @@ -559,8 +615,6 @@ M.treesitter = function(opts) return definitions, references, scopes end - - local function recurse_local_nodes(local_def, accumulator, full_match, last_match) if type(local_def) ~= "table" then return @@ -569,8 +623,12 @@ M.treesitter = function(opts) accumulator(local_def, local_def.node, full_match, last_match) else for match_key, def in pairs(local_def) do - recurse_local_nodes(def, accumulator, - full_match and (full_match .. "." .. match_key) or match_key, match_key) + recurse_local_nodes( + def, + accumulator, + full_match and (full_match .. "." .. match_key) or match_key, + match_key + ) end end end @@ -596,17 +654,21 @@ 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\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.buf_linenr](tostring(lnum + 1)), utils.ansi_codes[opts.hls.path_colnr](tostring(col + 1)), node_kind or "", - node_text) + node_text + ) cb(entry, function(err) coroutine.resume(co) - if err then cb(nil) end + if err then + cb(nil) + end end) end) coroutine.yield() @@ -624,7 +686,9 @@ end M.spellcheck = function(opts) opts = config.normalize_opts(opts, "spellcheck") - if not opts then return end + if not opts then + return + end if #vim.bo.spelllang == 0 then utils.info("Spell language not set, use ':setl spl=...' to enable spell checking.") @@ -693,27 +757,35 @@ M.spellcheck = function(opts) local prefix = from and string.sub(line, from - 1, from - 1) or "" local postfix = to and string.sub(line, to + 1, to + 1) or "" local valid_word = word - and (#prefix == 0 or prefix:match("^" .. word_separator)) - and (#postfix == 0 or postfix:match(word_separator .. "$")) + and (#prefix == 0 or prefix:match("^" .. word_separator)) + and (#postfix == 0 or postfix:match(word_separator .. "$")) if valid_word then local _, lead = word:find("^" .. word_separator .. "+") local spell = vim.spell.check(trim(word))[1] if spell then - cb(string.format("[%s]%s%s:%s:%s\t\t%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.buf_linenr](tostring(lnum)), - utils.ansi_codes[opts.hls.path_colnr](tostring(from + (lead or 0))), - trim(word) - ), function(err) - coroutine.resume(co) - if err then cb(nil) end - end) + cb( + string.format( + "[%s]%s%s:%s:%s\t\t%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.buf_linenr](tostring(lnum)), + utils.ansi_codes[opts.hls.path_colnr](tostring(from + (lead or 0))), + trim(word) + ), + function(err) + coroutine.resume(co) + if err then + cb(nil) + end + end + ) coroutine.yield() end end - if from then from = to + 1 end + if from then + from = to + 1 + end until not from end cb(nil) diff --git a/lua/fzf-lua/providers/colorschemes.lua b/lua/fzf-lua/providers/colorschemes.lua index 364218b21..ff7384b44 100644 --- a/lua/fzf-lua/providers/colorschemes.lua +++ b/lua/fzf-lua/providers/colorschemes.lua @@ -1,12 +1,12 @@ -local core = require "fzf-lua.core" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local shell = require "fzf-lua.shell" -local config = require "fzf-lua.config" -local actions = require "fzf-lua.actions" +local core = require("fzf-lua.core") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local shell = require("fzf-lua.shell") +local config = require("fzf-lua.config") +local actions = require("fzf-lua.actions") -- For AsyncDownloadManager -local Object = require "fzf-lua.class" +local Object = require("fzf-lua.class") local uv = vim.uv or vim.loop local function get_current_colorscheme() @@ -21,7 +21,9 @@ local M = {} M.colorschemes = function(opts) opts = config.normalize_opts(opts, "colorschemes") - if not opts then return end + if not opts then + return + end local current_colorscheme = get_current_colorscheme() local current_background = vim.o.background @@ -87,7 +89,9 @@ end M.highlights = function(opts) opts = config.normalize_opts(opts, "highlights") - if not opts then return end + if not opts then + return + end local contents = function(cb) local highlights = vim.fn.getcompletion("", "highlight") @@ -96,13 +100,17 @@ M.highlights = function(opts) -- translate the highlight using ansi escape sequences local x = utils.ansi_from_hl(hl, hl) cb(x, function(err) - if co then coroutine.resume(co) end + if co then + coroutine.resume(co) + end if err then -- error, close fzf pipe cb(nil) end end) - if co then coroutine.yield() end + if co then + coroutine.yield() + end end local function populate(entries, fn, co) @@ -111,7 +119,9 @@ M.highlights = function(opts) end cb(nil, function() - if co then coroutine.resume(co) end + if co then + coroutine.resume(co) + end end) end @@ -125,13 +135,11 @@ M.highlights = function(opts) -- E5560: vimL function must not be called in a lua loop callback -- and using 'vim.schedule' -- attempt to yield across C-call boundary - populate(highlights, - function(x, co) - vim.schedule(function() - add_entry(x, co) - end) - end, - coroutine.running()) + populate(highlights, function(x, co) + vim.schedule(function() + add_entry(x, co) + end) + end, coroutine.running()) coroutine.yield() end)() end @@ -140,7 +148,6 @@ M.highlights = function(opts) core.fzf_exec(contents, opts) end - local AsyncDownloadManager = Object:extend() function AsyncDownloadManager:new(opts) @@ -149,8 +156,9 @@ function AsyncDownloadManager:new(opts) self.max_threads = tonumber(opts.max_threads) > 0 and tonumber(opts.max_threads) or 5 local stat, _ = uv.fs_stat(self.path) if stat and stat.type ~= "directory" then - utils.warn(string.format( - [["%s" already exists and is not a directory (type:%s)]], self.path, stat.type)) + utils.warn( + string.format([["%s" already exists and is not a directory (type:%s)]], self.path, stat.type) + ) return end if not stat then @@ -180,7 +188,9 @@ function AsyncDownloadManager:jobwait_all(co) end if #jobs > 0 then vim.fn.jobwait(jobs) - if co then coroutine.resume(co) end + if co then + coroutine.resume(co) + end end end @@ -212,8 +222,9 @@ function AsyncDownloadManager:load_db(db) for i, v in ipairs(p.colorschemes) do p.colorschemes[i].disp_name = v.disp_name or p.disp_name if not v.name and not v.lua and not v.vim then - utils.warn(string.format( - "package %s: colorschemes[%d], must contain at least 'name|lua|vim'", k, i)) + utils.warn( + string.format("package %s: colorschemes[%d], must contain at least 'name|lua|vim'", k, i) + ) return false end end @@ -223,8 +234,7 @@ function AsyncDownloadManager:load_db(db) if self.dl_status == 0 or self.dl_status == 1 then for k, _ in pairs(self.db or {}) do local downloaded = self:downloaded(k) - if self.dl_status == 0 and downloaded - or self.dl_status == 1 and not downloaded then + if self.dl_status == 0 and downloaded or self.dl_status == 1 and not downloaded then self.db[k] = nil end end @@ -234,7 +244,9 @@ end function AsyncDownloadManager:downloaded(plugin) local info = plugin and self.db[plugin] - if not info then return end + if not info then + return + end local stat = uv.fs_stat(info.path) return stat and stat.type == "directory" end @@ -249,7 +261,9 @@ function AsyncDownloadManager:get(plugin) end function AsyncDownloadManager:set_once_on_exit(plugin, fn) - if not plugin or not self.db[plugin] then return end + if not plugin or not self.db[plugin] then + return + end self.db[plugin].on_exit = function(...) fn(...) self.db[plugin].on_exit = nil @@ -258,12 +272,16 @@ end function AsyncDownloadManager:jobwait(plugin) local info = plugin and self.db[plugin] - if not info or not info.job_id then return end + if not info or not info.job_id then + return + end vim.fn.jobwait({ info.job_id }) end function AsyncDownloadManager:delete(plugin) - if not plugin or not self.db[plugin] then return end + if not plugin or not self.db[plugin] then + return + end if self:downloaded(plugin) then vim.fn.delete(self.db[plugin].path, "rf") end @@ -287,25 +305,30 @@ function AsyncDownloadManager:dequeue() end function AsyncDownloadManager:jobstart(plugin, job_args) - if not plugin then return end + if not plugin then + return + end local info = plugin and self.db[plugin] - local msg = string.format("%s %s (%s)", - job_args[1][2] == "clone" and "Cloning" or "Updating", info.disp_name, info.dir) + local msg = string.format( + "%s %s (%s)", + job_args[1][2] == "clone" and "Cloning" or "Updating", + info.disp_name, + info.dir + ) local job_id - job_args[2] = vim.tbl_extend("keep", job_args[2] or {}, - { - on_exit = function(_, rc, _) - utils.info(string.format("%s [job_id:%d] finished with exit code %s", plugin, job_id, rc)) - if type(info.on_exit) == "function" then - -- this calls `coroutine.resume` and resumes fzf's reload input stream - info.on_exit(_, rc, _) - end - self.job_ids[tostring(job_id)] = nil - self.db[plugin].job_id = nil - -- dequeue the next job - self:dequeue() + job_args[2] = vim.tbl_extend("keep", job_args[2] or {}, { + on_exit = function(_, rc, _) + utils.info(string.format("%s [job_id:%d] finished with exit code %s", plugin, job_id, rc)) + if type(info.on_exit) == "function" then + -- this calls `coroutine.resume` and resumes fzf's reload input stream + info.on_exit(_, rc, _) end - }) + self.job_ids[tostring(job_id)] = nil + self.db[plugin].job_id = nil + -- dequeue the next job + self:dequeue() + end, + }) job_id = vim.fn.jobstart(unpack(job_args)) if job_id == 0 then utils.warn("jobstart: invalid args") @@ -313,8 +336,9 @@ function AsyncDownloadManager:jobstart(plugin, job_args) utils.warn(string.format([[jobstart: "%s" is not executable]], job_args[1])) else -- job started successfully - utils.info(string.format("%s [path:%s] [job_id:%d]...", - msg, path.HOME_to_tilde(info.path), job_id)) + utils.info( + string.format("%s [path:%s] [job_id:%d]...", msg, path.HOME_to_tilde(info.path), job_id) + ) self.job_ids[tostring(job_id)] = { plugin = plugin, args = job_args } self.db[plugin].job_id = job_id end @@ -322,19 +346,21 @@ end function AsyncDownloadManager:update(plugin) local info = plugin and self.db[plugin] - if not info then return end + if not info then + return + end if self:downloaded(plugin) then -- git pull self:queue(plugin, { ---@format disable-next - { "git", "pull", "--rebase" }, - { cwd = info.path } + { "git", "pull", "--rebase" }, + { cwd = info.path }, }) else -- git clone self:queue(plugin, { -- { "git", "clone", "--depth=1", info.url, info.dir } -- shallow clone - { "git", "clone", "--filter", "tree:0", info.url, info.path } -- treeless clone + { "git", "clone", "--filter", "tree:0", info.url, info.path }, -- treeless clone }) end end @@ -347,7 +373,9 @@ M.apply_awesome_theme = function(dbkey, idx, opts) assert(tonumber(idx) > 0, "colorscheme index is invalid") local cs = p.colorschemes[tonumber(idx)] -- TODO: should we check `package.loaded[...]` before packadd? - local ok, out = pcall(function() vim.cmd("packadd " .. p.dir) end) + local ok, out = pcall(function() + vim.cmd("packadd " .. p.dir) + end) if not ok then utils.warn(string.format("Unable to packadd %s: %s", p.dir, tostring(out))) return @@ -355,9 +383,13 @@ M.apply_awesome_theme = function(dbkey, idx, opts) if cs.vim then ok, out = pcall(vim.api.nvim_exec2, cs.vim, { output = true }) elseif cs.lua then - ok, out = pcall(function() loadstring(cs.lua)() end) + ok, out = pcall(function() + loadstring(cs.lua)() + end) else - ok, out = pcall(function() vim.cmd("colorscheme " .. cs.name) end) + ok, out = pcall(function() + vim.cmd("colorscheme " .. cs.name) + end) end if not ok then utils.warn(string.format("Unable to apply colorscheme %s: %s", cs.disp_name, tostring(out))) @@ -366,7 +398,9 @@ end M.awesome_colorschemes = function(opts) opts = config.normalize_opts(opts, "awesome_colorschemes") - if not opts then return end + if not opts then + return + end opts._cur_colorscheme = get_current_colorscheme() opts._cur_background = vim.o.background @@ -391,17 +425,18 @@ M.awesome_colorschemes = function(opts) -- save a ref for action opts._apply_awesome_theme = M.apply_awesome_theme - opts._packpath = type(opts.packpath) == "function" - and opts.packpath() or tostring(opts.packpath) + opts._packpath = type(opts.packpath) == "function" and opts.packpath() or tostring(opts.packpath) opts._adm = AsyncDownloadManager:new({ db = json_db, dl_status = opts.dl_status, max_threads = opts.max_threads, - path = path.join({ opts._packpath, "pack", "fzf-lua", "opt" }) + path = path.join({ opts._packpath, "pack", "fzf-lua", "opt" }), }) -- Error creating cache directory - if not opts._adm then return end + if not opts._adm then + return + end opts.func_async_callback = false opts.__fn_reload = function(_) @@ -436,16 +471,17 @@ M.awesome_colorschemes = function(opts) coroutine.yield() end vim.schedule(function() - local icon = not downloaded - and opts.icons[1] -- download icon - or i == 1 and opts.icons[2] -- colorscheme (package) icon - or opts.icons[3] -- colorscheme (variant) noicon - local entry = string.format("%s:%d:%s %s %s", + local icon = not downloaded and opts.icons[1] -- download icon + or i == 1 and opts.icons[2] -- colorscheme (package) icon + or opts.icons[3] -- colorscheme (variant) noicon + local entry = string.format( + "%s:%d:%s %s %s", dbkey, i, icon, cs.disp_name, - i == 1 and string.format("(%s)", info.disp_url) or "") + i == 1 and string.format("(%s)", info.disp_url) or "" + ) cb(entry, function() coroutine.resume(co) end) @@ -470,7 +506,9 @@ M.awesome_colorschemes = function(opts) -- some colorschemes choose a different theme based on dark|light bg -- restore to the original background when interface was opened -- wrap in pcall as some colorschemes have bg triggers that can fail - pcall(function() vim.o.background = opts._cur_background end) + pcall(function() + vim.o.background = opts._cur_background + end) M.apply_awesome_theme(dbkey, idx, opts) opts._live = true else diff --git a/lua/fzf-lua/providers/dap.lua b/lua/fzf-lua/providers/dap.lua index 7a683c128..bf8f89c1c 100644 --- a/lua/fzf-lua/providers/dap.lua +++ b/lua/fzf-lua/providers/dap.lua @@ -1,9 +1,9 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local utils = require "fzf-lua.utils" -local shell = require "fzf-lua.shell" -local config = require "fzf-lua.config" -local make_entry = require "fzf-lua.make_entry" +local core = require("fzf-lua.core") +local utils = require("fzf-lua.utils") +local shell = require("fzf-lua.shell") +local config = require("fzf-lua.config") +local make_entry = require("fzf-lua.make_entry") local _has_dap, _dap = nil, nil @@ -12,7 +12,9 @@ local M = {} -- attempt to load 'nvim-dap' every call -- in case the plugin was lazy loaded local function dap() - if _has_dap and _dap then return _dap end + if _has_dap and _dap then + return _dap + end _has_dap, _dap = pcall(require, "dap") if not _has_dap or not _dap then utils.info("DAP requires 'mfussenegger/nvim-dap'") @@ -22,10 +24,14 @@ local function dap() end M.commands = function(opts) - if not dap() then return end + if not dap() then + return + end opts = config.normalize_opts(opts, "dap.commands") - if not opts then return end + if not opts then + return + end local entries = {} for k, v in pairs(_dap) do @@ -44,28 +50,37 @@ M.commands = function(opts) end M.configurations = function(opts) - if not dap() then return end + if not dap() then + return + end opts = config.normalize_opts(opts, "dap.configurations") - if not opts then return end + if not opts then + return + end local entries = {} opts._cfgs = {} for lang, lang_cfgs in pairs(_dap.configurations) do for _, cfg in ipairs(lang_cfgs) do opts._cfgs[#entries + 1] = cfg - table.insert(entries, ("[%s] %s. %s"):format( - utils.ansi_codes.green(lang), - utils.ansi_codes.magenta(tostring(#entries + 1)), - cfg.name - )) + table.insert( + entries, + ("[%s] %s. %s"):format( + utils.ansi_codes.green(lang), + utils.ansi_codes.magenta(tostring(#entries + 1)), + cfg.name + ) + ) end end opts.actions = { ["enter"] = function(selected, _) -- cannot run while in session - if _dap.session() then return end + if _dap.session() then + return + end local idx = selected and tonumber(selected[1]:match("(%d+).")) or nil if idx and opts._cfgs[idx] then _dap.run(opts._cfgs[idx]) @@ -78,10 +93,14 @@ end M.breakpoints = function(opts) opts = config.normalize_opts(opts, "dap.breakpoints") - if not opts then return end + if not opts then + return + end - if not dap() then return end - local dap_bps = require "dap.breakpoints" + if not dap() then + return + end + local dap_bps = require("dap.breakpoints") if utils.tbl_isempty(dap_bps.get()) then utils.info("Breakpoint list is empty.") @@ -89,32 +108,37 @@ M.breakpoints = function(opts) end -- display relative paths by default - if opts.cwd == nil then opts.cwd = uv.cwd() end + if opts.cwd == nil then + opts.cwd = uv.cwd() + end opts.func_async_callback = false - opts.__fn_reload = opts.__fn_reload or function(_) - return function(cb) - coroutine.wrap(function() - local co = coroutine.running() - local bps = dap_bps.to_qf_list(dap_bps.get()) - for _, b in ipairs(bps) do - vim.schedule(function() - local entry = make_entry.lcol(b, opts) - entry = string.format("[%s]%s%s", - -- tostring(opts._locations[i].bufnr), - utils.ansi_codes.yellow(tostring(b.bufnr)), - utils.nbsp, - make_entry.file(entry, opts)) - cb(entry, function() - coroutine.resume(co) + opts.__fn_reload = opts.__fn_reload + or function(_) + return function(cb) + coroutine.wrap(function() + local co = coroutine.running() + local bps = dap_bps.to_qf_list(dap_bps.get()) + for _, b in ipairs(bps) do + vim.schedule(function() + local entry = make_entry.lcol(b, opts) + entry = string.format( + "[%s]%s%s", + -- tostring(opts._locations[i].bufnr), + utils.ansi_codes.yellow(tostring(b.bufnr)), + utils.nbsp, + make_entry.file(entry, opts) + ) + cb(entry, function() + coroutine.resume(co) + end) end) - end) - coroutine.yield() - end - cb(nil) - end)() + coroutine.yield() + end + cb(nil) + end)() + end end - end -- build the "reload" cmd and remove '-- {+}' from the initial cmd local contents, id = shell.reload_action_cmd(opts, "") @@ -131,10 +155,14 @@ M.breakpoints = function(opts) end M.variables = function(opts) - if not dap() then return end + if not dap() then + return + end opts = config.normalize_opts(opts, "dap.variables") - if not opts then return end + if not opts then + return + end local session = _dap.session() if not session then @@ -147,12 +175,15 @@ M.variables = function(opts) if s.variables then for _, v in pairs(s.variables) do if v.type ~= "" and v.value ~= "" then - table.insert(entries, ("[%s] %s = %s"):format( - utils.ansi_codes.green(v.type), - -- utils.ansi_codes.red(v.name), - v.name, - v.value - )) + table.insert( + entries, + ("[%s] %s = %s"):format( + utils.ansi_codes.green(v.type), + -- utils.ansi_codes.red(v.name), + v.name, + v.value + ) + ) end end end @@ -162,10 +193,14 @@ M.variables = function(opts) end M.frames = function(opts) - if not dap() then return end + if not dap() then + return + end opts = config.normalize_opts(opts, "dap.frames") - if not opts then return end + if not opts then + return + end local session = _dap.session() if not session then @@ -187,7 +222,9 @@ M.frames = function(opts) ---@return fzf-lua.buffer_or_file.Entry function p:parse_entry(entry_str) local idx = entry_str and tonumber(entry_str:match("(%d+).")) or nil - if not idx then return {} end + if not idx then + return {} + end local f = opts._frames[idx] if (not f) or not f.source then @@ -231,7 +268,9 @@ M.frames = function(opts) opts.actions = { ["enter"] = function(selected, o) local sess = _dap.session() - if not sess or not sess.stopped_thread_id then return end + if not sess or not sess.stopped_thread_id then + return + end local idx = selected and tonumber(selected[1]:match("(%d+).")) or nil if idx and o._frames[idx] then session:_frame_set(o._frames[idx]) @@ -241,12 +280,15 @@ M.frames = function(opts) local entries = {} for i, f in ipairs(opts._frames) do - table.insert(entries, ("%s. [%s] %s%s"):format( - utils.ansi_codes.magenta(tostring(i)), - utils.ansi_codes.green(f.name), - f.source and f.source.name or "", - f.line and ((":%d"):format(f.line)) or "" - )) + table.insert( + entries, + ("%s. [%s] %s%s"):format( + utils.ansi_codes.magenta(tostring(i)), + utils.ansi_codes.green(f.name), + f.source and f.source.name or "", + f.line and ((":%d"):format(f.line)) or "" + ) + ) end core.fzf_exec(entries, opts) diff --git a/lua/fzf-lua/providers/diagnostic.lua b/lua/fzf-lua/providers/diagnostic.lua index fbe43c13e..1ab3c5a19 100644 --- a/lua/fzf-lua/providers/diagnostic.lua +++ b/lua/fzf-lua/providers/diagnostic.lua @@ -1,18 +1,17 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local make_entry = require "fzf-lua.make_entry" +local core = require("fzf-lua.core") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local make_entry = require("fzf-lua.make_entry") local M = {} - local convert_diagnostic_type = function(severity) -- convert from string to int if type(severity) == "string" and not tonumber(severity) then -- make sure that e.g. error is uppercased to Error - return vim.diagnostic and vim.diagnostic.severity[severity:upper()] or - vim.lsp.protocol.DiagnosticSeverity[severity:gsub("^%l", string.upper)] + return vim.diagnostic and vim.diagnostic.severity[severity:upper()] + or vim.lsp.protocol.DiagnosticSeverity[severity:gsub("^%l", string.upper)] else -- otherwise keep original value, incl. nil return tonumber(severity) @@ -33,7 +32,9 @@ end M.diagnostics = function(opts) opts = config.normalize_opts(opts, "diagnostics") - if not opts then return end + if not opts then + return + end -- required for relative paths presentation if not opts.cwd or #opts.cwd == 0 then @@ -52,18 +53,20 @@ M.diagnostics = function(opts) end -- configure signs and highlights - local signs = vim.diagnostic and { - ["Error"] = { severity = 1, default = "E", name = "DiagnosticSignError" }, - ["Warn"] = { severity = 2, default = "W", name = "DiagnosticSignWarn" }, - ["Info"] = { severity = 3, default = "I", name = "DiagnosticSignInfo" }, - ["Hint"] = { severity = 4, default = "H", name = "DiagnosticSignHint" }, - } or { - -- At one point or another, we'll drop support for the old LSP diag - ["Error"] = { severity = 1, default = "E", name = "LspDiagnosticsSignError" }, - ["Warn"] = { severity = 2, default = "W", name = "LspDiagnosticsSignWarning" }, - ["Info"] = { severity = 3, default = "I", name = "LspDiagnosticsSignInformation" }, - ["Hint"] = { severity = 4, default = "H", name = "LspDiagnosticsSignHint" }, - } + local signs = vim.diagnostic + and { + ["Error"] = { severity = 1, default = "E", name = "DiagnosticSignError" }, + ["Warn"] = { severity = 2, default = "W", name = "DiagnosticSignWarn" }, + ["Info"] = { severity = 3, default = "I", name = "DiagnosticSignInfo" }, + ["Hint"] = { severity = 4, default = "H", name = "DiagnosticSignHint" }, + } + or { + -- At one point or another, we'll drop support for the old LSP diag + ["Error"] = { severity = 1, default = "E", name = "LspDiagnosticsSignError" }, + ["Warn"] = { severity = 2, default = "W", name = "LspDiagnosticsSignWarning" }, + ["Info"] = { severity = 3, default = "I", name = "LspDiagnosticsSignInformation" }, + ["Hint"] = { severity = 4, default = "H", name = "LspDiagnosticsSignHint" }, + } opts.__signs = {} for k, v in pairs(signs) do @@ -72,21 +75,30 @@ M.diagnostics = function(opts) -- from vim.diagnostic if utils.__HAS_NVIM_010 then local sign_confs = type(opts.diag_icons) == "table" and { text = opts.diag_icons } - or vim.diagnostic.config().signs + or vim.diagnostic.config().signs local level = vim.diagnostic.severity[k:upper()] - if type(sign_confs) ~= "table" or utils.tbl_isempty(sign_confs) then sign_confs = nil end - opts.__signs[v.severity].text = - (not opts.diag_icons or not sign_confs or not sign_confs.text or not sign_confs.text[level]) - and v.default or vim.trim(sign_confs.text[level]) + if type(sign_confs) ~= "table" or utils.tbl_isempty(sign_confs) then + sign_confs = nil + end + opts.__signs[v.severity].text = ( + not opts.diag_icons + or not sign_confs + or not sign_confs.text + or not sign_confs.text[level] + ) + and v.default + or vim.trim(sign_confs.text[level]) opts.__signs[v.severity].texthl = v.name else local sign_def = vim.fn.sign_getdefined(v.name) -- can be empty when config set to (#480): -- vim.diagnostic.config({ signs = false }) - if utils.tbl_isempty(sign_def) then sign_def = nil end - opts.__signs[v.severity].text = - (not opts.diag_icons or not sign_def or not sign_def[1].text) - and v.default or vim.trim(sign_def[1].text) + if utils.tbl_isempty(sign_def) then + sign_def = nil + end + opts.__signs[v.severity].text = (not opts.diag_icons or not sign_def or not sign_def[1].text) + and v.default + or vim.trim(sign_def[1].text) opts.__signs[v.severity].texthl = sign_def and sign_def[1].texthl or nil end @@ -113,8 +125,10 @@ M.diagnostics = function(opts) local diag_opts = { severity = {}, namespace = opts.namespace } if opts.severity_only ~= nil then if opts.severity_limit ~= nil or opts.severity_bound ~= nil then - utils.warn("Invalid severity parameters." .. - " Both a specific severity and a limit/bound is not allowed") + utils.warn( + "Invalid severity parameters." + .. " Both a specific severity and a limit/bound is not allowed" + ) return {} end diag_opts.severity = opts.severity_only @@ -124,18 +138,22 @@ M.diagnostics = function(opts) end local curbuf = vim.api.nvim_get_current_buf() - local diag_results = vim.diagnostic and - vim.diagnostic.get(not opts.diag_all and curbuf or nil, diag_opts) or - opts.diag_all and vim.lsp.diagnostic.get_all() or - { [curbuf] = vim.lsp.diagnostic.get(curbuf, opts.client_id) } + local diag_results = vim.diagnostic + and vim.diagnostic.get(not opts.diag_all and curbuf or nil, diag_opts) + or opts.diag_all and vim.lsp.diagnostic.get_all() + or { [curbuf] = vim.lsp.diagnostic.get(curbuf, opts.client_id) } if opts.sort then if opts.sort == 2 or opts.sort == "2" then -- ascending: hint, info, warn, error - table.sort(diag_results, function(a, b) return a.severity > b.severity end) + table.sort(diag_results, function(a, b) + return a.severity > b.severity + end) else -- descending: error, warn, info, hint - table.sort(diag_results, function(a, b) return a.severity < b.severity end) + table.sort(diag_results, function(a, b) + return a.severity < b.severity + end) end end @@ -146,7 +164,9 @@ M.diagnostics = function(opts) else -- format: { [bufnr] = , ... } for _, diags in pairs(diag_results) do - if #diags > 0 then has_diags = true end + if #diags > 0 then + has_diags = true + end end end if not has_diags then @@ -173,7 +193,7 @@ M.diagnostics = function(opts) lnum = row + 1, col = col + 1, text = vim.trim(opts.multiline and diag.message or diag.message:match("^[^\n]+")), - type = diag.severity or 1 + type = diag.severity or 1, } return buffer_diag end @@ -220,19 +240,26 @@ M.diagnostics = function(opts) entry = entry .. utils.ansi_from_hl("Comment", " [" .. diag.code .. "]") end - entry = string.format("%s%s%s", - icon and string.format("%s%s%s", icon, opts.icon_padding or "", utils.nbsp) - or "", - opts.diag_source and utils.ansi_from_hl( - opts.color_headings and sign_def.texthl, string.format( - "%s%s%s%s", - "[", --utils.ansi_codes.bold("["), - diag.source, - "]", --utils.ansi_codes.bold("]"), - utils.nbsp)) - or "", - entry) - fzf_cb(entry, function() coroutine.resume(co) end) + entry = string.format( + "%s%s%s", + icon and string.format("%s%s%s", icon, opts.icon_padding or "", utils.nbsp) or "", + opts.diag_source + and utils.ansi_from_hl( + opts.color_headings and sign_def.texthl, + string.format( + "%s%s%s%s", + "[", --utils.ansi_codes.bold("["), + diag.source, + "]", --utils.ansi_codes.bold("]"), + utils.nbsp + ) + ) + or "", + entry + ) + fzf_cb(entry, function() + coroutine.resume(co) + end) end end) -- wait here for 'vim.schedule' to return @@ -260,7 +287,9 @@ M.diagnostics = function(opts) end M.all = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.diag_all = true return M.diagnostics(opts) end diff --git a/lua/fzf-lua/providers/files.lua b/lua/fzf-lua/providers/files.lua index 2993a9f92..337b477de 100644 --- a/lua/fzf-lua/providers/files.lua +++ b/lua/fzf-lua/providers/files.lua @@ -1,11 +1,11 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local shell = require "fzf-lua.shell" -local libuv = require "fzf-lua.libuv" -local config = require "fzf-lua.config" -local make_entry = require "fzf-lua.make_entry" +local core = require("fzf-lua.core") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local shell = require("fzf-lua.shell") +local libuv = require("fzf-lua.libuv") +local config = require("fzf-lua.config") +local make_entry = require("fzf-lua.make_entry") local M = {} @@ -16,7 +16,7 @@ local get_files_cmd = function(opts) local search_paths = (function() -- NOTE: deepcopy to avoid recursive shellescapes with `actions.toggle_ignore` local search_paths = type(opts.search_paths) == "table" and vim.deepcopy(opts.search_paths) - or type(opts.search_paths) == "string" and { tostring(opts.search_paths) } + or type(opts.search_paths) == "string" and { tostring(opts.search_paths) } -- Make paths relative, note this will not work well with resuming if changing -- the cwd, this is by design for perf reasons as having to deal with full paths -- will result in more code routes taken in `make_entry.file` @@ -31,19 +31,27 @@ local get_files_cmd = function(opts) if opts.cmd and #opts.cmd > 0 then command = opts.cmd elseif vim.fn.executable("fdfind") == 1 then - command = string.format("fdfind %s%s", opts.fd_opts, - search_paths and string.format(" . %s", search_paths) or "") + command = string.format( + "fdfind %s%s", + opts.fd_opts, + search_paths and string.format(" . %s", search_paths) or "" + ) elseif vim.fn.executable("fd") == 1 then - command = string.format("fd %s%s", opts.fd_opts, - search_paths and string.format(" . %s", search_paths) or "") + command = string.format( + "fd %s%s", + opts.fd_opts, + search_paths and string.format(" . %s", search_paths) or "" + ) elseif vim.fn.executable("rg") == 1 then - command = string.format("rg %s%s", opts.rg_opts, - search_paths and string.format(" %s", search_paths) or "") + command = string.format( + "rg %s%s", + opts.rg_opts, + search_paths and string.format(" %s", search_paths) or "" + ) elseif utils.__IS_WINDOWS then command = "dir " .. opts.dir_opts else - command = string.format("find %s %s", - search_paths and search_paths or ".", opts.find_opts) + command = string.format("find %s %s", search_paths and search_paths or ".", opts.find_opts) end for k, v in pairs({ follow = opts.toggle_follow_flag or "-L", @@ -53,10 +61,16 @@ local get_files_cmd = function(opts) (function() local toggle, is_find = opts[k], nil -- Do nothing unless opt was set - if opts[k] == nil then return end - if command:match("^dir") then return end + if opts[k] == nil then + return + end + if command:match("^dir") then + return + end if command:match("^find") then - if k == "no_ignore" then return end + if k == "no_ignore" then + return + end if k == "hidden" then is_find = true toggle = not opts[k] @@ -71,14 +85,15 @@ end M.files = function(opts) opts = config.normalize_opts(opts, "files") - if not opts then return end + if not opts then + return + end if opts.ignore_current_file then local curbuf = vim.api.nvim_buf_get_name(0) if #curbuf > 0 then curbuf = path.relative_to(curbuf, opts.cwd or uv.cwd()) opts.file_ignore_patterns = opts.file_ignore_patterns or {} - table.insert(opts.file_ignore_patterns, - "^" .. utils.lua_regex_escape(curbuf) .. "$") + table.insert(opts.file_ignore_patterns, "^" .. utils.lua_regex_escape(curbuf) .. "$") end end opts.cmd = get_files_cmd(opts) @@ -96,7 +111,9 @@ end M.args = function(opts) opts = config.normalize_opts(opts, "args") - if not opts then return end + if not opts then + return + end if vim.fn.argc() == 0 then utils.warn("arglist is empty.") @@ -104,38 +121,39 @@ M.args = function(opts) end opts.func_async_callback = false - opts.__fn_reload = opts.__fn_reload or function(_) - return function(cb) - local argc = vim.fn.argc() - - -- use coroutine & vim.schedule to avoid - -- E5560: vimL function must not be called in a lua loop callback - coroutine.wrap(function() - local co = coroutine.running() - - -- local start = os.time(); for _ = 1,10000,1 do - for i = 0, argc - 1 do - vim.schedule(function() - local s = vim.fn.argv(i) - local st = uv.fs_stat(s) - if opts.files_only == false or st and st.type == "file" then - s = make_entry.file(s, opts) - cb(s, function() + opts.__fn_reload = opts.__fn_reload + or function(_) + return function(cb) + local argc = vim.fn.argc() + + -- use coroutine & vim.schedule to avoid + -- E5560: vimL function must not be called in a lua loop callback + coroutine.wrap(function() + local co = coroutine.running() + + -- local start = os.time(); for _ = 1,10000,1 do + for i = 0, argc - 1 do + vim.schedule(function() + local s = vim.fn.argv(i) + local st = uv.fs_stat(s) + if opts.files_only == false or st and st.type == "file" then + s = make_entry.file(s, opts) + cb(s, function() + coroutine.resume(co) + end) + else coroutine.resume(co) - end) - else - coroutine.resume(co) - end - end) - coroutine.yield() - end - -- end; print("took", os.time()-start, "seconds.") - - -- done - cb(nil) - end)() + end + end) + coroutine.yield() + end + -- end; print("took", os.time()-start, "seconds.") + + -- done + cb(nil) + end)() + end end - end -- build the "reload" cmd and remove '-- {+}' from the initial cmd local contents, id = shell.reload_action_cmd(opts, "") @@ -151,7 +169,9 @@ end M.zoxide = function(opts) opts = config.normalize_opts(opts, "zoxide") - if not opts then return end + if not opts then + return + end if vim.fn.executable("zoxide") ~= 1 then utils.warn("Install zoxide to use this picker.") @@ -166,10 +186,10 @@ M.zoxide = function(opts) opts.__mt_transform = [[return require("fzf-lua.make_entry").zoxide]] contents = core.mt_cmd_wrapper(opts) else - opts.__fn_transform = opts.__fn_transform or - function(x) - return make_entry.zoxide(x, opts) - end + opts.__fn_transform = opts.__fn_transform + or function(x) + return make_entry.zoxide(x, opts) + end opts.__fn_reload = function(_) return opts.cmd @@ -189,12 +209,13 @@ M.zoxide = function(opts) end opts.preview = (function() - if opts.preview then return opts.preview end + if opts.preview then + return opts.preview + end return vim.fn.executable("lsd") == 1 and "lsd -la --color=always --icon=always --group-directories-first --literal {2}" - or vim.fn.executable("eza") == 1 - and "eza -la --color=always --icons -g --group-directories-first {2}" - or "ls -la {2}" + or vim.fn.executable("eza") == 1 and "eza -la --color=always --icons -g --group-directories-first {2}" + or "ls -la {2}" end)() return core.fzf_exec(contents, opts) diff --git a/lua/fzf-lua/providers/git.lua b/lua/fzf-lua/providers/git.lua index 51ec6378c..d19c0d898 100644 --- a/lua/fzf-lua/providers/git.lua +++ b/lua/fzf-lua/providers/git.lua @@ -1,10 +1,10 @@ -local core = require "fzf-lua.core" -local path = require "fzf-lua.path" -local libuv = require "fzf-lua.libuv" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local shell = require "fzf-lua.shell" -local make_entry = require "fzf-lua.make_entry" +local core = require("fzf-lua.core") +local path = require("fzf-lua.path") +local libuv = require("fzf-lua.libuv") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local shell = require("fzf-lua.shell") +local make_entry = require("fzf-lua.make_entry") local M = {} @@ -24,9 +24,13 @@ end M.files = function(opts) opts = config.normalize_opts(opts, "git.files") - if not opts then return end + if not opts then + return + end opts = set_git_cwd_args(opts) - if not opts.cwd then return end + if not opts.cwd then + return + end local contents = core.mt_cmd_wrapper(opts) opts = core.set_header(opts, opts.headers or { "cwd" }) return core.fzf_exec(contents, opts) @@ -34,9 +38,13 @@ end M.status = function(opts) opts = config.normalize_opts(opts, "git.status") - if not opts then return end + if not opts then + return + end opts = set_git_cwd_args(opts) - if not opts.cwd then return end + if not opts.cwd then + return + end if opts.preview then opts.preview = path.git_cwd(opts.preview, opts) end @@ -59,10 +67,10 @@ M.status = function(opts) opts.__mt_transform = [[return require("fzf-lua.make_entry").git_status]] contents = core.mt_cmd_wrapper(opts) else - opts.__fn_transform = opts.__fn_transform or - function(x) - return make_entry.git_status(x, opts) - end + opts.__fn_transform = opts.__fn_transform + or function(x) + return make_entry.git_status(x, opts) + end -- we are reusing the "live" reload action, this gets called once -- on init and every reload and should return the command we wish @@ -94,13 +102,17 @@ end local function git_cmd(opts) opts = set_git_cwd_args(opts) - if not opts.cwd then return end + if not opts.cwd then + return + end opts = core.set_header(opts, opts.headers or { "cwd" }) core.fzf_exec(opts.cmd, opts) end local function git_preview(opts, file) - if not type(opts.preview) == "string" then return end + if not type(opts.preview) == "string" then + return + end if file then opts.preview = opts.preview:gsub("[<{]file[}>]", file) end @@ -109,8 +121,8 @@ local function git_preview(opts, file) opts.preview_pager = opts.preview_pager() end if opts.preview_pager then - opts.preview = string.format("%s | %s", opts.preview, - utils._if_win_normalize_vars(opts.preview_pager)) + opts.preview = + string.format("%s | %s", opts.preview, utils._if_win_normalize_vars(opts.preview_pager)) end if vim.o.shell and vim.o.shell:match("fish$") then -- TODO: why does fish shell refuse to pass along $COLUMNS @@ -122,7 +134,9 @@ end M.diff = function(opts) opts = config.normalize_opts(opts, "git.diff") - if not opts then return end + if not opts then + return + end local cmd = path.git_cwd({ "git", "rev-parse", "--verify", opts.ref }, opts) local _, err = utils.io_systemlist(cmd) if err ~= 0 then @@ -133,7 +147,9 @@ M.diff = function(opts) opts[k] = opts[k]:gsub("[<{]ref[}>]", opts.ref) end opts = set_git_cwd_args(opts) - if not opts.cwd then return end + if not opts.cwd then + return + end opts.preview = git_preview(opts, "{-1}") local contents = core.mt_cmd_wrapper(opts) opts = core.set_header(opts, opts.headers or { "cwd" }) @@ -142,7 +158,9 @@ end M.commits = function(opts) opts = config.normalize_opts(opts, "git.commits") - if not opts then return end + if not opts then + return + end opts.preview = git_preview(opts) opts = core.set_header(opts, opts.headers or { "actions", "cwd" }) return git_cmd(opts) @@ -150,7 +168,9 @@ end M.bcommits = function(opts) opts = config.normalize_opts(opts, "git.bcommits") - if not opts then return end + if not opts then + return + end local bufname = vim.api.nvim_buf_get_name(0) if #bufname == 0 then utils.info("'bcommits' is not available for unnamed buffers.") @@ -165,7 +185,9 @@ M.bcommits = function(opts) opts.cwd = path.git_root({ cwd = vim.fn.expand("%:p:h") }, true) end local git_root = path.git_root(opts) - if not git_root then return end + if not git_root then + return + end local file = libuv.shellescape(path.relative_to(vim.fn.expand("%:p"), git_root)) local range if utils.mode_is_visual() then @@ -184,7 +206,9 @@ end M.blame = function(opts) opts = config.normalize_opts(opts, "git.blame") - if not opts then return end + if not opts then + return + end local bufname = vim.api.nvim_buf_get_name(0) if #bufname == 0 then utils.info("'blame' is not available for unnamed buffers.") @@ -195,7 +219,9 @@ M.blame = function(opts) opts.cwd = path.git_root({ cwd = vim.fn.expand("%:p:h") }, true) end local git_root = path.git_root(opts) - if not git_root then return end + if not git_root then + return + end local file = libuv.shellescape(path.relative_to(vim.fn.expand("%:p"), git_root)) local range if utils.mode_is_visual() then @@ -214,7 +240,9 @@ end M.branches = function(opts) opts = config.normalize_opts(opts, "git.branches") - if not opts then return end + if not opts then + return + end if opts.preview then opts.__preview = path.git_cwd(opts.preview, opts) opts.preview = shell.raw_preview_action_cmd(function(items) @@ -233,15 +261,21 @@ end M.tags = function(opts) opts = config.normalize_opts(opts, "git.tags") - if not opts then return end + if not opts then + return + end return git_cmd(opts) end M.stash = function(opts) opts = config.normalize_opts(opts, "git.stash") - if not opts then return end + if not opts then + return + end opts = set_git_cwd_args(opts) - if not opts.cwd then return end + if not opts.cwd then + return + end opts.preview = git_preview(opts) @@ -251,17 +285,17 @@ M.stash = function(opts) opts.cmd = opts.cmd .. " -G " .. libuv.shellescape(opts.search) end - opts.__fn_transform = opts.__fn_transform or - function(x) - local stash, rest = x:match("([^:]+)(.*)") - if stash then - stash = utils.ansi_codes.yellow(stash) - stash = stash:gsub("{%d+}", function(s) - return ("%s"):format(utils.ansi_codes.green(tostring(s))) - end) - end - return (not stash or not rest) and x or stash .. rest + opts.__fn_transform = opts.__fn_transform + or function(x) + local stash, rest = x:match("([^:]+)(.*)") + if stash then + stash = utils.ansi_codes.yellow(stash) + stash = stash:gsub("{%d+}", function(s) + return ("%s"):format(utils.ansi_codes.green(tostring(s))) + end) end + return (not stash or not rest) and x or stash .. rest + end opts.__fn_reload = function(_) return opts.cmd @@ -281,7 +315,9 @@ end M.hunks = function(opts) opts = config.normalize_opts(opts, "git.hunks") - if not opts then return end + if not opts then + return + end local cmd = path.git_cwd({ "git", "rev-parse", "--verify", opts.ref }, opts) local _, err = utils.io_systemlist(cmd) if err ~= 0 then @@ -290,7 +326,9 @@ M.hunks = function(opts) end opts.cmd = opts.cmd:gsub("[<{]ref[}>]", opts.ref) opts = set_git_cwd_args(opts) - if not opts.cwd then return end + if not opts.cwd then + return + end -- we don't need git icons since we get them -- as part of our `git status -s` @@ -304,10 +342,10 @@ M.hunks = function(opts) opts.__mt_transform = [[return require("fzf-lua.make_entry").git_hunk]] contents = core.mt_cmd_wrapper(opts) else - opts.__fn_transform = opts.__fn_transform or - function(x) - return make_entry.git_hunk(x, opts) - end + opts.__fn_transform = opts.__fn_transform + or function(x) + return make_entry.git_hunk(x, opts) + end -- we are reusing the "live" reload action, this gets called once -- on init and every reload and should return the command we wish diff --git a/lua/fzf-lua/providers/grep.lua b/lua/fzf-lua/providers/grep.lua index e1ceac097..3da36e6e2 100644 --- a/lua/fzf-lua/providers/grep.lua +++ b/lua/fzf-lua/providers/grep.lua @@ -1,10 +1,10 @@ local uv = vim.uv or vim.loop -local path = require "fzf-lua.path" -local core = require "fzf-lua.core" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local libuv = require "fzf-lua.libuv" -local make_entry = require "fzf-lua.make_entry" +local path = require("fzf-lua.path") +local core = require("fzf-lua.core") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local libuv = require("fzf-lua.libuv") +local make_entry = require("fzf-lua.make_entry") local M = {} @@ -36,7 +36,9 @@ local get_grep_cmd = function(opts, search_query, no_esc) }) do (function() -- Do nothing unless opt was set - if opts[k] == nil then return end + if opts[k] == nil then + return + end command = utils.toggle_cmd_flag(command, v, opts[k]) end)() end @@ -69,8 +71,7 @@ local get_grep_cmd = function(opts, search_query, no_esc) if not (no_esc or opts.no_esc) then new_query = utils.rg_escape(new_query) opts.no_esc = true - opts.search = ("%s%s"):format(new_query, - search_query:match(opts.glob_separator .. ".*")) + opts.search = ("%s%s"):format(new_query, search_query:match(opts.glob_separator .. ".*")) end search_query = new_query command = make_entry.rg_insert_args(command, glob_args) @@ -90,7 +91,8 @@ local get_grep_cmd = function(opts, search_query, no_esc) elseif opts.search_paths then local search_paths = type(opts.search_paths) == "table" -- NOTE: deepcopy to avoid recursive shellescapes with `actions.grep_lgrep` - and vim.deepcopy(opts.search_paths) or { tostring(opts.search_paths) } + and vim.deepcopy(opts.search_paths) + or { tostring(opts.search_paths) } -- Make paths relative, note this will not work well with resuming if changing -- the cwd, this is by design for perf reasons as having to deal with full paths -- will result in more code rouets taken in `make_entry.file` @@ -119,22 +121,27 @@ local get_grep_cmd = function(opts, search_query, no_esc) local bin = path.tail(command:match("[^%s]+")) local bin2flags = { grep = { { "--line-number", "-n" }, { "--recursive", "-r" } }, - rg = { { "--line-number", "-n" }, { "--column" } } + rg = { { "--line-number", "-n" }, { "--column" } }, } for _, flags in ipairs(bin2flags[bin] or {}) do local has_flag_group for _, f in ipairs(flags) do - if command:match("^" .. utils.lua_regex_escape(f)) - or command:match("%s+" .. utils.lua_regex_escape(f)) + if + command:match("^" .. utils.lua_regex_escape(f)) + or command:match("%s+" .. utils.lua_regex_escape(f)) then has_flag_group = true end end if not has_flag_group then if not opts.silent then - utils.warn(string.format( - "Added missing '%s' flag to '%s'. Add 'silent=true' to hide this message.", - table.concat(flags, "|"), bin)) + utils.warn( + string.format( + "Added missing '%s' flag to '%s'. Add 'silent=true' to hide this message.", + table.concat(flags, "|"), + bin + ) + ) end command = make_entry.rg_insert_args(command, flags[1]) end @@ -166,7 +173,9 @@ end M.grep = function(opts) opts = config.normalize_opts(opts, "grep") - if not opts then return end + if not opts then + return + end -- we need this for `actions.grep_lgrep` opts.__ACT_TO = opts.__ACT_TO or M.live_grep @@ -196,12 +205,17 @@ M.grep = function(opts) -- get the grep command before saving the last search -- in case the search string is overwritten by 'rg_glob' opts.cmd = get_grep_cmd(opts, opts.search, opts.no_esc) - if not opts.cmd then return end + if not opts.cmd then + return + end - local contents = core.mt_cmd_wrapper(vim.tbl_deep_extend("force", opts, + local contents = core.mt_cmd_wrapper(vim.tbl_deep_extend( + "force", + opts, -- query was already parsed for globs inside 'get_grep_cmd' -- no need for our external headless instance to parse again - { rg_glob = false })) + { rg_glob = false } + )) -- by redirecting the error stream to stdout -- we make sure a clear error message is displayed @@ -223,7 +237,9 @@ local function normalize_live_grep_opts(opts) opts._treesitter = false opts = config.normalize_opts(opts, "grep") - if not opts then return end + if not opts then + return + end -- we need this for `actions.grep_lgrep` opts.__ACT_TO = opts.__ACT_TO or M.grep @@ -260,7 +276,8 @@ local function normalize_live_grep_opts(opts) opts.__resume_get = function(what, o) return config.resume_get( what == "query" and "search" or what, - { __resume_key = o.__resume_key }) + { __resume_key = o.__resume_key } + ) end -- when using an empty string grep (as in 'grep_project') or @@ -293,7 +310,9 @@ end -- single threaded version M.live_grep_st = function(opts) opts = normalize_live_grep_opts(opts) - if not opts then return end + if not opts then + return + end assert(not opts.multiprocess) @@ -305,14 +324,14 @@ M.live_grep_st = function(opts) end if opts.requires_processing or opts.git_icons or opts.file_icons then - opts.fn_transform = opts.fn_transform or - function(x) - return make_entry.file(x, opts) - end - opts.fn_preprocess = opts.fn_preprocess or - function(o) - return make_entry.preprocess(o) - end + opts.fn_transform = opts.fn_transform + or function(x) + return make_entry.file(x, opts) + end + opts.fn_preprocess = opts.fn_preprocess + or function(o) + return make_entry.preprocess(o) + end end -- search query in header line @@ -325,7 +344,9 @@ end -- multi threaded (multi-process actually) version M.live_grep_mt = function(opts) opts = normalize_live_grep_opts(opts) - if not opts then return end + if not opts then + return + end assert(opts.multiprocess) @@ -343,7 +364,9 @@ M.live_grep_mt = function(opts) -- this will be replaced by the appropriate fzf -- FIELD INDEX EXPRESSION by 'fzf_exec' opts.cmd = get_grep_cmd(opts, core.fzf_query_placeholder, 2) - if not opts.cmd then return end + if not opts.cmd then + return + end local command = core.mt_cmd_wrapper(opts) @@ -400,7 +423,9 @@ end M.live_grep = function(opts) opts = config.normalize_opts(opts, "grep") - if not opts then return end + if not opts then + return + end if opts.multiprocess then return M.live_grep_mt(opts) @@ -411,7 +436,9 @@ end M.live_grep_glob = function(opts) opts = config.normalize_opts(opts, "grep") - if not opts then return end + if not opts then + return + end if opts.multiprocess then return M.live_grep_glob_mt(opts) @@ -421,19 +448,25 @@ M.live_grep_glob = function(opts) end M.live_grep_resume = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.resume = true return M.live_grep(opts) end M.grep_last = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.resume = true return M.grep(opts) end M.grep_cword = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.no_esc = true -- match whole words only (#968) opts.search = [[\b]] .. utils.rg_escape(vim.fn.expand("")) .. [[\b]] @@ -441,7 +474,9 @@ M.grep_cword = function(opts) end M.grep_cWORD = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.no_esc = true -- match neovim's WORD, match only surrounding space|SOL|EOL opts.search = [[(^|\s)]] .. utils.rg_escape(vim.fn.expand("")) .. [[($|\s)]] @@ -449,14 +484,20 @@ M.grep_cWORD = function(opts) end M.grep_visual = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.search = utils.get_visual_selection() return M.grep(opts) end M.grep_project = function(opts) - if not opts then opts = {} end - if not opts.search then opts.search = "" end + if not opts then + opts = {} + end + if not opts.search then + opts.search = "" + end -- by default, do not include filename in search opts.fzf_opts = opts.fzf_opts or {} if opts.fzf_opts["--delimiter"] == nil then @@ -473,7 +514,9 @@ M.grep_curbuf = function(opts, lgrep) -- 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 + 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 @@ -484,8 +527,7 @@ M.grep_curbuf = function(opts, lgrep) 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 = vim.tbl_deep_extend("keep", opts.__call_opts or {}, config.globals.grep_curbuf) opts.__call_opts.filename = opts.filename if lgrep then @@ -520,13 +562,17 @@ local grep_list = function(opts, lgrep, loclist) end opts.search_paths = files_from_qf(loclist) if utils.tbl_isempty(opts.search_paths) then - utils.info((loclist and "Location" or "Quickfix") - .. " list is empty or does not contain valid file buffers.") + utils.info( + (loclist and "Location" or "Quickfix") + .. " list is empty or does not contain valid file buffers." + ) return end opts.exec_empty_query = opts.exec_empty_query == nil and true opts = config.normalize_opts(opts, "grep") - if not opts then return end + if not opts then + return + end 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 68cb5ae27..40de4ba2d 100644 --- a/lua/fzf-lua/providers/helptags.lua +++ b/lua/fzf-lua/providers/helptags.lua @@ -1,13 +1,15 @@ -local path = require "fzf-lua.path" -local core = require "fzf-lua.core" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" +local path = require("fzf-lua.path") +local core = require("fzf-lua.core") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") local M = {} M.helptags = function(opts) opts = config.normalize_opts(opts, "helptags") - if not opts then return end + if not opts then + return + end local contents = function(cb) opts.lang = opts.lang or vim.o.helplang @@ -56,13 +58,15 @@ M.helptags = function(opts) local hl = (function() local _, _, fn = utils.ansi_from_hl("Label", "foo") - return function(s) return fn(s) end + return function(s) + return fn(s) + end end)() local add_tag = function(t, fzf_cb, co) local w = 80 + string.len(t.tag) - vim.fn.strwidth(t.tag) - local tag = string.format("%-" .. w .. "s %s%s%s", hl(t.tag), t.filename, utils.nbsp, - t.filepath) + local tag = + string.format("%-" .. w .. "s %s%s%s", hl(t.tag), t.filename, utils.nbsp, t.filepath) fzf_cb(tag, function() coroutine.resume(co) end) @@ -77,7 +81,7 @@ M.helptags = function(opts) 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 + if not line:match("^!_TAG_") then local fields = vim.split(line, delimiter) if #fields == 3 and not tags_map[fields[1]] then add_tag({ diff --git a/lua/fzf-lua/providers/lsp.lua b/lua/fzf-lua/providers/lsp.lua index df7592f96..ca8bc4a61 100644 --- a/lua/fzf-lua/providers/lsp.lua +++ b/lua/fzf-lua/providers/lsp.lua @@ -1,10 +1,10 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local actions = require "fzf-lua.actions" -local make_entry = require "fzf-lua.make_entry" +local core = require("fzf-lua.core") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local actions = require("fzf-lua.actions") +local make_entry = require("fzf-lua.make_entry") local M = {} @@ -75,7 +75,9 @@ local regex_filter_fn = function(regex_filter) end if type(regex_filter) == "table" and type(regex_filter[1]) == "string" then return function(item, _) - if not item.text then return true end + if not item.text then + return true + end local is_match = item.text:match(regex_filter[1]) ~= nil if regex_filter.exclude then return not is_match @@ -115,13 +117,13 @@ local function location_handler(opts, cb, _, result, ctx, _) local uri = vim.uri_from_bufnr(core.CTX().bufnr) local cursor_line = core.CTX().cursor[1] - 1 result = vim.tbl_filter(function(l) - if (l.uri - and l.uri == uri - and utils.map_get(l, "range.start.line") == cursor_line) - or - (l.targetUri - and l.targetUri == uri - and utils.map_get(l, "targetRange.start.line") == cursor_line) + if + (l.uri and l.uri == uri and utils.map_get(l, "range.start.line") == cursor_line) + or ( + l.targetUri + and l.targetUri == uri + and utils.map_get(l, "targetRange.start.line") == cursor_line + ) then return false end @@ -136,8 +138,10 @@ local function location_handler(opts, cb, _, result, ctx, _) -- here to accurately determine `jump1` (#980) result = vim.tbl_filter(function(x) local item = vim.lsp.util.locations_to_items({ x }, encoding)[1] - if (opts.cwd_only and not path.is_relative_to(item.filename, opts.cwd)) or - (opts._regex_filter_fn and not opts._regex_filter_fn(item, core.CTX())) then + if + (opts.cwd_only and not path.is_relative_to(item.filename, opts.cwd)) + or (opts._regex_filter_fn and not opts._regex_filter_fn(item, core.CTX())) + then return false end if opts.current_buffer_only and not path.equals(core.CTX().bname, item.filename) then @@ -154,7 +158,9 @@ local function location_handler(opts, cb, _, result, ctx, _) end end, result) -- Populate post-filter entries - vim.tbl_map(function(x) cb(x.entry, x) end, entries) + vim.tbl_map(function(x) + cb(x.entry, x) + end, entries) end local function call_hierarchy_handler(opts, cb, _, result, ctx, _) @@ -176,7 +182,9 @@ local function call_hierarchy_handler(opts, cb, _, result, ctx, _) end local entry = make_entry.lcol(location, opts) entry = make_entry.file(entry, opts) - if entry then cb(entry) end + if entry then + cb(entry) + end end end end @@ -206,7 +214,9 @@ local function symbols_to_items(symbols, bufnr, child_prefix) text = prefix .. "[" .. kind .. "] " .. symbol.name, }) if symbol.children then - for _, v in ipairs(_symbols_to_items(symbol.children, _items, _bufnr, prefix .. child_prefix)) do + for _, v in + ipairs(_symbols_to_items(symbol.children, _items, _bufnr, prefix .. child_prefix)) + do for _, s in ipairs(v) do table.insert(_items, s) end @@ -223,8 +233,11 @@ local function symbol_handler(opts, cb, _, result, ctx, _) result = utils.tbl_islist(result) and result or { result } local items if opts.child_prefix then - items = symbols_to_items(result, core.CTX().bufnr, - opts.child_prefix == true and string.rep(" ", 2) or opts.child_prefix) + items = symbols_to_items( + result, + core.CTX().bufnr, + opts.child_prefix == true and string.rep(" ", 2) or opts.child_prefix + ) else local encoding = vim.lsp.get_client_by_id(ctx.client_id).offset_encoding items = vim.lsp.util.symbols_to_items(result, core.CTX().bufnr, encoding) @@ -233,20 +246,23 @@ local function symbol_handler(opts, cb, _, result, ctx, _) opts._regex_filter_fn = regex_filter_fn(opts.regex_filter) end for _, entry in ipairs(items) do - if (not opts.current_buffer_only or core.CTX().bname == entry.filename) and - (not opts._regex_filter_fn or opts._regex_filter_fn(entry, core.CTX())) then + if + (not opts.current_buffer_only or core.CTX().bname == entry.filename) + and (not opts._regex_filter_fn or opts._regex_filter_fn(entry, core.CTX())) + then local mbicon_align = 0 if opts.fn_reload and type(opts.query) == "string" and #opts.query > 0 then -- highlight exact matches with `live_workspace_symbols` (#1028) local sym, text = entry.text:match("^(.+%])(.*)$") - local pattern = "[" .. utils.lua_regex_escape( - opts.query:gsub("%a", function(x) + local pattern = "[" + .. utils.lua_regex_escape(opts.query:gsub("%a", function(x) return string.upper(x) .. string.lower(x) + end)) + .. "]+" + entry.text = sym + .. text:gsub(pattern, function(x) + return utils.ansi_codes[opts.hls.live_sym](x) end) - ) .. "]+" - entry.text = sym .. text:gsub(pattern, function(x) - return utils.ansi_codes[opts.hls.live_sym](x) - end) end if M._sym2style then local kind = entry.text:match("%[(.-)%]") @@ -291,63 +307,63 @@ local handlers = { label = "References", server_capability = "referencesProvider", method = "textDocument/references", - handler = location_handler + handler = location_handler, }, ["definitions"] = { label = "Definitions", server_capability = "definitionProvider", method = "textDocument/definition", - handler = location_handler + handler = location_handler, }, ["declarations"] = { label = "Declarations", server_capability = "declarationProvider", method = "textDocument/declaration", - handler = location_handler + handler = location_handler, }, ["typedefs"] = { label = "Type Definitions", server_capability = "typeDefinitionProvider", method = "textDocument/typeDefinition", - handler = location_handler + handler = location_handler, }, ["implementations"] = { label = "Implementations", server_capability = "implementationProvider", method = "textDocument/implementation", - handler = location_handler + handler = location_handler, }, ["document_symbols"] = { label = "Document Symbols", server_capability = "documentSymbolProvider", method = "textDocument/documentSymbol", - handler = symbol_handler + handler = symbol_handler, }, ["workspace_symbols"] = { label = "Workspace Symbols", server_capability = "workspaceSymbolProvider", method = "workspace/symbol", - handler = symbol_handler + handler = symbol_handler, }, ["live_workspace_symbols"] = { label = "Workspace Symbols", server_capability = "workspaceSymbolProvider", method = "workspace/symbol", - handler = symbol_handler + handler = symbol_handler, }, ["incoming_calls"] = { label = "Incoming Calls", server_capability = "callHierarchyProvider", method = "callHierarchy/incomingCalls", prep = "textDocument/prepareCallHierarchy", - handler = call_hierarchy_handler + handler = call_hierarchy_handler, }, ["outgoing_calls"] = { label = "Outgoing Calls", server_capability = "callHierarchyProvider", method = "callHierarchy/outgoingCalls", prep = "textDocument/prepareCallHierarchy", - handler = call_hierarchy_handler + handler = call_hierarchy_handler, }, } @@ -372,12 +388,14 @@ local function gen_lsp_contents(opts) -- from the context buffer and cursor position if not lsp_params then lsp_params = function(client) - local params = vim.lsp.util.make_position_params(core.CTX().winid, + local params = vim.lsp.util.make_position_params( + core.CTX().winid, -- nvim 0.11 requires offset_encoding param, `client` is first arg of called func -- https://github.com/neovim/neovim/commit/629483e24eed3f2c07e55e0540c553361e0345a2 - client and client.offset_encoding or nil) + client and client.offset_encoding or nil + ) params.context = { - includeDeclaration = opts.includeDeclaration == nil and true or opts.includeDeclaration + includeDeclaration = opts.includeDeclaration == nil and true or opts.includeDeclaration, } return params end @@ -392,8 +410,8 @@ local function gen_lsp_contents(opts) if type(opts.async_or_timeout) == "number" then timeout = opts.async_or_timeout end - local lsp_results, err = vim.lsp.buf_request_sync(core.CTX().bufnr, - lsp_handler.method, lsp_params, timeout) + local lsp_results, err = + vim.lsp.buf_request_sync(core.CTX().bufnr, lsp_handler.method, lsp_params, timeout) if err then utils.err(string.format("Error executing '%s': %s", lsp_handler.method, err)) else @@ -401,8 +419,12 @@ local function gen_lsp_contents(opts) local jump1 local cb = function(text, x) -- Only populate jump1 with the first entry - if jump1 then jump1 = false end - if x and jump1 == nil then jump1 = { result = x.result, encoding = x.encoding } end + if jump1 then + jump1 = false + end + if x and jump1 == nil then + jump1 = { result = x.result, encoding = x.encoding } + end table.insert(results, text) end for client_id, response in pairs(lsp_results) do @@ -410,8 +432,9 @@ local function gen_lsp_contents(opts) local context = { client_id = client_id } lsp_handler.handler(opts, cb, lsp_handler.method, response.result, context, nil) elseif response.error then - utils.warn(string.format("Error executing '%s': %s", - lsp_handler.method, response.error.message)) + utils.warn( + string.format("Error executing '%s': %s", lsp_handler.method, response.error.message) + ) end end if utils.tbl_isempty(results) then @@ -430,7 +453,9 @@ local function gen_lsp_contents(opts) coroutine.wrap(function() local co = coroutine.running() for _, e in ipairs(results) do - fzf_cb(e, function() coroutine.resume(co) end) + fzf_cb(e, function() + coroutine.resume(co) + end) coroutine.yield() end fzf_cb(nil) @@ -458,13 +483,13 @@ local function gen_lsp_contents(opts) -- so we can determine if all callbacks were completed (#468) local async_opts = { num_callbacks = 0, - num_clients = check_capabilities(lsp_handler, opts.silent), + num_clients = check_capabilities(lsp_handler, opts.silent), -- signals the handler to not print a warning when empty result set -- is returned, important for `live_workspace_symbols` when the user -- inputs a query that returns no results -- also used with `finder` to prevent the window from being closed - no_autoclose = opts.no_autoclose or opts.fn_reload, - silent = opts.silent or opts.fn_reload, + no_autoclose = opts.no_autoclose or opts.fn_reload, + silent = opts.silent or opts.fn_reload, } -- when used with 'live_workspace_symbols' @@ -474,8 +499,10 @@ local function gen_lsp_contents(opts) local async_buf_request = function() -- save cancel all fnref so we can cancel all requests -- when using `live_ws_symbols` - _, opts._cancel_all = vim.lsp.buf_request(core.CTX().bufnr, - lsp_handler.method, lsp_params, + _, opts._cancel_all = vim.lsp.buf_request( + core.CTX().bufnr, + lsp_handler.method, + lsp_params, function(err, result, context, lspcfg) -- Increment client callback counter async_opts.num_callbacks = async_opts.num_callbacks + 1 @@ -485,7 +512,8 @@ local function gen_lsp_contents(opts) utils.err(string.format("Error executing '%s': %s", lsp_handler.method, err)) end coroutine.resume(co, done, err, result, context, lspcfg) - end) + end + ) end -- When called from another coroutine callback (when using 'finder') will err: @@ -508,15 +536,21 @@ local function gen_lsp_contents(opts) -- Increment result callback counter num_results = num_results + 1 -- Only populate jump1 with the first entry - if jump1 then jump1 = false end - if x and jump1 == nil then jump1 = { result = x.result, encoding = x.encoding } end - fzf_cb(e, function() coroutine.resume(co) end) + if jump1 then + jump1 = false + end + if x and jump1 == nil then + jump1 = { result = x.result, encoding = x.encoding } + end + fzf_cb(e, function() + coroutine.resume(co) + end) coroutine.yield() end lsp_handler.handler(opts, cb, lsp_handler.method, result, context, lspcfg) end - -- some clients may not always return results (null-ls?) - -- so don't terminate the loop when 'result == nil` + -- some clients may not always return results (null-ls?) + -- so don't terminate the loop when 'result == nil` until done -- no more results @@ -549,10 +583,10 @@ end -- see $VIMRUNTIME/lua/vim/buf.lua:pick_call_hierarchy_item() local function gen_lsp_contents_call_hierarchy(opts) local lsp_params = opts.lsp_params - or not utils.__HAS_NVIM_011 and vim.lsp.util.make_position_params(core.CTX().winid) - or function(client) - return vim.lsp.util.make_position_params(core.CTX().winid, client.offset_encoding) - end + or not utils.__HAS_NVIM_011 and vim.lsp.util.make_position_params(core.CTX().winid) + or function(client) + return vim.lsp.util.make_position_params(core.CTX().winid, client.offset_encoding) + end local res, err = vim.lsp.buf_request_sync(0, opts.lsp_handler.prep, lsp_params, 2000) if err then utils.err(("Error executing '%s': %s"):format(opts.lsp_handler.prep, err)) @@ -572,12 +606,17 @@ end local normalize_lsp_opts = function(opts, cfg, __resume_key) opts = config.normalize_opts(opts, cfg, __resume_key) - if not opts then return end + if not opts then + return + end -- `title_prefix` is priortized over both `prompt` and `prompt_prefix` if (not opts.winopts or opts.winopts.title == nil) and opts.title_prefix then - utils.map_set(opts, - "winopts.title", string.format(" %s %s ", opts.title_prefix, opts.lsp_handler.label)) + utils.map_set( + opts, + "winopts.title", + string.format(" %s %s ", opts.title_prefix, opts.lsp_handler.label) + ) elseif opts.prompt == nil and opts.prompt_postfix then opts.prompt = opts.lsp_handler.label .. (opts.prompt_postfix or "") end @@ -594,7 +633,9 @@ end local function fzf_lsp_locations(opts, fn_contents) opts = normalize_lsp_opts(opts, "lsp") - if not opts then return end + if not opts then + return + end opts = core.set_fzf_field_index(opts) opts = fn_contents(opts) if not opts or not opts.__contents then @@ -636,7 +677,9 @@ end M.finder = function(opts) opts = normalize_lsp_opts(opts, "lsp.finder") - if not opts then return end + if not opts then + return + end local contents = {} local lsp_params = opts.lsp_params for _, p in ipairs(opts.providers) do @@ -667,8 +710,10 @@ M.finder = function(opts) -- make sure we add only valid contents -- sync returns empty table when no results are found if type(c) == "function" then - table.insert(contents, - { prefix = (p.prefix or "") .. (opts.separator or ""), contents = c }) + table.insert( + contents, + { prefix = (p.prefix or "") .. (opts.separator or ""), contents = c } + ) end end end @@ -685,7 +730,9 @@ end local function gen_sym2style_map(opts) assert(opts.symbol_style ~= nil) - if M._sym2style then return end + if M._sym2style then + return + end M._sym2style = {} for kind, icon in pairs(opts.symbol_icons) do -- style==1: " " @@ -717,11 +764,12 @@ end M.document_symbols = function(opts) opts = normalize_lsp_opts(opts, "lsp.symbols", "lsp_document_symbols") - if not opts then return end + if not opts then + return + end -- no support for sym_lsym for k, fn in pairs(opts.actions or {}) do - if type(fn) == "table" and - (fn[1] == actions.sym_lsym or fn.fn == actions.sym_lsym) then + if type(fn) == "table" and (fn[1] == actions.sym_lsym or fn.fn == actions.sym_lsym) then opts.actions[k] = nil end end @@ -736,8 +784,12 @@ M.document_symbols = function(opts) opts.fzf_opts["--with-nth"] = "..-4" end if opts.symbol_style or opts.symbol_fmt then - opts.fn_pre_fzf = function() gen_sym2style_map(opts) end - opts.fn_post_fzf = function() M._sym2style = nil end + opts.fn_pre_fzf = function() + gen_sym2style_map(opts) + end + opts.fn_post_fzf = function() + M._sym2style = nil + end -- run once in case we're not running async opts.fn_pre_fzf() end @@ -751,12 +803,13 @@ end M.workspace_symbols = function(opts) opts = normalize_lsp_opts(opts, "lsp.symbols", "lsp_workspace_symbols") - if not opts then return end + if not opts then + return + end opts.__ACT_TO = opts.__ACT_TO or M.live_workspace_symbols opts.__call_fn = utils.__FNCREF__() opts.lsp_params = { query = opts.lsp_query or "" } - opts = core.set_header(opts, opts.headers or - { "actions", "cwd", "lsp_query", "regex_filter" }) + opts = core.set_header(opts, opts.headers or { "actions", "cwd", "lsp_query", "regex_filter" }) opts = core.set_fzf_field_index(opts) opts = gen_lsp_contents(opts) if not opts.__contents then @@ -767,16 +820,21 @@ M.workspace_symbols = function(opts) opts.prompt = utils.ansi_from_hl(opts.hls.live_prompt, opts.lsp_query) .. " > " end if opts.symbol_style or opts.symbol_fmt then - opts.fn_pre_fzf = function() gen_sym2style_map(opts) end - opts.fn_post_fzf = function() M._sym2style = nil end + opts.fn_pre_fzf = function() + gen_sym2style_map(opts) + end + opts.fn_post_fzf = function() + M._sym2style = nil + end end return core.fzf_exec(opts.__contents, opts) end - M.live_workspace_symbols = function(opts) opts = normalize_lsp_opts(opts, "lsp.symbols", "lsp_workspace_symbols") - if not opts then return end + if not opts then + return + end -- needed by 'actions.sym_lsym' opts.__ACT_TO = opts.__ACT_TO or M.workspace_symbols @@ -793,8 +851,10 @@ M.live_workspace_symbols = function(opts) -- the prompt input is the LSP query, store as "lsp_query" opts.__resume_set = function(what, val, o) config.resume_set( - what == "query" and "lsp_query" or what, val, - { __resume_key = o.__resume_key }) + what == "query" and "lsp_query" or what, + val, + { __resume_key = o.__resume_key } + ) utils.map_set(config, "__resume_data.last_query", val) -- also store query for `fzf_resume` (#963) utils.map_set(config, "__resume_data.opts.query", val) @@ -804,7 +864,8 @@ M.live_workspace_symbols = function(opts) opts.__resume_get = function(what, o) return config.resume_get( what == "query" and "lsp_query" or what, - { __resume_key = o.__resume_key }) + { __resume_key = o.__resume_key } + ) end -- if no lsp_query was set, use previous prompt query (from the non-live version) @@ -832,15 +893,21 @@ M.live_workspace_symbols = function(opts) opts = core.set_header(opts, opts.headers or { "actions", "cwd", "regex_filter" }) opts = core.set_fzf_field_index(opts) if opts.symbol_style or opts.symbol_fmt then - opts.fn_pre_fzf = function() gen_sym2style_map(opts) end - opts.fn_post_fzf = function() M._sym2style = nil end + opts.fn_pre_fzf = function() + gen_sym2style_map(opts) + end + opts.fn_post_fzf = function() + M._sym2style = nil + end end return core.fzf_exec(nil, opts) end M.code_actions = function(opts) opts = normalize_lsp_opts(opts, "lsp.code_actions") - if not opts then return end + if not opts then + return + end -- code actions uses `vim.ui.select`, requires neovim >= 0.6 if vim.fn.has("nvim-0.6") ~= 1 then @@ -848,12 +915,14 @@ M.code_actions = function(opts) return end - local ui_select = require "fzf-lua.providers.ui_select" + local ui_select = require("fzf-lua.providers.ui_select") local registered = ui_select.is_registered() if not registered and not opts.silent then - utils.warn("FzfLua is not currently registered as 'vim.ui.select' backend, use 'silent=true'" .. - " to hide this message or register globally using ':FzfLua register_ui_select'.") + utils.warn( + "FzfLua is not currently registered as 'vim.ui.select' backend, use 'silent=true'" + .. " to hide this message or register globally using ':FzfLua register_ui_select'." + ) end opts.actions = opts.actions or {} @@ -900,5 +969,5 @@ return setmetatable({}, { else return M[key] end - end + end, }) diff --git a/lua/fzf-lua/providers/manpages.lua b/lua/fzf-lua/providers/manpages.lua index 85603a7a1..02c731d2c 100644 --- a/lua/fzf-lua/providers/manpages.lua +++ b/lua/fzf-lua/providers/manpages.lua @@ -1,7 +1,7 @@ -local core = require "fzf-lua.core" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local libuv = require "fzf-lua.libuv" +local core = require("fzf-lua.core") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local libuv = require("fzf-lua.libuv") local M = {} @@ -28,7 +28,9 @@ end M.manpages = function(opts) opts = config.normalize_opts(opts, "manpages") - if not opts then return end + if not opts then + return + end if utils.__IS_WINDOWS then utils.warn("man is not supported on Windows.") diff --git a/lua/fzf-lua/providers/module.lua b/lua/fzf-lua/providers/module.lua index 2e1764cdc..70f169457 100644 --- a/lua/fzf-lua/providers/module.lua +++ b/lua/fzf-lua/providers/module.lua @@ -1,15 +1,19 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" +local core = require("fzf-lua.core") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") local M = {} M.metatable = function(opts) - if not opts then return end + if not opts then + return + end - if not opts.metatable then opts.metatable = getmetatable("").__index end + if not opts.metatable then + opts.metatable = getmetatable("").__index + end local methods = {} for k, _ in pairs(opts.metatable) do @@ -18,7 +22,9 @@ M.metatable = function(opts) end end - table.sort(methods, function(a, b) return a < b end) + table.sort(methods, function(a, b) + return a < b + end) opts.preview = function(args) local options_md = require("fzf-lua.cmd").options_md() @@ -55,7 +61,9 @@ end M.profiles = function(opts) opts = config.normalize_opts(opts, "profiles") - if not opts then return end + if not opts then + return + end if opts.load then -- silent = [2] @@ -64,7 +72,7 @@ M.profiles = function(opts) end local dirs = { - path.join({ vim.g.fzf_lua_directory, "profiles" }) + path.join({ vim.g.fzf_lua_directory, "profiles" }), } local contents = function(cb) @@ -78,11 +86,13 @@ M.profiles = function(opts) local profile = name:sub(1, #name - 4) local res = utils.load_profile_fname(fname, profile, true) if res then - local entry = string.format("%s:%-30s%s", fname, - utils.ansi_codes.yellow(profile), res.desc or "") + local entry = + string.format("%s:%-30s%s", fname, utils.ansi_codes.yellow(profile), res.desc or "") cb(entry, function(err) coroutine.resume(co) - if err then cb(nil) end + if err then + cb(nil) + end end) coroutine.yield() end diff --git a/lua/fzf-lua/providers/nvim.lua b/lua/fzf-lua/providers/nvim.lua index 18ee42e86..ffb444e46 100644 --- a/lua/fzf-lua/providers/nvim.lua +++ b/lua/fzf-lua/providers/nvim.lua @@ -1,18 +1,20 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local shell = require "fzf-lua.shell" -local config = require "fzf-lua.config" -local devicons = require "fzf-lua.devicons" +local core = require("fzf-lua.core") +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local shell = require("fzf-lua.shell") +local config = require("fzf-lua.config") +local devicons = require("fzf-lua.devicons") local M = {} M.commands = function(opts) opts = config.normalize_opts(opts, "commands") - if not opts then return end + if not opts then + return + end - local global_commands = vim.api.nvim_get_commands {} + local global_commands = vim.api.nvim_get_commands({}) local buf_commands = vim.api.nvim_buf_get_commands(0, {}) local builtin_commands = {} @@ -23,17 +25,23 @@ M.commands = function(opts) local cmd, desc for line in utils.read_file(help):gmatch("[^\n]*\n") do if line:match("^|:[^|]") then - if cmd then builtin_commands[cmd] = desc end + if cmd then + builtin_commands[cmd] = desc + end cmd, desc = line:match("^|:(%S+)|%s*%S+%s*(.*%S)") elseif cmd then -- found if line:match("^%s+%S") then local desc_continue = line:match("^%s*(.*%S)") desc = desc .. (desc_continue and " " .. desc_continue or "") end - if line:match("^%s*$") then break end + if line:match("^%s*$") then + break + end end end - if cmd then builtin_commands[cmd] = desc end + if cmd then + builtin_commands[cmd] = desc + end end end @@ -67,28 +75,36 @@ M.commands = function(opts) for k, _ in pairs(global_commands) do table.insert(entries, utils.ansi_codes.blue(k)) local flattened = vim.is_callable(opts.flatten[k]) and opts.flatten[k](opts) - or opts.flatten[k] and vim.fn.getcompletion(k .. " ", "cmdline") - or {} - vim.list_extend(entries, - vim.tbl_map(function(cmd) return utils.ansi_codes.blue(k .. " " .. cmd) end, - flattened)) + or opts.flatten[k] and vim.fn.getcompletion(k .. " ", "cmdline") + or {} + vim.list_extend( + entries, + vim.tbl_map(function(cmd) + return utils.ansi_codes.blue(k .. " " .. cmd) + end, flattened) + ) end for k, v in pairs(buf_commands) do if type(v) == "table" then table.insert(entries, utils.ansi_codes.green(k)) local flattened = vim.is_callable(opts.flatten[k]) and opts.flatten[k](opts) - or opts.flatten[k] and vim.fn.getcompletion(k .. " ", "cmdline") - or {} - vim.list_extend(entries, - vim.tbl_map(function(cmd) return utils.ansi_codes.green(k .. " " .. cmd) end, - flattened)) + or opts.flatten[k] and vim.fn.getcompletion(k .. " ", "cmdline") + or {} + vim.list_extend( + entries, + vim.tbl_map(function(cmd) + return utils.ansi_codes.green(k .. " " .. cmd) + end, flattened) + ) end end -- Sort before adding "builtin" so they don't end up atop the list if not opts.sort_lastused then - table.sort(entries, function(a, b) return a < b end) + table.sort(entries, function(a, b) + return a < b + end) end for k, _ in pairs(builtin_commands) do @@ -108,11 +124,11 @@ end ---@param str ":"|"/" local history = function(opts, str) - local histnr = vim.fn.histnr(str) - local dr = opts.reverse_list and 1 or -1 - local bulk = 500 + local histnr = vim.fn.histnr(str) + local dr = opts.reverse_list and 1 or -1 + local bulk = 500 local from, to, delta = dr, dr * histnr, dr * bulk - local content = coroutine.wrap(function(cb) + local content = coroutine.wrap(function(cb) local co = coroutine.running() for i = from, to, delta do vim.schedule(function() @@ -138,7 +154,9 @@ end M.command_history = function(opts) opts = config.normalize_opts(opts, "command_history") - if not opts then return end + if not opts then + return + end if opts.fzf_opts["--header"] == nil then opts = core.set_header(opts, opts.headers or { "actions" }) end @@ -147,7 +165,9 @@ end M.search_history = function(opts) opts = config.normalize_opts(opts, "search_history") - if not opts then return end + if not opts then + return + end if opts.fzf_opts["--header"] == nil then opts = core.set_header(opts, opts.headers or { "actions" }) end @@ -161,7 +181,9 @@ end M.jumps = function(opts) opts = config.normalize_opts(opts, "jumps") - if not opts then return end + if not opts then + return + end local jumps = vim.fn.execute(opts.cmd) jumps = vim.split(jumps, "\n") @@ -169,11 +191,16 @@ M.jumps = function(opts) local entries = {} for i = #jumps - 1, 3, -1 do local jump, line, col, text = jumps[i]:match("(%d+)%s+(%d+)%s+(%d+)%s+(.*)") - table.insert(entries, string.format(" %16s %15s %15s %s", - utils.ansi_codes.yellow(jump), - utils.ansi_codes.blue(line), - utils.ansi_codes.green(col), - text)) + table.insert( + entries, + string.format( + " %16s %15s %15s %s", + utils.ansi_codes.yellow(jump), + utils.ansi_codes.blue(line), + utils.ansi_codes.green(col), + text + ) + ) end if utils.tbl_isempty(entries) then @@ -181,8 +208,11 @@ M.jumps = function(opts) return end - table.insert(entries, 1, - string.format("%6s %s %s %s", opts.h1 or "jump", "line", "col", "file/text")) + table.insert( + entries, + 1, + string.format("%6s %s %s %s", opts.h1 or "jump", "line", "col", "file/text") + ) opts.fzf_opts["--header-lines"] = 1 @@ -191,7 +221,9 @@ end M.tagstack = function(opts) opts = config.normalize_opts(opts, "tagstack") - if not opts then return end + if not opts then + return + end local tagstack = vim.fn.gettagstack().items @@ -225,60 +257,79 @@ M.tagstack = function(opts) end end -- table.insert(entries, ("%s)%s[%s]%s%s%s%s:%s:%s: %s %s"):format( - table.insert(entries, ("%s)%s%s%s%s:%s:%s: %s %s"):format( - utils.ansi_codes.yellow(tostring(i)), - utils.nbsp, - -- utils.ansi_codes.yellow(tostring(tag.bufnr)), - -- utils.nbsp, - buficon or "", - buficon and utils.nbsp or "", - utils.ansi_codes.magenta(#bufname > 0 and bufname or "[No Name]"), - utils.ansi_codes.green(tostring(tag.lnum)), - tag.col, - utils.ansi_codes.red("[" .. tag.tagname .. "]"), - tag.text)) + table.insert( + entries, + ("%s)%s%s%s%s:%s:%s: %s %s"):format( + utils.ansi_codes.yellow(tostring(i)), + utils.nbsp, + -- utils.ansi_codes.yellow(tostring(tag.bufnr)), + -- utils.nbsp, + buficon or "", + buficon and utils.nbsp or "", + utils.ansi_codes.magenta(#bufname > 0 and bufname or "[No Name]"), + utils.ansi_codes.green(tostring(tag.lnum)), + tag.col, + utils.ansi_codes.red("[" .. tag.tagname .. "]"), + tag.text + ) + ) end core.fzf_exec(entries, opts) end - M.marks = function(opts) opts = config.normalize_opts(opts, "marks") - if not opts then return end - - opts.__fn_reload = opts.__fn_reload or function() - return function(cb) - local win = core.CTX().winid - local buf = core.CTX().bufnr - local marks = vim.api.nvim_win_call(win, - function() return vim.api.nvim_buf_call(buf, function() return vim.fn.execute("marks") end) end) - marks = vim.split(marks, "\n") - local entries = {} - local pattern = opts.marks and opts.marks or "" - for i = #marks, 3, -1 do - local mark, line, col, text = marks[i]:match("(.)%s+(%d+)%s+(%d+)%s+(.*)") - col = tostring(tonumber(col) + 1) - if path.is_absolute(text) then - text = path.HOME_to_tilde(text) - end - if not pattern or string.match(mark, pattern) then - table.insert(entries, string.format(" %-15s %15s %15s %s", - utils.ansi_codes.yellow(mark), - utils.ansi_codes.blue(line), - utils.ansi_codes.green(col), - text)) + if not opts then + return + end + + opts.__fn_reload = opts.__fn_reload + or function() + return function(cb) + local win = core.CTX().winid + local buf = core.CTX().bufnr + local marks = vim.api.nvim_win_call(win, function() + return vim.api.nvim_buf_call(buf, function() + return vim.fn.execute("marks") + end) + end) + marks = vim.split(marks, "\n") + local entries = {} + local pattern = opts.marks and opts.marks or "" + for i = #marks, 3, -1 do + local mark, line, col, text = marks[i]:match("(.)%s+(%d+)%s+(%d+)%s+(.*)") + col = tostring(tonumber(col) + 1) + if path.is_absolute(text) then + text = path.HOME_to_tilde(text) + end + if not pattern or string.match(mark, pattern) then + table.insert( + entries, + string.format( + " %-15s %15s %15s %s", + utils.ansi_codes.yellow(mark), + utils.ansi_codes.blue(line), + utils.ansi_codes.green(col), + text + ) + ) + end end - end - table.sort(entries, function(a, b) return a < b end) - table.insert(entries, 1, - string.format("%-5s %s %s %s", "mark", "line", "col", "file/text")) + table.sort(entries, function(a, b) + return a < b + end) + table.insert( + entries, + 1, + string.format("%-5s %s %s %s", "mark", "line", "col", "file/text") + ) - vim.tbl_map(cb, entries) - cb(nil) + vim.tbl_map(cb, entries) + cb(nil) + end end - end -- build the "reload" cmd and remove '-- {+}' from the initial cmd local contents, id = shell.reload_action_cmd(opts, "") @@ -288,7 +339,6 @@ M.marks = function(opts) shell.set_protected(id) end - opts.fzf_opts["--header-lines"] = 1 --[[ opts.preview = function (args, fzf_lines, _) local mark = args[1]:match("[^ ]+") @@ -309,7 +359,9 @@ end M.registers = function(opts) opts = config.normalize_opts(opts, "registers") - if not opts then return end + if not opts then + return + end local registers = { [["]], "_", "#", "=", "_", "/", "*", "+", ":", ".", "%" } -- named @@ -323,16 +375,18 @@ M.registers = function(opts) if type(opts.filter) == "string" or type(opts.filter) == "function" then local filter = type(opts.filter) == "function" and opts.filter - or function(r) - return r:match(opts.filter) ~= nil - end + or function(r) + return r:match(opts.filter) ~= nil + end registers = vim.tbl_filter(filter, registers) end local function register_escape_special(reg, nl) - if not reg then return end + if not reg then + return + end local gsub_map = { - ["\3"] = "^C", -- + ["\3"] = "^C", -- ["\27"] = "^[", -- ["\18"] = "^R", -- } @@ -340,8 +394,8 @@ M.registers = function(opts) reg = reg:gsub(k, utils.ansi_codes.magenta(v)) end return not nl and reg - or nl == 2 and reg:gsub("\n$", "") - or reg:gsub("\n", utils.ansi_codes.magenta("\\n")) + or nl == 2 and reg:gsub("\n$", "") + or reg:gsub("\n", utils.ansi_codes.magenta("\\n")) end local entries = {} @@ -352,8 +406,7 @@ M.registers = function(opts) local _, contents = pcall(vim.fn.getreg, r) contents = register_escape_special(contents, opts.multiline and 2 or 1) if (contents and #contents > 0) or not opts.ignore_empty then - table.insert(entries, string.format("[%s] %s", - utils.ansi_codes.yellow(r), contents)) + table.insert(entries, string.format("[%s] %s", utils.ansi_codes.yellow(r), contents)) end end @@ -368,7 +421,9 @@ end M.keymaps = function(opts) opts = config.normalize_opts(opts, "keymaps") - if not opts then return end + if not opts then + return + end local key_modes = opts.modes or { "n", "i", "c", "v", "t" } local modes = { @@ -376,23 +431,31 @@ M.keymaps = function(opts) i = "red", c = "yellow", v = "magenta", - t = "green" + t = "green", } local keymaps = {} local separator = "│" local fields = { "mode", "lhs", "desc", "rhs" } local field_fmt = { mode = "%s", lhs = "%-14s", desc = "%-33s", rhs = "%s" } - if opts.show_desc == false then field_fmt.desc = nil end - if opts.show_details == false then field_fmt.rhs = nil end + if opts.show_desc == false then + field_fmt.desc = nil + end + if opts.show_details == false then + field_fmt.rhs = nil + end local format = function(info) info.desc = field_fmt.rhs and string.sub(info.desc or "", 1, 33) or info.desc local ret for _, f in ipairs(fields) do if field_fmt[f] then - ret = string.format("%s%s" .. field_fmt[f], ret or "", - ret and string.format(" %s ", separator) or "", info[f] or "") + ret = string.format( + "%s%s" .. field_fmt[f], + ret or "", + ret and string.format(" %s ", separator) or "", + info[f] or "" + ) end end return ret @@ -417,10 +480,10 @@ M.keymaps = function(opts) keymap.str = format({ mode = utils.ansi_codes[modes[keymap.mode] or "blue"](keymap.mode), - lhs = keymap.lhs:gsub("%s", ""), + lhs = keymap.lhs:gsub("%s", ""), -- desc can be a multi-line string, normalize it desc = keymap.desc and string.gsub(keymap.desc, "\n%s+", "\r"), - rhs = keymap.rhs or string.format("%s", keymap.callback) + rhs = keymap.rhs or string.format("%s", keymap.callback), }) local k = string.format("[%s:%s:%s]", keymap.buffer, keymap.mode, keymap.lhs) @@ -456,7 +519,9 @@ end M.nvim_options = function(opts) opts = config.normalize_opts(opts, "nvim_options") - if not opts then return end + if not opts then + return + end local format_str = function(info) local fields = { "option", "value" } @@ -468,8 +533,7 @@ M.nvim_options = function(opts) ret = string.format( "%s%s" .. field_fmt[f], ret or "", - ret and string.format(" %s ", utils.ansi_codes["grey"](opts.separator)) - or " ", + ret and string.format(" %s ", utils.ansi_codes["grey"](opts.separator)) or " ", info[f] or "" ) end @@ -501,32 +565,34 @@ M.nvim_options = function(opts) utils.ansi_from_hl(opts.hls.header_bind, ""), utils.ansi_from_hl(opts.hls.header_text, "local scope"), utils.ansi_from_hl(opts.hls.header_bind, ""), - utils.ansi_from_hl(opts.hls.header_text, "global scope")) + utils.ansi_from_hl(opts.hls.header_text, "global scope") + ) table.insert(entries, 1, keymaps) table.insert(entries, 2, header) return entries end opts.func_async_callback = false - opts.__fn_reload = opts.__fn_reload or function(_) - return function(cb) - vim.api.nvim_win_call(opts.__CTX.winid, function() - coroutine.wrap(function() - local co = coroutine.running() - local entries = format_option_entries() - for _, entry in pairs(entries) do - vim.schedule(function() - cb(entry, function() - coroutine.resume(co) + opts.__fn_reload = opts.__fn_reload + or function(_) + return function(cb) + vim.api.nvim_win_call(opts.__CTX.winid, function() + coroutine.wrap(function() + local co = coroutine.running() + local entries = format_option_entries() + for _, entry in pairs(entries) do + vim.schedule(function() + cb(entry, function() + coroutine.resume(co) + end) end) - end) - coroutine.yield() - end - cb() - end)() - end) + coroutine.yield() + end + cb() + end)() + end) + end end - end -- build the "reload" cmd and remove '-- {+}' from the initial cmd local contents, id = shell.reload_action_cmd(opts, "") @@ -544,7 +610,9 @@ end M.spell_suggest = function(opts) -- if not vim.wo.spell then return false end opts = config.normalize_opts(opts, "spell_suggest") - if not opts then return end + if not opts then + return + end local match = opts.word_pattern or "[^%s\"'%(%)%.%%%+%-%*%?%[%]%^%$:#,]*" local line = vim.api.nvim_get_current_line() @@ -561,32 +629,46 @@ M.spell_suggest = function(opts) local entries = vim.fn.spellsuggest(cursor_word) opts.complete = function(selected, o, l, _) - if #selected == 0 then return end + if #selected == 0 then + return + end local replace_at = col - #before local before_path = replace_at > 1 and l:sub(1, replace_at - 1) or "" local rest_of_line = #l >= (col + #after) and l:sub(col + #after) or "" return before_path .. selected[1] .. rest_of_line, - -- this goes to `nvim_win_set_cursor` which is 0-based - replace_at + #selected[1] - 2 + -- this goes to `nvim_win_set_cursor` which is 0-based + replace_at + + #selected[1] + - 2 end - if utils.tbl_isempty(entries) then return end + if utils.tbl_isempty(entries) then + return + end core.fzf_exec(entries, opts) end M.filetypes = function(opts) opts = config.normalize_opts(opts, "filetypes") - if not opts then return end + if not opts then + return + end local entries = vim.fn.getcompletion("", "filetype") - if utils.tbl_isempty(entries) then return end + if utils.tbl_isempty(entries) then + return + end if opts.file_icons then entries = vim.tbl_map(function(ft) local buficon, hl = devicons.icon_by_ft(ft) - if not buficon then buficon = " " end - if hl then buficon = utils.ansi_from_hl(hl, buficon) end + if not buficon then + buficon = " " + end + if hl then + buficon = utils.ansi_from_hl(hl, buficon) + end return string.format("%s%s%s", buficon, utils.nbsp, ft) end, entries) end @@ -596,37 +678,41 @@ end M.packadd = function(opts) opts = config.normalize_opts(opts, "packadd") - if not opts then return end + if not opts then + return + end local entries = vim.fn.getcompletion("", "packadd") - if utils.tbl_isempty(entries) then return end + if utils.tbl_isempty(entries) then + return + end core.fzf_exec(entries, opts) end M.menus = function(opts) opts = config.normalize_opts(opts, "menus") - if not opts then return end + if not opts then + return + end -- @param prefix will be prepended to the entry name local function gen_menu_entries(prefix, entry) local name = prefix and ("%s.%s"):format(prefix, entry.name) or entry.name if entry.submenus then -- entry.submenus is a list of {} - return vim.tbl_map( - function(x) - return gen_menu_entries(name, x) - end, entry.submenus) + return vim.tbl_map(function(x) + return gen_menu_entries(name, x) + end, entry.submenus) else -- if we reached a leaf return name end end - local entries = utils.tbl_flatten(vim.tbl_map( - function(x) - return gen_menu_entries(nil, x) - end, vim.fn.menu_get(""))) + local entries = utils.tbl_flatten(vim.tbl_map(function(x) + return gen_menu_entries(nil, x) + end, vim.fn.menu_get(""))) if utils.tbl_isempty(entries) then utils.info("No menus available") @@ -638,7 +724,9 @@ end M.autocmds = function(opts) opts = config.normalize_opts(opts, "autocmds") - if not opts then return end + if not opts then + return + end local autocmds = vim.api.nvim_get_autocmds({}) if not autocmds or utils.tbl_isempty(autocmds) then @@ -655,7 +743,9 @@ M.autocmds = function(opts) desc = "%s", } - if opts.show_desc == false then field_fmt.desc = nil end + if opts.show_desc == false then + field_fmt.desc = nil + end local format = function(info) local ret @@ -668,8 +758,12 @@ M.autocmds = function(opts) fmt = fmt:gsub("%d+", tostring(len - 11)) end end - ret = string.format("%s%s" .. fmt, ret or "", - ret and string.format(" %s ", separator) or "", info[f] or "") + ret = string.format( + "%s%s" .. fmt, + ret or "", + ret and string.format(" %s ", separator) or "", + info[f] or "" + ) end end return ret @@ -678,17 +772,28 @@ M.autocmds = function(opts) local contents = function(cb) coroutine.wrap(function() local co = coroutine.running() - cb(string.format("%s:%d:%s%s", "", 0, separator, format({ - event = "event", - pattern = "pattern", - group = "group", - code = "code", - desc = "description", - color = false, - })), function(err) - coroutine.resume(co) - if err then cb(nil) end - end) + cb( + string.format( + "%s:%d:%s%s", + "", + 0, + separator, + format({ + event = "event", + pattern = "pattern", + group = "group", + code = "code", + desc = "description", + color = false, + }) + ), + function(err) + coroutine.resume(co) + if err then + cb(nil) + end + end + ) for _, a in ipairs(autocmds) do local file, line = "", 0 if a.callback then @@ -696,16 +801,24 @@ M.autocmds = function(opts) file = info and info.source and info.source:sub(2) or "" line = info and info.linedefined or 0 end - local entry = string.format("%s:%d:%s%s", file, line, separator, format({ - event = utils.ansi_codes.blue(a.event), - pattern = utils.ansi_codes.yellow(a.pattern), - group = utils.ansi_codes.green(a.group_name and vim.trim(a.group_name) or " "), - code = a.callback and utils.ansi_codes.red(tostring(a.callback)) or a.command, - desc = a.desc, - })) + local entry = string.format( + "%s:%d:%s%s", + file, + line, + separator, + format({ + event = utils.ansi_codes.blue(a.event), + pattern = utils.ansi_codes.yellow(a.pattern), + group = utils.ansi_codes.green(a.group_name and vim.trim(a.group_name) or " "), + code = a.callback and utils.ansi_codes.red(tostring(a.callback)) or a.command, + desc = a.desc, + }) + ) cb(entry, function(err) coroutine.resume(co) - if err then cb(nil) end + if err then + cb(nil) + end end) coroutine.yield() end diff --git a/lua/fzf-lua/providers/oldfiles.lua b/lua/fzf-lua/providers/oldfiles.lua index f3e5ecb6e..fc79cdc02 100644 --- a/lua/fzf-lua/providers/oldfiles.lua +++ b/lua/fzf-lua/providers/oldfiles.lua @@ -1,14 +1,16 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local make_entry = require "fzf-lua.make_entry" +local core = require("fzf-lua.core") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local make_entry = require("fzf-lua.make_entry") local M = {} M.oldfiles = function(opts) opts = config.normalize_opts(opts, "oldfiles") - if not opts then return end + if not opts then + return + end -- cwd implies we want `cwd_only=true` if opts.cwd and opts.cwd_only == nil then @@ -20,15 +22,17 @@ M.oldfiles = function(opts) local sess_tbl = {} local sess_map = {} - local stat_fn = not opts.stat_file and function(_) return true end - or type(opts.stat_file) == "function" and opts.stat_file - or function(file) - local stat = uv.fs_stat(file) - return (not utils.path_is_directory(file, stat) - -- FIFO blocks `fs_open` indefinitely (#908) - and not utils.file_is_fifo(file, stat) - and utils.file_is_readable(file)) - end + local stat_fn = not opts.stat_file and function(_) + return true + end or type(opts.stat_file) == "function" and opts.stat_file or function(file) + local stat = uv.fs_stat(file) + return ( + not utils.path_is_directory(file, stat) + -- FIFO blocks `fs_open` indefinitely (#908) + and not utils.file_is_fifo(file, stat) + and utils.file_is_readable(file) + ) + end if opts.include_current_session then for _, buffer in ipairs(vim.split(vim.fn.execute(":buffers! t"), "\n")) do @@ -47,7 +51,9 @@ M.oldfiles = function(opts) local contents = function(cb) local function add_entry(x, co) x = make_entry.file(x, opts) - if not x then return end + if not x then + return + end cb(x, function(err) coroutine.resume(co) if err then diff --git a/lua/fzf-lua/providers/quickfix.lua b/lua/fzf-lua/providers/quickfix.lua index a100a92da..f121657ba 100644 --- a/lua/fzf-lua/providers/quickfix.lua +++ b/lua/fzf-lua/providers/quickfix.lua @@ -1,19 +1,25 @@ local uv = vim.uv or vim.loop -local core = require "fzf-lua.core" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local make_entry = require "fzf-lua.make_entry" +local core = require("fzf-lua.core") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local make_entry = require("fzf-lua.make_entry") local M = {} local quickfix_run = function(opts, cfg, locations) - if not locations then return {} end + if not locations then + return {} + end local results = {} opts = config.normalize_opts(opts, cfg) - if not opts then return end + if not opts then + return + end - if not opts.cwd then opts.cwd = uv.cwd() end + if not opts.cwd then + opts.cwd = uv.cwd() + end for _, entry in ipairs(locations) do if entry.valid == 1 or not opts.only_valid then @@ -27,7 +33,9 @@ local quickfix_run = function(opts, cfg, locations) x = make_entry.file(x, opts) if x then cb(x, function(err) - if err then return end + if err then + return + end -- close the pipe to fzf, this -- removes the loading indicator in fzf cb(nil) @@ -66,20 +74,19 @@ M.loclist = function(opts) return quickfix_run(opts, "loclist", locations) end - local qfstack_exec = function(opts, cfg, is_loclist) opts = config.normalize_opts(opts, cfg) - if not opts then return end + if not opts then + return + end opts.fn_pre_fzf = function() - opts.__history = vim.split( - vim.fn.execute(is_loclist and "lhistory" or "chistory"), "\n") + opts.__history = vim.split(vim.fn.execute(is_loclist and "lhistory" or "chistory"), "\n") end opts.fn_pre_fzf() if utils.tbl_isempty(opts.__history) or opts.__history[2] == "No entries" then - utils.info(string.format("No %s", - is_loclist and "location lists" or "quickfix lists")) + utils.info(string.format("No %s", is_loclist and "location lists" or "quickfix lists")) return end @@ -91,13 +98,17 @@ local qfstack_exec = function(opts, cfg, is_loclist) local is_current = line:match("^>") local nr, name = line:match("list (%d+) of %d+; %d+ errors%s+(.*)$") if nr and tonumber(nr) > 0 then - local entry = string.format("[%s] %s %s", - utils.ansi_codes.yellow(nr), is_current - and utils.ansi_codes.red(opts.marker) - or " ", name) + local entry = string.format( + "[%s] %s %s", + utils.ansi_codes.yellow(nr), + is_current and utils.ansi_codes.red(opts.marker) or " ", + name + ) cb(entry, function(err) coroutine.resume(co) - if err then cb(nil) end + if err then + cb(nil) + end end) coroutine.yield() end diff --git a/lua/fzf-lua/providers/tags.lua b/lua/fzf-lua/providers/tags.lua index 8d708aaf3..44e1d3136 100644 --- a/lua/fzf-lua/providers/tags.lua +++ b/lua/fzf-lua/providers/tags.lua @@ -1,15 +1,17 @@ local uv = vim.uv or vim.loop -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local libuv = require "fzf-lua.libuv" -local config = require "fzf-lua.config" -local make_entry = require "fzf-lua.make_entry" +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local libuv = require("fzf-lua.libuv") +local config = require("fzf-lua.config") +local make_entry = require("fzf-lua.make_entry") local M = {} local function get_tags_cmd(opts) -- command already set by `ctags_autogen`? - if opts.cmd then return opts.cmd end + if opts.cmd then + return opts.cmd + end local query, filter = nil, nil local bin, flags = nil, nil if vim.fn.executable("rg") == 1 then @@ -25,19 +27,21 @@ local function get_tags_cmd(opts) if opts.filename and #opts.filename > 0 then -- tags use relative paths, by now we should -- have the correct cwd from `get_ctags_cwd` - query = libuv.shellescape( - utils.rg_escape(path.relative_to(opts.filename, opts.cwd or uv.cwd()))) + query = + libuv.shellescape(utils.rg_escape(path.relative_to(opts.filename, opts.cwd or uv.cwd()))) elseif opts.search and #opts.search > 0 then filter = ([[%s -v "^!"]]):format(bin) - query = libuv.shellescape(opts.no_esc and opts.search or - utils.rg_escape(opts.search)) + query = libuv.shellescape(opts.no_esc and opts.search or utils.rg_escape(opts.search)) else query = [[-v "^!_TAG_"]] end return ("%s %s %s %s"):format( - bin, flags, query, + bin, + flags, + query, opts._ctags_file and libuv.shellescape(opts._ctags_file) or "" - ), filter + ), + filter end local get_ctags_file = function(opts) @@ -57,9 +61,13 @@ end -- search the headers of the tags file for "!TAG_PROC_CWD" local get_ctags_cwd = function(ctags_file) - if vim.fn.filereadable(ctags_file) == 0 then return end + if vim.fn.filereadable(ctags_file) == 0 then + return + end local lines = vim.fn.readfile(ctags_file, "", 10) - if utils.tbl_isempty(lines) then return end + if utils.tbl_isempty(lines) then + return + end for _, l in ipairs(lines) do local cwd = l:match("^!_TAG_PROC_CWD%s+(.*)%s+//$") if cwd then @@ -73,7 +81,9 @@ M._TAGS2CWD = {} local function tags(opts) -- make sure we have the correct 'bat' previewer for tags - if opts.previewer == "bat_native" then opts.previewer = "bat" end + if opts.previewer == "bat_native" then + opts.previewer = "bat" + end -- signal actions this is a ctag opts._ctag = true @@ -94,13 +104,16 @@ local function tags(opts) if vim.fn.executable(opts.ctags_bin) == 1 then opts.cmd = opts.cmd or opts._btags_cmd else - utils.info("Unable to locate `ctags` executable, " .. - "install `ctags` or supply its path using 'ctags_bin'") + utils.info( + "Unable to locate `ctags` executable, " + .. "install `ctags` or supply its path using 'ctags_bin'" + ) return end else - utils.info(("Tags file ('%s') does not exist. Create one with ctags -R") - :format(opts._ctags_file)) + utils.info( + ("Tags file ('%s') does not exist. Create one with ctags -R"):format(opts._ctags_file) + ) return end end @@ -154,7 +167,9 @@ local function tags(opts) opts.__ACT_TO = opts.__ACT_TO or M.grep -- live_grep requested by caller ('tags_live_grep') local cmd, filter = get_tags_cmd({ search = "dummy" }) - if not cmd then return end -- cmd only used for this test + if not cmd then + return + end -- cmd only used for this test opts.filter = (opts.filter == nil) and filter or opts.filter -- rg globs are meaningless here since we are searching a single file opts.rg_glob = false @@ -162,13 +177,13 @@ local function tags(opts) opts.formatter, opts._fmt = false, { _to = false, to = false, from = false } opts.filespec = libuv.shellescape(opts._ctags_file) if opts.multiprocess then - return require "fzf-lua.providers.grep".live_grep_mt(opts) + return require("fzf-lua.providers.grep").live_grep_mt(opts) else -- 'live_grep_st' uses different signature 'fn_transform' opts.fn_transform = function(x) return make_entry.tag(x, opts) end - return require "fzf-lua.providers.grep".live_grep_st(opts) + return require("fzf-lua.providers.grep").live_grep_st(opts) end else -- we need this for 'actions.grep_lgrep' @@ -177,7 +192,9 @@ local function tags(opts) -- Since we cannot use include and exclude in the -- same grep command, we need to use a pipe to filter local cmd, filter = get_tags_cmd(opts) - if not cmd then return end + if not cmd then + return + end opts.raw_cmd = cmd opts.filter = (opts.filter == nil) and filter or opts.filter if opts.filter and #opts.filter > 0 then @@ -185,19 +202,23 @@ local function tags(opts) end -- tags has its own formatter opts.formatter, opts._fmt = false, { _to = false, to = false, from = false } - return require "fzf-lua.providers.grep".grep(opts) + return require("fzf-lua.providers.grep").grep(opts) end end M.tags = function(opts) opts = config.normalize_opts(opts, "tags") - if not opts then return end + if not opts then + return + end return tags(opts) end M.btags = function(opts) opts = config.normalize_opts(opts, "btags") - if not opts then return end + if not opts then + return + end opts.filename = vim.api.nvim_buf_get_name(0) if #opts.filename == 0 then utils.info("'btags' is not available for unnamed buffers.") @@ -205,10 +226,8 @@ M.btags = function(opts) end -- store the autogen command in case tags file doesn't exist. -- Used as fallback to pipe the tags into fzf from stdout - opts._btags_cmd = string.format("%s %s %s", - opts.ctags_bin or "ctags", - opts.ctags_args or "-f -", - opts.filename) + opts._btags_cmd = + string.format("%s %s %s", opts.ctags_bin or "ctags", opts.ctags_args or "-f -", opts.filename) if opts.ctags_autogen then opts.cmd = opts.cmd or opts._btags_cmd end @@ -240,20 +259,26 @@ end M.live_grep = function(opts) opts = config.normalize_opts(opts, "tags") - if not opts then return end + if not opts then + return + end opts.lgrep = true return tags(opts) end M.grep_cword = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.no_esc = true opts.search = [[\b]] .. utils.rg_escape(vim.fn.expand("")) .. [[\b]] return M.grep(opts) end M.grep_cWORD = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.no_esc = true -- since we're searching a tags file also search for surrounding literals ^ $ opts.search = [[(^|\^|\s)]] .. utils.rg_escape(vim.fn.expand("")) .. [[($|\$|\s)]] @@ -261,7 +286,9 @@ M.grep_cWORD = function(opts) end M.grep_visual = function(opts) - if not opts then opts = {} end + if not opts then + opts = {} + end opts.search = utils.get_visual_selection() return M.grep(opts) end diff --git a/lua/fzf-lua/providers/tmux.lua b/lua/fzf-lua/providers/tmux.lua index 3975c90b9..e943858a3 100644 --- a/lua/fzf-lua/providers/tmux.lua +++ b/lua/fzf-lua/providers/tmux.lua @@ -1,13 +1,15 @@ -local core = require "fzf-lua.core" -local shell = require "fzf-lua.shell" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" +local core = require("fzf-lua.core") +local shell = require("fzf-lua.shell") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") local M = {} M.buffers = function(opts) opts = config.normalize_opts(opts, "tmux.buffers") - if not opts then return end + if not opts then + return + end opts.fn_transform = function(x) local buf, data = x:match([[^(.-):%s+%d+%s+bytes: "(.*)"$]]) diff --git a/lua/fzf-lua/providers/ui_select.lua b/lua/fzf-lua/providers/ui_select.lua index ba5edcc24..c1dd7a908 100644 --- a/lua/fzf-lua/providers/ui_select.lua +++ b/lua/fzf-lua/providers/ui_select.lua @@ -1,7 +1,7 @@ -local core = require "fzf-lua.core" -local utils = require "fzf-lua.utils" -local config = require "fzf-lua.config" -local actions = require "fzf-lua.actions" +local core = require("fzf-lua.core") +local utils = require("fzf-lua.utils") +local config = require("fzf-lua.config") +local actions = require("fzf-lua.actions") local M = {} @@ -47,7 +47,9 @@ M.register = function(opts, silent, opts_once) end M.accept_item = function(selected, o) - if #selected == 0 then return end + if #selected == 0 then + return + end local idx = selected and tonumber(selected[1]:match("^%s*(%d+)%.")) or nil o._on_choice(idx and o._items[idx] or nil, idx) o._on_choice_called = true @@ -79,9 +81,13 @@ M.ui_select = function(items, ui_opts, on_choice) local num_width = math.ceil(math.log10(#items)) local num_format_str = "%" .. num_width .. "d" for i, e in ipairs(items) do - table.insert(entries, - ("%s. %s"):format(utils.ansi_codes.magenta(num_format_str:format(i)), - ui_opts.format_item and ui_opts.format_item(e) or tostring(e))) + table.insert( + entries, + ("%s. %s"):format( + utils.ansi_codes.magenta(num_format_str:format(i)), + ui_opts.format_item and ui_opts.format_item(e) or tostring(e) + ) + ) end local opts = _OPTS or {} @@ -92,7 +98,7 @@ M.ui_select = function(items, ui_opts, on_choice) end opts.fzf_opts = vim.tbl_extend("keep", opts.fzf_opts or {}, { - ["--no-multi"] = true, + ["--no-multi"] = true, ["--preview-window"] = "hidden:right:0", }) @@ -106,7 +112,7 @@ M.ui_select = function(items, ui_opts, on_choice) opts._ui_select = ui_opts opts.actions = vim.tbl_deep_extend("keep", opts.actions or {}, { - ["enter"] = { fn = M.accept_item, desc = "accept-item" } + ["enter"] = { fn = M.accept_item, desc = "accept-item" }, }) opts.fn_selected = function(selected, o) @@ -137,16 +143,17 @@ M.ui_select = function(items, ui_opts, on_choice) if o.__CTX.mode == "i" then -- If called from INSERT mode we have to schedule the callback -- till **after** the mode is changed (#1572) - vim.cmd [[noautocmd lua vim.api.nvim_feedkeys('i', 'n', true)]] + vim.cmd([[noautocmd lua vim.api.nvim_feedkeys('i', 'n', true)]]) vim.api.nvim_create_autocmd("ModeChanged", { - pattern = "*:i*", once = true, callback = exec_choice + pattern = "*:i*", + once = true, + callback = exec_choice, }) else exec_choice() end end - -- ui.select is code actions -- inherit from defaults if not triggered by lsp_code_actions local opts_merge_strategy = "keep" @@ -164,15 +171,17 @@ M.ui_select = function(items, ui_opts, on_choice) local previewer = _OPTS_ONCE.previewer _OPTS_ONCE.previewer = nil -- can't copy the previewer object opts = vim.tbl_deep_extend(opts_merge_strategy, _OPTS_ONCE, opts) - opts.actions = vim.tbl_deep_extend("force", opts.actions or {}, - { ["enter"] = opts.actions.enter }) + opts.actions = + vim.tbl_deep_extend("force", opts.actions or {}, { ["enter"] = opts.actions.enter }) opts.previewer = previewer -- Callback to set the coroutine so we know if the interface -- was opened or not (e.g. when no code actions are present) opts.cb_co = (function() -- NOTE: use clojure as `_OPTS_ONCE` is otherwise nullified local opts_once_ref = _OPTS_ONCE - return function(co) opts_once_ref._co = co end + return function(co) + opts_once_ref._co = co + end end)() _OPTS_ONCE = nil end diff --git a/lua/fzf-lua/shell.lua b/lua/fzf-lua/shell.lua index 9e1193021..5658d9be0 100644 --- a/lua/fzf-lua/shell.lua +++ b/lua/fzf-lua/shell.lua @@ -1,9 +1,9 @@ -- modified version of: -- https://github.com/vijaymarupudi/nvim-fzf/blob/master/lua/fzf/actions.lua local uv = vim.uv or vim.loop -local utils = require "fzf-lua.utils" -local path = require "fzf-lua.path" -local libuv = require "fzf-lua.libuv" +local utils = require("fzf-lua.utils") +local path = require("fzf-lua.path") +local libuv = require("fzf-lua.libuv") local M = {} @@ -65,8 +65,7 @@ function M.raw_async_action(fn, fzf_field_expression, debug) pcall(function() local module = loadstring("return require'fzf-lua'")() if module then - module.__INFO = vim.tbl_deep_extend("force", - module.__INFO or {}, { selected = args[1][1] }) + module.__INFO = vim.tbl_deep_extend("force", module.__INFO or {}, { selected = args[1][1] }) end end) uv.pipe_connect(pipe, pipe_path, function(err) @@ -89,10 +88,11 @@ function M.raw_async_action(fn, fzf_field_expression, debug) -- all args after `-l` will be in `_G.args` local action_cmd = ("%s -u NONE -l %s %s %s %s"):format( libuv.shellescape(path.normalize(nvim_bin)), - libuv.shellescape(path.normalize(path.join { vim.g.fzf_lua_directory, "shell_helper.lua" })), + libuv.shellescape(path.normalize(path.join({ vim.g.fzf_lua_directory, "shell_helper.lua" }))), id, tostring(debug), - fzf_field_expression) + fzf_field_expression + ) return action_cmd, id end @@ -120,7 +120,13 @@ function M.raw_action(fn, fzf_field_expression, debug) on_complete() elseif type(ret) == "table" then if not utils.tbl_isempty(ret) then - uv.write(pipe, vim.tbl_map(function(x) return x .. "\n" end, ret), on_complete) + uv.write( + pipe, + vim.tbl_map(function(x) + return x .. "\n" + end, ret), + on_complete + ) else on_complete() end @@ -171,7 +177,9 @@ M.raw_preview_action_cmd = function(fn, fzf_field_expression, debug) return libuv.spawn(vim.tbl_extend("force", opts, { cb_finish = on_finish, cb_write = on_write, - cb_pid = function(pid) M.__pid_preview = pid end, + cb_pid = function(pid) + M.__pid_preview = pid + end, })) end, fzf_field_expression, debug) end @@ -192,7 +200,9 @@ M.reload_action_cmd = function(opts, fzf_field_expression) -- local on_finish = function(code, sig, from, pid) -- print("finish", pipe, pipe_want_close, code, sig, from, pid) local on_finish = function(_, _, _, _) - if not pipe then return end + if not pipe then + return + end pipe_want_close = true if write_cb_count == 0 then -- only close if all our uv.write calls are completed @@ -205,16 +215,24 @@ M.reload_action_cmd = function(opts, fzf_field_expression) -- pipe can be nil when using a shell command with spawn -- and typing quickly, the process will terminate assert(not co or (co and pipe and not uv.is_closing(pipe))) - if not pipe then return end + if not pipe then + return + end if not data then on_finish(nil, nil, 5) - if cb then cb(nil) end + if cb then + cb(nil) + end else write_cb_count = write_cb_count + 1 uv.write(pipe, tostring(data), function(err) write_cb_count = write_cb_count - 1 - if co then coroutine.resume(co) end - if cb then cb(err) end + if co then + coroutine.resume(co) + end + if cb then + cb(err) + end if err then -- force close on error write_cb_count = 0 @@ -249,7 +267,9 @@ M.reload_action_cmd = function(opts, fzf_field_expression) cmd = reload_contents, cb_finish = on_finish, cb_write = on_write, - cb_pid = function(pid) M.__pid_reload = pid end, + cb_pid = function(pid) + M.__pid_reload = pid + end, EOL = EOL, -- must send false, 'coroutinify' adds callback as last argument -- which will conflict with the 'fn_transform' argument @@ -287,7 +307,6 @@ M.reload_action_cmd = function(opts, fzf_field_expression) return on_write(data, cb, opts.__co) end - if type(reload_contents) == "table" then for _, l in ipairs(reload_contents) do on_write_nl_co(l) diff --git a/lua/fzf-lua/shell_helper.lua b/lua/fzf-lua/shell_helper.lua index c66c5cfd8..165151ad9 100644 --- a/lua/fzf-lua/shell_helper.lua +++ b/lua/fzf-lua/shell_helper.lua @@ -34,7 +34,9 @@ uv.listen(preview_socket, 1, function(_) if not _is_win then uv.fs_unlink(preview_socket_path) local tmpdir = vim.fn.fnamemodify(preview_socket_path, ":h") - if tmpdir and #tmpdir > 0 then uv.fs_rmdir(tmpdir) end + if tmpdir and #tmpdir > 0 then + uv.fs_rmdir(tmpdir) + end end preview_receive_socket:read_start(function(err, data) @@ -58,7 +60,10 @@ local rpc_nvim_exec_lua = function(opts) local preview_lines = vim.env.FZF_PREVIEW_LINES or vim.env.LINES local preview_cols = vim.env.FZF_PREVIEW_COLUMNS or vim.env.COLUMNS local chan_id = vim.fn.sockconnect("pipe", opts.fzf_lua_server, { rpc = true }) - vim.rpcrequest(chan_id, "nvim_exec_lua", [[ + vim.rpcrequest( + chan_id, + "nvim_exec_lua", + [[ local luaargs = {...} local function_id = luaargs[1] local preview_socket_path = luaargs[2] @@ -67,13 +72,15 @@ local rpc_nvim_exec_lua = function(opts) local fzf_columns = luaargs[5] local usr_func = require"fzf-lua.shell".get_func(function_id) return usr_func(preview_socket_path, fzf_selection, fzf_lines, fzf_columns) - ]], { - opts.fnc_id, - preview_socket_path, - opts.fzf_selection, - tonumber(preview_lines), - tonumber(preview_cols), - }) + ]], + { + opts.fnc_id, + preview_socket_path, + opts.fzf_selection, + tonumber(preview_lines), + tonumber(preview_cols), + } + ) vim.fn.chanclose(chan_id) end) diff --git a/lua/fzf-lua/spawn.lua b/lua/fzf-lua/spawn.lua index 6848c2091..7266e785b 100644 --- a/lua/fzf-lua/spawn.lua +++ b/lua/fzf-lua/spawn.lua @@ -35,5 +35,7 @@ _G._fzf_lua_is_headless = true local _, pid = require("fzf-lua.libuv").spawn_stdio(loadstring(_G.arg[1])()) -- while vim.uv.run() do end -- os.exit in spawn_stdio while uv.os_getpriority(pid) do - vim.wait(100, function() return uv.os_getpriority(pid) == nil end) + vim.wait(100, function() + return uv.os_getpriority(pid) == nil + end) end diff --git a/lua/fzf-lua/test/helpers.lua b/lua/fzf-lua/test/helpers.lua index 787dcfae5..24b644c21 100644 --- a/lua/fzf-lua/test/helpers.lua +++ b/lua/fzf-lua/test/helpers.lua @@ -11,8 +11,12 @@ local M = {} M.assert = { is = { same = MiniTest.expect.equality, - True = function(b) return MiniTest.expect.equality(b, true) end, - False = function(b) return MiniTest.expect.equality(b, false) end, + True = function(b) + return MiniTest.expect.equality(b, true) + end, + False = function(b) + return MiniTest.expect.equality(b, false) + end, }, are = { same = MiniTest.expect.equality, @@ -31,12 +35,34 @@ end local os_detect = { WIN = { name = "Windows", - fn = function() return vim.fn.has("win32") == 1 or vim.fn.has("win64") == 1 end + fn = function() + return vim.fn.has("win32") == 1 or vim.fn.has("win64") == 1 + end, + }, + MAC = { + name = "MacOS", + fn = function() + return vim.fn.has("mac") == 1 + end, + }, + LINUX = { + name = "Linux", + fn = function() + return vim.fn.has("linux") == 1 + end, + }, + STABLE = { + name = "Neovim stable", + fn = function() + return M.NVIM_VERSION() == "0.11.1" + end, + }, + NIGHTLY = { + name = "Neovim nightly", + fn = function() + return vim.fn.has("nvim-0.12") == 1 + end, }, - MAC = { name = "MacOS", fn = function() return vim.fn.has("mac") == 1 end }, - LINUX = { name = "Linux", fn = function() return vim.fn.has("linux") == 1 end }, - STABLE = { name = "Neovim stable", fn = function() return M.NVIM_VERSION() == "0.11.1" end }, - NIGHTLY = { name = "Neovim nightly", fn = function() return vim.fn.has("nvim-0.12") == 1 end }, } -- Creates M.IS_WIN(), M.IS_NOT_WIN(), M.SKIP_IF_WIN(), etc @@ -66,30 +92,28 @@ end -- Add extra expectations M.expect = vim.deepcopy(MiniTest.expect) -M.expect.match = MiniTest.new_expectation( - "string matching", - function(str, pattern) return str:find(pattern) ~= nil end, - function(str, pattern) - return string.format("Pattern: %s\nObserved string: %s", vim.inspect(pattern), str) - end -) +M.expect.match = MiniTest.new_expectation("string matching", function(str, pattern) + return str:find(pattern) ~= nil +end, function(str, pattern) + return string.format("Pattern: %s\nObserved string: %s", vim.inspect(pattern), str) +end) -M.expect.no_match = MiniTest.new_expectation( - "no string matching", - function(str, pattern) return str:find(pattern) == nil end, - function(str, pattern) - return string.format("Pattern: %s\nObserved string: %s", vim.inspect(pattern), str) - end -) +M.expect.no_match = MiniTest.new_expectation("no string matching", function(str, pattern) + return str:find(pattern) == nil +end, function(str, pattern) + return string.format("Pattern: %s\nObserved string: %s", vim.inspect(pattern), str) +end) M.make_partial_tbl = function(tbl, ref) local res = {} for k, v in pairs(ref) do - res[k] = (type(tbl[k]) == "table" and type(v) == "table") and M.make_partial_tbl(tbl[k], v) or - tbl[k] + res[k] = (type(tbl[k]) == "table" and type(v) == "table") and M.make_partial_tbl(tbl[k], v) + or tbl[k] end for i = 1, #tbl do - if ref[i] == nil then res[i] = tbl[i] end + if ref[i] == nil then + res[i] = tbl[i] + end end return res end @@ -97,12 +121,17 @@ end M.expect.equality_partial_tbl = MiniTest.new_expectation( "equality of tables only in reference fields", function(x, y) - if type(x) == "table" and type(y) == "table" then x = M.make_partial_tbl(x, y) end + if type(x) == "table" and type(y) == "table" then + x = M.make_partial_tbl(x, y) + end return vim.deep_equal(x, y) end, function(x, y) - return string.format("Left: %s\nRight: %s", vim.inspect(M.make_partial_tbl(x, y)), - vim.inspect(y)) + return string.format( + "Left: %s\nRight: %s", + vim.inspect(M.make_partial_tbl(x, y)), + vim.inspect(y) + ) end ) @@ -111,7 +140,9 @@ M.new_child_neovim = function() local child = MiniTest.new_child_neovim() local prevent_hanging = function(method) - if not child.is_blocked() then return end + if not child.is_blocked() then + return + end local msg = string.format("Can not use `child.%s` because child process is blocked.", method) error(msg) @@ -145,9 +176,11 @@ M.new_child_neovim = function() } } })) ]]) - -- using "FZF_DEFAULT_OPTS" hangs the command on the - -- child process and the loading indicator never stops - :format(M.IS_WIN() and "defaults = { pipe_cmd = true }," or "") + -- using "FZF_DEFAULT_OPTS" hangs the command on the + -- child process and the loading indicator never stops + :format( + M.IS_WIN() and "defaults = { pipe_cmd = true }," or "" + ) child.lua(lua_cmd, { config or {} }) end @@ -179,7 +212,9 @@ M.new_child_neovim = function() child.set_lines = function(arr, start, finish) prevent_hanging("set_lines") - if type(arr) == "string" then arr = vim.split(arr, "\n") end + if type(arr) == "string" then + arr = vim.split(arr, "\n") + end child.api.nvim_buf_set_lines(0, start or 0, finish or -1, false, arr) end @@ -205,9 +240,13 @@ M.new_child_neovim = function() child.set_size = function(lines, columns) prevent_hanging("set_size") - if type(lines) == "number" then child.o.lines = lines end + if type(lines) == "number" then + child.o.lines = lines + end - if type(columns) == "number" then child.o.columns = columns end + if type(columns) == "number" then + child.o.columns = columns + end end child.get_size = function() @@ -291,7 +330,9 @@ M.new_child_neovim = function() -- we don't need this if we compare inline opts.no_ruler = true local lines = str and vim.split(str, "\n") or { "" } - if #lines > 1 then lines[#lines] = nil end + if #lines > 1 then + lines[#lines] = nil + end local screen_ref = screenshot.from_lines(lines, opts) local screen_obs = child.get_screen_lines(opts) screenshot.compare(screen_ref, screen_obs, opts) @@ -314,10 +355,14 @@ M.new_child_neovim = function() end end - error(string.format("Timed out waiting for condition after %d ms\n\n%s\n\n%s", max, - tostring(child.cmd_capture("messages")), - tostring(child.get_screenshot()) - )) + error( + string.format( + "Timed out waiting for condition after %d ms\n\n%s\n\n%s", + max, + tostring(child.cmd_capture("messages")), + tostring(child.get_screenshot()) + ) + ) end --- waits until child screenshot contains text @@ -330,7 +375,9 @@ M.new_child_neovim = function() end -- Poke child's event loop to make it up to date - child.poke_eventloop = function() child.api.nvim_eval("1") end + child.poke_eventloop = function() + child.api.nvim_eval("1") + end child.sleep = function(ms) vim.uv.sleep(math.max(ms, 1)) @@ -384,7 +431,9 @@ end M.sleep = function(ms, child) vim.uv.sleep(math.max(ms, 1)) - if child ~= nil then child.poke_eventloop() end + if child ~= nil then + child.poke_eventloop() + end end return M diff --git a/lua/fzf-lua/test/previewer.lua b/lua/fzf-lua/test/previewer.lua index 37fb86356..19ff10e3b 100644 --- a/lua/fzf-lua/test/previewer.lua +++ b/lua/fzf-lua/test/previewer.lua @@ -13,7 +13,7 @@ function M:populate_preview_buf(entry_str) local fname = fzf.path.tail(entry.path) local buf = self:get_tmp_buffer() vim.api.nvim_buf_set_lines(buf, 0, -1, false, { - string.format("SELECTED FILE: %s", fname) + string.format("SELECTED FILE: %s", fname), }) self:set_preview_buf(buf) self.win:update_preview_title(fname) diff --git a/lua/fzf-lua/test/screenshot.lua b/lua/fzf-lua/test/screenshot.lua index 50c6e33e3..a73e855b3 100644 --- a/lua/fzf-lua/test/screenshot.lua +++ b/lua/fzf-lua/test/screenshot.lua @@ -64,7 +64,9 @@ end function M.from_lines(text_lines, opts) opts = opts or {} if opts and opts.normalize_paths then - text_lines = vim.tbl_map(function(x) return x:gsub([[\]], [[/]]) end, text_lines) + text_lines = vim.tbl_map(function(x) + return x:gsub([[\]], [[/]]) + end, text_lines) end local f = function(x) return string_to_chars(x) @@ -76,16 +78,20 @@ end ---@param opts test.ScreenOpts? function M.fromChildBufLines(child, buf, opts) opts = opts or {} - if opts and opts.redraw then child.cmd("redraw") end - local lines = child.api.nvim_buf_get_lines(buf or 0, opts.start_line and 0, opts.end_line + 1 or -1, - true) + if opts and opts.redraw then + child.cmd("redraw") + end + local lines = + child.api.nvim_buf_get_lines(buf or 0, opts.start_line and 0, opts.end_line + 1 or -1, true) return M.from_lines(lines, opts) end ---@param opts test.ScreenOpts? function M.fromChildScreen(child, opts) opts = opts or {} - if opts and opts.redraw then child.cmd("redraw") end + if opts and opts.redraw then + child.cmd("redraw") + end local lines = child.lua(([[ local lines = {} for i = %s, %s do @@ -105,17 +111,18 @@ local screenshot_read = function(path) local lines = vim.fn.readfile(path) local text_lines = vim.list_slice(lines, 2, #lines) - local f = function(x) return H.string_to_chars(x:gsub("^%d+|", "")) end + local f = function(x) + return H.string_to_chars(x:gsub("^%d+|", "")) + end return screenshot_new({ text = vim.tbl_map(f, text_lines) }, opts) end - -- modified version (no attr) local screenshot_compare = function(screen_ref, screen_obs, opts) local compare = function(x, y, desc) if x ~= y then return false, - ("Different %s. Reference: %s. Observed: %s."):format(desc, vim.inspect(x), vim.inspect(y)) + ("Different %s. Reference: %s. Observed: %s."):format(desc, vim.inspect(x), vim.inspect(y)) end return true, "" end @@ -156,10 +163,15 @@ local screenshot_compare = function(screen_ref, screen_obs, opts) end M.reference_screenshot = function(screenshot, path, opts) - if screenshot == nil then return true end + if screenshot == nil then + return true + end - opts = vim.tbl_extend("force", - { force = false, ignore_text = {}, directory = "tests/screenshots" }, opts or {}) + opts = vim.tbl_extend( + "force", + { force = false, ignore_text = {}, directory = "tests/screenshots" }, + opts or {} + ) H.cache.n_screenshots = H.cache.n_screenshots + 1 @@ -168,9 +180,13 @@ M.reference_screenshot = function(screenshot, path, opts) -- forbidden characters with '-' (with some useful exception) local linux_forbidden = [[/]] local windows_forbidden = [[<>:"/\|?*]] - local pattern = string.format("[%%c%%s%s%s]", vim.pesc(linux_forbidden), - vim.pesc(windows_forbidden)) - local replacements = setmetatable({ ['"'] = "'" }, { __index = function() return "-" end }) + local pattern = + string.format("[%%c%%s%s%s]", vim.pesc(linux_forbidden), vim.pesc(windows_forbidden)) + local replacements = setmetatable({ ['"'] = "'" }, { + __index = function() + return "-" + end, + }) local name = H.case_to_stringid(MiniTest.current.case):gsub(pattern, replacements) -- Don't end with whitespace or dot (forbidden on Windows) @@ -180,7 +196,9 @@ M.reference_screenshot = function(screenshot, path, opts) path = vim.fs.normalize(opts.directory):gsub("/$", "") .. "/" .. name -- Deal with multiple screenshots - if H.cache.n_screenshots > 1 then path = path .. string.format("-%03d", H.cache.n_screenshots) end + if H.cache.n_screenshots > 1 then + path = path .. string.format("-%03d", H.cache.n_screenshots) + end end -- If there is no readable screenshot file, create it. Pass with note. @@ -198,11 +216,17 @@ M.reference_screenshot = function(screenshot, path, opts) -- Compare local are_same, cause = screenshot_compare(reference, screenshot, opts) - if are_same then return true end + if are_same then + return true + end local subject = "screenshot equality to reference at " .. vim.inspect(path) - local context = string.format("%s\nReference:\n%s\n\nObserved:\n%s", cause, tostring(reference), - tostring(screenshot)) + local context = string.format( + "%s\nReference:\n%s\n\nObserved:\n%s", + cause, + tostring(reference), + tostring(screenshot) + ) H.error_expect(subject, context) end @@ -223,12 +247,17 @@ M.compare = function(reference, screenshot, opts) ruler = prefix .. ("---------|"):rep(math.ceil(0.1 * n_cols)):sub(1, n_cols) .. "\n" end - if are_same then return true end + if are_same then + return true + end local subject = "screenshot equality to reference at " .. vim.inspect(path) - local context = string.format("%s\nReference:\n%s\n\nObserved:\n%s", cause, + local context = string.format( + "%s\nReference:\n%s\n\nObserved:\n%s", + cause, ruler .. tostring(reference), - ruler .. tostring(screenshot)) + ruler .. tostring(screenshot) + ) H.error_expect(subject, context) end diff --git a/lua/fzf-lua/utils.lua b/lua/fzf-lua/utils.lua index 1bc1bfef1..05091f7df 100644 --- a/lua/fzf-lua/utils.lua +++ b/lua/fzf-lua/utils.lua @@ -17,15 +17,23 @@ M.__IS_WINDOWS = vim.fn.has("win32") == 1 or vim.fn.has("win64") == 1 -- `:help shellslash` (for more info see #1055) M.__WIN_HAS_SHELLSLASH = M.__IS_WINDOWS and vim.fn.exists("+shellslash") -function M.__FILE__() return debug.getinfo(2, "S").source end +function M.__FILE__() + return debug.getinfo(2, "S").source +end -function M.__LINE__() return debug.getinfo(2, "l").currentline end +function M.__LINE__() + return debug.getinfo(2, "l").currentline +end -function M.__FNC__() return debug.getinfo(2, "n").name end +function M.__FNC__() + return debug.getinfo(2, "n").name +end -- current function ref, since `M.__FNCREF__` is itself a function -- we need to go backwards once in stack (i.e. "2") -function M.__FNCREF__() return debug.getinfo(2, "f").func end +function M.__FNCREF__() + return debug.getinfo(2, "f").func +end -- calling function ref, go backwards in stack twice first -- out of `utils.__FNCREF2__`, second out of calling function @@ -65,10 +73,9 @@ M.nbsp = [[\xe2\x80\x82]] -- "\u{2002}" if _VERSION and type(_VERSION) == "string" then local ver = tonumber(_VERSION:match("%d+.%d+")) if ver < 5.2 then - M.nbsp = M.nbsp:gsub("\\x(%x%x)", - function(x) - return string.char(tonumber(x, 16)) - end) + M.nbsp = M.nbsp:gsub("\\x(%x%x)", function(x) + return string.char(tonumber(x, 16)) + end) end end @@ -84,12 +91,18 @@ end -- Style 1: %VAR% -- Style 2: !VAR! M._if_win_normalize_vars = function(cmd, style) - if not M.__IS_WINDOWS then return cmd end + if not M.__IS_WINDOWS then + return cmd + end local expander = style == 2 and "!" or "%" - cmd = cmd:gsub("%$[^%s]+", function(x) return expander .. x:sub(2) .. expander end) + cmd = cmd:gsub("%$[^%s]+", function(x) + return expander .. x:sub(2) .. expander + end) if style == 2 then -- also sub %VAR% for !VAR! - cmd = cmd:gsub("%%[^%s]+%%", function(x) return "!" .. x:sub(2, #x - 1) .. "!" end) + cmd = cmd:gsub("%%[^%s]+%%", function(x) + return "!" .. x:sub(2, #x - 1) .. "!" + end) end return cmd end @@ -103,10 +116,13 @@ end M.shell_setenv_str = function(vars) local ret = {} for k, v in pairs(vars or {}) do - table.insert(ret, M._if_win( - string.format([[set %s=%s&&]], tostring(k), tostring(v)), - string.format("%s=%s;", tostring(k), tostring(v)) - )) + table.insert( + ret, + M._if_win( + string.format([[set %s=%s&&]], tostring(k), tostring(v)), + string.format("%s=%s;", tostring(k), tostring(v)) + ) + ) end return ret end @@ -126,10 +142,16 @@ M.strsplit = function(inputstr, sep) end function M.round(num, limit) - if not num then return nil end - if not limit then limit = 0.5 end + if not num then + return nil + end + if not limit then + limit = 0.5 + end local fraction = num - math.floor(num) - if fraction > limit then return math.ceil(num) end + if fraction > limit then + return math.ceil(num) + end return math.floor(num) end @@ -166,15 +188,21 @@ end ---@param str string ---@return string function M.rg_escape(str) - if not str then return str end + if not str then + return str + end -- [(~'"\/$?'`*&&||;[]<>)] -- escape "\~$?*|[()^-." - local ret = str:gsub("[\\~$?*|{\\[()^%-%.%+]", function(x) - return "\\" .. x - end) - -- Escape newline (#1203) at the end so we - -- don't end up escaping the backslash twice - :gsub("\n", "\\n") + local ret = str + :gsub("[\\~$?*|{\\[()^%-%.%+]", function(x) + return "\\" .. x + end) + -- Escape newline (#1203) at the end so we + -- don't end up escaping the backslash twice + :gsub( + "\n", + "\\n" + ) return ret end @@ -187,18 +215,27 @@ function M.regex_to_magic(str) end function M.ctag_to_magic(str) - return [[\v]] .. str:gsub("[=&@<>{%(%)%.%[]", function(x) return [[\]] .. x end) + return [[\v]] .. str:gsub("[=&@<>{%(%)%.%[]", function(x) + return [[\]] .. x + end) end function M.sk_escape(str) - if not str then return str end - return str:gsub('["`]', function(x) - return "\\" .. x - end):gsub([[\\]], [[\\\\]]):gsub([[\%$]], [[\\\$]]) + if not str then + return str + end + return str + :gsub('["`]', function(x) + return "\\" .. x + end) + :gsub([[\\]], [[\\\\]]) + :gsub([[\%$]], [[\\\$]]) end function M.lua_escape(str) - if not str then return str end + if not str then + return str + end return str:gsub("[%%]", function(x) return "%" .. x end) @@ -208,13 +245,17 @@ end function M.lua_regex_escape(str) -- escape all lua special chars -- ( ) % . + - * [ ? ^ $ - if not str then return nil end + if not str then + return nil + end -- gsub returns a tuple, return the string only or unexpected happens (#1257) return (str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1")) end function M.glob_escape(str) - if not str then return str end + if not str then + return str + end return str:gsub("[%{}[%]]", function(x) return [[\]] .. x end) @@ -242,15 +283,14 @@ end -- wrong result for some lua files ('charset=binary')? M.file_is_binary = function(filepath) filepath = M.pcall_expand(filepath) - if vim.fn.executable("file") ~= 1 or - not uv.fs_stat(filepath) then + if vim.fn.executable("file") ~= 1 or not uv.fs_stat(filepath) then return false end local out = M.io_system({ "file", "--dereference", "--mime", filepath }) return out:match("charset=binary") ~= nil end -local S_IFMT = 0xF000 -- filetype mask +local S_IFMT = 0xF000 -- filetype mask local S_IFIFO = 0x1000 -- fifo local S_IFDIR = 0x4000 -- directory @@ -285,8 +325,7 @@ end M.perl_file_is_binary = function(filepath) filepath = M.pcall_expand(filepath) - if vim.fn.executable("perl") ~= 1 or - not uv.fs_stat(filepath) then + if vim.fn.executable("perl") ~= 1 or not uv.fs_stat(filepath) then return false end -- can also use '-T' to test for text files @@ -297,9 +336,13 @@ end M.read_file = function(filepath) local fd = uv.fs_open(filepath, "r", 438) - if fd == nil then return "" end + if fd == nil then + return "" + end local stat = assert(uv.fs_fstat(fd)) - if stat.type ~= "file" then return "" end + if stat.type ~= "file" then + return "" + end local data = assert(uv.fs_read(fd, stat.size, 0)) assert(uv.fs_close(fd)) return data @@ -317,7 +360,9 @@ M.read_file_async = function(filepath, callback) end uv.fs_fstat(fd, function(err_fstat, stat) assert(not err_fstat, err_fstat) - if stat.type ~= "file" then return callback("") end + if stat.type ~= "file" then + return callback("") + end uv.fs_read(fd, stat.size, 0, function(err_read, data) assert(not err_read, err_read) uv.fs_close(fd, function(err_close) @@ -342,7 +387,9 @@ function M.deepcopy(t) end function M.tbl_deep_clone(t) - if not t then return end + if not t then + return + end local clone = {} for k, v in pairs(t) do @@ -399,7 +446,9 @@ end function M.tbl_count(T) local count = 0 - for _ in pairs(T) do count = count + 1 end + for _ in pairs(T) do + count = count + 1 + end return count end @@ -440,8 +489,12 @@ end -- e.g. `map_get(m, "key.sub1.sub2")` -- `map_get(m, { "key", "sub1", "sub2" })` function M.map_get(m, k) - if not m then return end - if not k then return m end + if not m then + return + end + if not k then + return m + end local keys = type(k) == "table" and k or M.strsplit(k, "%.") local iter = m for i = 1, #keys do @@ -484,8 +537,8 @@ function M.map_tolower(m, exclude_patterns) -- We use "exclude_patterns" to filter "alt-{a|A}" -- as it's a valid and different fzf bind exclude_patterns = type(exclude_patterns) == "table" and exclude_patterns - or type(exclude_patterns) == "string" and { exclude_patterns } - or {} + or type(exclude_patterns) == "string" and { exclude_patterns } + or {} if not m then return end @@ -496,7 +549,9 @@ function M.map_tolower(m, exclude_patterns) return k end for _, p in ipairs(exclude_patterns) do - if k:match(p) then return k end + if k:match(p) then + return k + end end return k:lower() end)() @@ -515,7 +570,9 @@ end ---@param m table? ---@return table? function M.map_flatten(m, prefix) - if M.tbl_isempty(m) then return {} end + if M.tbl_isempty(m) then + return {} + end local ret = {} prefix = prefix and string.format("%s.", prefix) or "" for k, v in pairs(m) do @@ -533,7 +590,9 @@ end local function hex2rgb(hexcol) local r, g, b = hexcol:match("#(%x%x)(%x%x)(%x%x)") - if not r or not g or not b then return end + if not r or not g or not b then + return + end r, g, b = tonumber(r, 16), tonumber(g, 16), tonumber(b, 16) return r, g, b end @@ -590,26 +649,30 @@ M.ansi_escseq = { -- the "\x1b" esc sequence causes issues -- with older Lua versions -- clear = "\x1b[0m", - clear = "", - bold = "", - italic = "", + clear = "", + bold = "", + italic = "", underline = "", - black = "", - red = "", - green = "", - yellow = "", - blue = "", - magenta = "", - cyan = "", - white = "", - grey = "", + black = "", + red = "", + green = "", + yellow = "", + blue = "", + magenta = "", + cyan = "", + white = "", + grey = "", dark_grey = "", } M.cache_ansi_escseq = function(name, escseq) M.ansi_codes[name] = function(string) - if string == nil or #string == 0 then return "" end - if not escseq or #escseq == 0 then return string end + if string == nil or #string == 0 then + return "" + end + if not escseq or #escseq == 0 then + return string + end return escseq .. string .. M.ansi_escseq.clear end end @@ -637,13 +700,15 @@ end local function synIDattr(hl, w, mode) -- Although help specifies invalid mode returns the active hlgroups -- when sending `nil` for mode the return value for "fg" is also nil - return mode == "cterm" or mode == "gui" - and vim.fn.synIDattr(vim.fn.synIDtrans(vim.fn.hlID(hl)), w, mode) - or vim.fn.synIDattr(vim.fn.synIDtrans(vim.fn.hlID(hl)), w) + return mode == "cterm" + or mode == "gui" and vim.fn.synIDattr(vim.fn.synIDtrans(vim.fn.hlID(hl)), w, mode) + or vim.fn.synIDattr(vim.fn.synIDtrans(vim.fn.hlID(hl)), w) end function M.hexcol_from_hl(hlgroup, what, mode) - if not hlgroup or not what then return end + if not hlgroup or not what then + return + end local hexcol = synIDattr(hlgroup, what, mode) -- Without termguicolors hexcol returns `{ctermfg|ctermbg}` which is -- a simple number representing the term ANSI color (e.g. 1-15, etc) @@ -687,13 +752,13 @@ function M.ansi_from_hl(hl, s) -- Set foreground color as RGB: 'ESC[38;2;{r};{g};{b}m' -- Set background color as RGB: 'ESC[48;2;{r};{g};{b}m' local what = { - ["fg"] = { rgb = true, code = 38 }, - ["bg"] = { rgb = true, code = 48 }, - ["bold"] = { code = 1 }, - ["italic"] = { code = 3 }, - ["underline"] = { code = 4 }, - ["inverse"] = { code = 7 }, - ["reverse"] = { code = 7 }, + ["fg"] = { rgb = true, code = 38 }, + ["bg"] = { rgb = true, code = 48 }, + ["bold"] = { code = 1 }, + ["italic"] = { code = 3 }, + ["underline"] = { code = 4 }, + ["inverse"] = { code = 7 }, + ["reverse"] = { code = 7 }, ["strikethrough"] = { code = 9 }, } -- List of ansi sequences to apply @@ -732,7 +797,9 @@ function M.has_ansi_coloring(str) end function M.strip_ansi_coloring(str) - if not str then return str end + if not str then + return str + end -- remove escape sequences of the following formats: -- 1. ^[[34m -- 2. ^[[0;34m @@ -750,14 +817,14 @@ end function M.mode_is_visual() local visual_modes = { - v = true, - vs = true, - V = true, - Vs = true, + v = true, + vs = true, + V = true, + Vs = true, nov = true, noV = true, niV = true, - Rv = true, + Rv = true, Rvc = true, Rvx = true, } @@ -789,18 +856,25 @@ function M.get_visual_selection() _, cerow, cecol, _ = unpack(vim.fn.getpos("'>")) end -- swap vars if needed - if cerow < csrow then csrow, cerow = cerow, csrow end - if cecol < cscol then cscol, cecol = cecol, cscol end + if cerow < csrow then + csrow, cerow = cerow, csrow + end + if cecol < cscol then + cscol, cecol = cecol, cscol + end local lines = vim.fn.getline(csrow, cerow) -- local n = cerow-csrow+1 local n = #lines - if n <= 0 then return "" end + if n <= 0 then + return "" + end lines[n] = string.sub(lines[n], 1, cecol) lines[1] = string.sub(lines[1], cscol) - return table.concat(lines, "\n"), { - start = { line = csrow, char = cscol }, - ["end"] = { line = cerow, char = cecol }, - } + return table.concat(lines, "\n"), + { + start = { line = csrow, char = cscol }, + ["end"] = { line = cerow, char = cecol }, + } end function M.fzf_exit() @@ -842,8 +916,9 @@ function M.reset_info() end function M.setup_highlights(override) - pcall(loadstring(string.format( - "require'fzf-lua'.setup_highlights(%s)", override and "true" or ""))) + pcall( + loadstring(string.format("require'fzf-lua'.setup_highlights(%s)", override and "true" or "")) + ) end ---@param fname string @@ -875,23 +950,25 @@ function M.load_profiles(profiles, silent) local ret = {} local path = require("fzf-lua").path profiles = type(profiles) == "table" and profiles - or type(profiles) == "string" and { profiles } - or {} + or type(profiles) == "string" and { profiles } + or {} -- If the use specified only the "hide" profile, inherit the defaults if #profiles == 1 and profiles[1] == "hide" then table.insert(profiles, 1, "default") end for _, profile in ipairs(profiles) do -- backward compat, renamed "borderless_full" > "borderless-full" - if profile == "borderless_full" then profile = "borderless-full" end + if profile == "borderless_full" then + profile = "borderless-full" + end local fname = path.join({ vim.g.fzf_lua_directory, "profiles", profile .. ".lua" }) local profile_opts = M.load_profile_fname(fname, nil, silent) if type(profile_opts) == "table" then if profile_opts[1] then -- profile requires loading base profile(s) -- silent = 1, only warn if failed to load - profile_opts = vim.tbl_deep_extend("keep", - profile_opts, M.load_profiles(profile_opts[1], 1)) + profile_opts = + vim.tbl_deep_extend("keep", profile_opts, M.load_profiles(profile_opts[1], 1)) end if type(profile_opts.fn_load) == "function" then profile_opts.fn_load() @@ -904,17 +981,17 @@ function M.load_profiles(profiles, silent) end function M.send_ctrl_c() - vim.api.nvim_feedkeys( - vim.api.nvim_replace_termcodes("", true, false, true), "n", true) + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", true, false, true), "n", true) end function M.feed_keys_termcodes(key) - vim.api.nvim_feedkeys( - vim.api.nvim_replace_termcodes(key, true, false, true), "n", true) + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, false, true), "n", true) end function M.is_term_bufname(bufname) - if bufname and bufname:match("term://") then return true end + if bufname and bufname:match("term://") then + return true + end return false end @@ -938,8 +1015,12 @@ function M.buffer_is_dirty(bufnr, warn, only_if_last_buffer) return false end if warn then - M.warn(("buffer %d:%s has unsaved changes"):format(bufnr, - info.name and #info.name > 0 and info.name or "")) + M.warn( + ("buffer %d:%s has unsaved changes"):format( + bufnr, + info.name and #info.name > 0 and info.name or "" + ) + ) end return true end @@ -954,8 +1035,8 @@ function M.save_dialog(bufnr) M.warn(string.format("buffer %d has unsaved changes", bufnr)) return false end - local res = vim.fn.confirm(string.format([[Save changes to "%s"?]], info.name), - "&Yes\n&No\n&Cancel") + local res = + vim.fn.confirm(string.format([[Save changes to "%s"?]], info.name), "&Yes\n&No\n&Cancel") if res == 0 or res == 3 then -- user cancelled return false @@ -987,9 +1068,12 @@ end ---@return 1|2|false function M.buf_is_qf(bufnr, bufinfo) bufinfo = bufinfo or (vim.api.nvim_buf_is_valid(bufnr) and M.getbufinfo(bufnr)) - if bufinfo and bufinfo.variables and - bufinfo.variables.current_syntax == "qf" and - not M.tbl_isempty(bufinfo.windows) then + if + bufinfo + and bufinfo.variables + and bufinfo.variables.current_syntax == "qf" + and not M.tbl_isempty(bufinfo.windows) + then return M.win_is_qf(bufinfo.windows[1]) end return false @@ -1028,7 +1112,9 @@ end ---@return string? function M.nvim_buf_get_name(bufnr, bufinfo) assert(not vim.in_fast_event()) - if not vim.api.nvim_buf_is_valid(bufnr) then return end + if not vim.api.nvim_buf_is_valid(bufnr) then + return + end if bufinfo and bufinfo.name and #bufinfo.name > 0 then return bufinfo.name end @@ -1056,7 +1142,9 @@ end function M.zz() -- skip for terminal buffers - if M.is_term_buffer() then return end + if M.is_term_buffer() then + return + end local lnum1 = vim.api.nvim_win_get_cursor(0)[1] local lcount = vim.api.nvim_buf_line_count(0) local zb = "keepj norm! %dzb" @@ -1104,12 +1192,16 @@ end -- Set buffer for window without an autocmd function M.win_set_buf_noautocmd(win, buf) - return M.eventignore(function() return vim.api.nvim_win_set_buf(win, buf) end) + return M.eventignore(function() + return vim.api.nvim_win_set_buf(win, buf) + end) end -- Open a window without triggering an autocmd function M.nvim_open_win(bufnr, enter, config) - return M.eventignore(function() return vim.api.nvim_open_win(bufnr, enter, config) end) + return M.eventignore(function() + return vim.api.nvim_open_win(bufnr, enter, config) + end) end function M.nvim_open_win0(bufnr, enter, config) @@ -1124,13 +1216,17 @@ end -- Close a window without triggering an autocmd function M.nvim_win_close(win, opts) - return M.eventignore(function() return vim.api.nvim_win_close(win, opts) end) + return M.eventignore(function() + return vim.api.nvim_win_close(win, opts) + end) end -- Close a buffer without triggering an autocmd function M.nvim_buf_delete(bufnr, opts) return M.eventignore(function() - if not vim.api.nvim_buf_is_valid(bufnr) then return end + if not vim.api.nvim_buf_is_valid(bufnr) then + return + end return vim.api.nvim_buf_delete(bufnr, opts) end) end @@ -1159,8 +1255,12 @@ function M.upvfind(func, upval_name) local i = 1 while true do local name, value = debug.getupvalue(func, i) - if not name then break end - if name == upval_name then return value end + if not name then + break + end + if name == upval_name then + return value + end i = i + 1 end return nil @@ -1191,7 +1291,7 @@ function M.io_systemlist(cmd) if vim.system ~= nil then -- nvim 0.10+ local proc = vim.system(cmd):wait() local output = (type(proc.stderr) == "string" and proc.stderr or "") - .. (type(proc.stdout) == "string" and proc.stdout or "") + .. (type(proc.stdout) == "string" and proc.stdout or "") return vim.split(output, "\n", { trimempty = true }), proc.code else return vim.fn.systemlist(cmd), vim.v.shell_error @@ -1205,7 +1305,7 @@ function M.io_system(cmd) if vim.system ~= nil then -- nvim 0.10+ local proc = vim.system(cmd):wait() local output = (type(proc.stderr) == "string" and proc.stderr or "") - .. (type(proc.stdout) == "string" and proc.stdout or "") + .. (type(proc.stdout) == "string" and proc.stdout or "") return output, proc.code else return vim.fn.system(cmd), vim.v.shell_error @@ -1221,10 +1321,9 @@ function M.input(prompt, default) -- causes the return value to appear as cancellation -- if vim.ui then if false then - ok, _ = pcall(vim.ui.input, { prompt = prompt, default = default }, - function(input) - res = input - end) + ok, _ = pcall(vim.ui.input, { prompt = prompt, default = default }, function(input) + res = input + end) else ok, res = pcall(vim.fn.input, { prompt = prompt, default = default, cancelreturn = 3 }) if res == 3 then @@ -1240,7 +1339,7 @@ function M.fzf_bind_to_neovim(key) ["ctrl"] = "C", ["shift"] = "S", } - key = key:lower() + key = key:lower() for k, v in pairs(conv_map) do key = key:gsub(k, v) end @@ -1254,7 +1353,7 @@ function M.neovim_bind_to_fzf(key) ["s"] = "shift", } - key = key:lower():gsub("[<>]", "") + key = key:lower():gsub("[<>]", "") for k, v in pairs(conv_map) do key = key:gsub(k .. "%-", v .. "-") end @@ -1262,7 +1361,9 @@ function M.neovim_bind_to_fzf(key) end function M.parse_verstr(str) - if type(str) ~= "string" then return end + if type(str) ~= "string" then + return + end local major, minor, patch = str:match("(%d+).(%d+)%.?(.*)") -- Fzf on HEAD edge case major = tonumber(major) or str:match("HEAD") and 100 or nil @@ -1270,7 +1371,9 @@ function M.parse_verstr(str) end function M.ver2str(v) - if type(v) ~= "table" or not v[1] then return end + if type(v) ~= "table" or not v[1] then + return + end return string.format("%d.%d.%d", tonumber(v[1]) or 0, tonumber(v[2]) or 0, tonumber(v[3]) or 0) end @@ -1280,21 +1383,32 @@ function M.has(opts, ...) if what == "fzf" or what == "sk" then local has_ver = select(2, ...) if not has_ver then - if what == "sk" and opts.__SK_VERSION then return true end - if what == "fzf" and opts.__FZF_VERSION then return true end + if what == "sk" and opts.__SK_VERSION then + return true + end + if what == "fzf" and opts.__FZF_VERSION then + return true + end else local curr_ver - if what == "sk" then curr_ver = opts.__SK_VERSION end - if what == "fzf" then curr_ver = opts.__FZF_VERSION end - if type(has_ver) == "string" then has_ver = M.parse_verstr(has_ver) end + if what == "sk" then + curr_ver = opts.__SK_VERSION + end + if what == "fzf" then + curr_ver = opts.__FZF_VERSION + end + if type(has_ver) == "string" then + has_ver = M.parse_verstr(has_ver) + end if type(has_ver) == "table" and type(curr_ver) == "table" then has_ver[2] = tonumber(has_ver[2]) or 0 has_ver[3] = tonumber(has_ver[3]) or 0 curr_ver[2] = tonumber(curr_ver[2]) or 0 curr_ver[3] = tonumber(curr_ver[3]) or 0 - if curr_ver[1] > has_ver[1] - or curr_ver[1] == has_ver[1] and curr_ver[2] > has_ver[2] - or curr_ver[1] == has_ver[1] and curr_ver[2] == has_ver[2] and curr_ver[3] >= has_ver[3] + if + curr_ver[1] > has_ver[1] + or curr_ver[1] == has_ver[1] and curr_ver[2] > has_ver[2] + or curr_ver[1] == has_ver[1] and curr_ver[2] == has_ver[2] and curr_ver[3] >= has_ver[3] then return true end @@ -1345,7 +1459,9 @@ function M.create_user_command_callback(provider, arg, altmap) local function fzflua_opts(o) local ret = {} -- fzf.vim's bang version of the commands opens fullscreen - if o.bang then ret.winopts = { fullscreen = true } end + if o.bang then + ret.winopts = { fullscreen = true } + end return ret end return function(o) @@ -1377,7 +1493,9 @@ end -- setmetatable wrapper, also enable `__gc` function M.setmetatable__gc(t, mt) local prox = newproxy(true) - getmetatable(prox).__gc = function() mt.__gc(t) end + getmetatable(prox).__gc = function() + mt.__gc(t) + end t[prox] = true return setmetatable(t, mt) end @@ -1399,8 +1517,11 @@ end ---@return boolean function M.jump_to_location(location, offset_encoding, reuse_win) if M.__HAS_NVIM_011 then - return vim.lsp.util.show_document(location, offset_encoding, - { reuse_win = reuse_win, focus = true }) + return vim.lsp.util.show_document( + location, + offset_encoding, + { reuse_win = reuse_win, focus = true } + ) else ---@diagnostic disable-next-line: deprecated return vim.lsp.util.jump_to_location(location, offset_encoding, reuse_win) @@ -1413,8 +1534,9 @@ function M.termopen(cmd, opts) if M.__HAS_NVIM_011 and M._JOBSTART_HAS_TERM == nil then local ok, err = pcall(vim.fn.jobstart, "", { term = 1 }) M._JOBSTART_HAS_TERM = not ok - and err:match [[Vim:E475: Invalid argument: 'term' must be Boolean]] - and true or false + and err:match([[Vim:E475: Invalid argument: 'term' must be Boolean]]) + and true + or false end if M.__HAS_NVIM_011 and M._JOBSTART_HAS_TERM then opts = opts or {} @@ -1433,7 +1555,9 @@ function M.toggle_cmd_flag(cmd, flag, enabled, append) end -- flag must be preceded by whitespace - if not flag:match("^%s") then flag = " " .. flag end + if not flag:match("^%s") then + flag = " " .. flag + end -- auto-detect toggle when nil if enabled == nil then @@ -1463,9 +1587,15 @@ function M.lsp_get_clients(opts) local clients = get(opts) return vim.tbl_map(function(client) return setmetatable({ - supports_method = function(_, ...) return client.supports_method(...) end, - request = function(_, ...) return client.request(...) end, - request_sync = function(_, ...) return client.request_sync(...) end, + supports_method = function(_, ...) + return client.supports_method(...) + end, + request = function(_, ...) + return client.request(...) + end, + request_sync = function(_, ...) + return client.request_sync(...) + end, }, { __index = client }) end, clients) end diff --git a/lua/fzf-lua/win.lua b/lua/fzf-lua/win.lua index d51eb3cbf..619560bca 100644 --- a/lua/fzf-lua/win.lua +++ b/lua/fzf-lua/win.lua @@ -1,8 +1,8 @@ -local path = require "fzf-lua.path" -local utils = require "fzf-lua.utils" -local libuv = require "fzf-lua.libuv" -local config = require "fzf-lua.config" -local actions = require "fzf-lua.actions" +local path = require("fzf-lua.path") +local utils = require("fzf-lua.utils") +local libuv = require("fzf-lua.libuv") +local config = require("fzf-lua.config") +local actions = require("fzf-lua.actions") local api = vim.api local fn = vim.fn @@ -13,7 +13,9 @@ local TSInjector = {} TSInjector.cache = {} function TSInjector.setup() - if TSInjector._setup then return true end + if TSInjector._setup then + return true + end TSInjector._setup = true TSInjector._ns = TSInjector._ns or vim.api.nvim_create_namespace("fzf-lua.win.highlighter") @@ -43,14 +45,18 @@ function TSInjector.setup() end function TSInjector.deregister() - if not TSInjector._ns then return end + if not TSInjector._ns then + return + end vim.api.nvim_set_decoration_provider(TSInjector._ns, { on_win = nil, on_line = nil }) TSInjector._setup = nil end function TSInjector.clear_cache(buf) -- If called from fzf-tmux buf will be `nil` (#1556) - if not buf then return end + if not buf then + return + end TSInjector.cache[buf] = nil -- If called from `FzfWin.hide` cache will not be empty assert(utils.tbl_isempty(TSInjector.cache)) @@ -58,7 +64,9 @@ end ---@param buf integer function TSInjector.attach(buf, regions) - if not TSInjector.setup() then return end + if not TSInjector.setup() then + return + end TSInjector.cache[buf] = TSInjector.cache[buf] or {} for lang, _ in pairs(TSInjector.cache[buf]) do @@ -75,7 +83,9 @@ end function TSInjector._attach_lang(buf, lang, regions) if not TSInjector.cache[buf][lang] then local ok, parser = pcall(vim.treesitter.languagetree.new, buf, lang) - if not ok then return end + if not ok then + return + end TSInjector.cache[buf][lang] = { parser = parser, highlighter = vim.treesitter.highlighter.new(parser), @@ -83,7 +93,9 @@ function TSInjector._attach_lang(buf, lang, regions) end local parser = TSInjector.cache[buf][lang].parser - if not parser then return end + if not parser then + return + end TSInjector.cache[buf][lang].enabled = true ---@diagnostic disable-next-line: invisible @@ -103,32 +115,34 @@ function FzfWin.__SELF() end local _preview_keymaps = { - ["toggle-preview"] = { module = "win", fnc = "toggle_preview()" }, - ["toggle-preview-wrap"] = { module = "win", fnc = "toggle_preview_wrap()" }, - ["toggle-preview-cw"] = { module = "win", fnc = "toggle_preview_cw(1)" }, - ["toggle-preview-ccw"] = { module = "win", fnc = "toggle_preview_cw(-1)" }, - ["toggle-preview-ts-ctx"] = { module = "win", fnc = "toggle_preview_ts_ctx()" }, - ["preview-ts-ctx-inc"] = { module = "win", fnc = "preview_ts_ctx_inc_dec(1)" }, - ["preview-ts-ctx-dec"] = { module = "win", fnc = "preview_ts_ctx_inc_dec(-1)" }, - ["preview-up"] = { module = "win", fnc = "preview_scroll('line-up')" }, - ["preview-down"] = { module = "win", fnc = "preview_scroll('line-down')" }, - ["preview-page-up"] = { module = "win", fnc = "preview_scroll('page-up')" }, - ["preview-page-down"] = { module = "win", fnc = "preview_scroll('page-down')" }, - ["preview-half-page-up"] = { module = "win", fnc = "preview_scroll('half-page-up')" }, + ["toggle-preview"] = { module = "win", fnc = "toggle_preview()" }, + ["toggle-preview-wrap"] = { module = "win", fnc = "toggle_preview_wrap()" }, + ["toggle-preview-cw"] = { module = "win", fnc = "toggle_preview_cw(1)" }, + ["toggle-preview-ccw"] = { module = "win", fnc = "toggle_preview_cw(-1)" }, + ["toggle-preview-ts-ctx"] = { module = "win", fnc = "toggle_preview_ts_ctx()" }, + ["preview-ts-ctx-inc"] = { module = "win", fnc = "preview_ts_ctx_inc_dec(1)" }, + ["preview-ts-ctx-dec"] = { module = "win", fnc = "preview_ts_ctx_inc_dec(-1)" }, + ["preview-up"] = { module = "win", fnc = "preview_scroll('line-up')" }, + ["preview-down"] = { module = "win", fnc = "preview_scroll('line-down')" }, + ["preview-page-up"] = { module = "win", fnc = "preview_scroll('page-up')" }, + ["preview-page-down"] = { module = "win", fnc = "preview_scroll('page-down')" }, + ["preview-half-page-up"] = { module = "win", fnc = "preview_scroll('half-page-up')" }, ["preview-half-page-down"] = { module = "win", fnc = "preview_scroll('half-page-down')" }, - ["preview-reset"] = { module = "win", fnc = "preview_scroll('reset')" }, - ["preview-top"] = { module = "win", fnc = "preview_scroll('top')" }, - ["preview-bottom"] = { module = "win", fnc = "preview_scroll('bottom')" }, + ["preview-reset"] = { module = "win", fnc = "preview_scroll('reset')" }, + ["preview-top"] = { module = "win", fnc = "preview_scroll('top')" }, + ["preview-bottom"] = { module = "win", fnc = "preview_scroll('bottom')" }, } function FzfWin:setup_keybinds() - if not self:validate() then return end + if not self:validate() then + return + end 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()" }, + ["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 @@ -169,9 +183,9 @@ 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" or self.fullscreen)) + if + not self.previewer_is_builtin + or (self.preview_hidden and (self._previewer.toggle_behavior ~= "extend" or self.fullscreen)) then self.layout = { fzf = self:normalize_border({ @@ -184,7 +198,7 @@ function FzfWin:generate_layout(winopts) relative = self.winopts.relative or "editor", zindex = self.winopts.zindex, hide = self.winopts.hide, - }, { type = "nvim", name = "fzf", nwin = 1 }) + }, { type = "nvim", name = "fzf", nwin = 1 }), } return end @@ -218,7 +232,8 @@ function FzfWin:generate_layout(winopts) if self._preview_pos_force then -- Get the correct layout string and size when set from `:toggle_preview_cw` preview_str = (self._preview_pos_force == "up" or self._preview_pos_force == "down") - and winopts.preview.vertical or winopts.preview.horizontal + and winopts.preview.vertical + or winopts.preview.horizontal self._preview_pos = self._preview_pos_force else preview_str = self:fzf_preview_layout_str() @@ -232,7 +247,7 @@ function FzfWin:generate_layout(winopts) 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 + pwopts.height = utils.round(height * preview_size / 100, math.huge) - 2 if preview_pos == "down" then pwopts.row = height - pwopts.height - 2 end @@ -250,7 +265,7 @@ function FzfWin:generate_layout(winopts) height = height - 2 pwopts.col = col pwopts.width = width - pwopts.height = utils.round((height) * preview_size / 100, 0.5) + pwopts.height = utils.round(height * preview_size / 100, 0.5) height = height - pwopts.height if preview_pos == "down" then -- next row @@ -283,14 +298,19 @@ function FzfWin:generate_layout(winopts) relative = self.winopts.relative or "editor", zindex = self.winopts.zindex, hide = self.winopts.hide, - }), { type = "nvim", name = "fzf", nwin = nwin, 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, - hide = self.winopts.hide, - }), { type = "nvim", name = "prev", nwin = nwin, layout = preview_pos }) + }), + { type = "nvim", name = "fzf", nwin = nwin, 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, + hide = self.winopts.hide, + }), + { type = "nvim", name = "prev", nwin = nwin, layout = preview_pos } + ), } end @@ -317,8 +337,10 @@ function FzfWin:tmux_columns() end end)() local out = utils.io_system({ - "tmux", "display-message", "-p", - is_popup and "#{window_width}" or "#{pane_width}" + "tmux", + "display-message", + "-p", + is_popup and "#{window_width}" or "#{pane_width}", }) local cols = tonumber(out:match("%d+")) -- Calc the correct width when using tmux popup or left|right splits @@ -337,15 +359,15 @@ function FzfWin:columns(no_fullscreen) -- when starting with `winopts.fullscreen == true` local winopts = no_fullscreen and self:normalize_winopts(false) or self.winopts return self._o._is_fzf_tmux and self:tmux_columns() - or winopts.split and vim.api.nvim_win_get_width(self.fzf_winid or 0) - or winopts.width + or winopts.split and vim.api.nvim_win_get_width(self.fzf_winid or 0) + or winopts.width end function FzfWin:fzf_preview_layout_str() assert(self.winopts) local columns = self:columns() local is_hsplit = self.winopts.preview.layout == "horizontal" - or self.winopts.preview.layout == "flex" and columns > self.winopts.preview.flip_columns + or self.winopts.preview.layout == "flex" and columns > self.winopts.preview.flip_columns return is_hsplit and self._o.winopts.preview.horizontal or self._o.winopts.preview.vertical end @@ -357,37 +379,41 @@ function FzfWin:normalize_border(winopts, metadata) border = border(winopts, metadata) end -- Convert boolean types - if not border then border = "none" end - if border == true then border = "rounded" end + 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 + 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"] = "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"] = { "", "", "", "", "─", "─", "─", "" }, + ["border-top"] = { "─", "─", "─", "", "", "", "", "" }, + ["border-bottom"] = { "", "", "", "", "─", "─", "─", "" }, } if type(border) == "string" then if not valid_borders[border] then @@ -408,8 +434,9 @@ function FzfWin:normalize_border(winopts, metadata) -- when ambiwdith="double" `nvim_open_win` with border chars fails: -- with "border chars must be one cell", force string border (#874) if not self._o.silent then - utils.warn(string.format( - "Invalid border type for 'ambiwidth=double', will use 'rounded'.", border)) + utils.warn( + string.format("Invalid border type for 'ambiwidth=double', will use 'rounded'.", border) + ) end border = "rounded" end @@ -452,17 +479,17 @@ function FzfWin:normalize_winopts(fullscreen) winopts.__winhls = { main = { - { "Normal", self.hls.normal }, - { "NormalFloat", self.hls.normal }, - { "FloatBorder", self.hls.border }, - { "CursorLine", self.hls.cursorline }, + { "Normal", self.hls.normal }, + { "NormalFloat", self.hls.normal }, + { "FloatBorder", self.hls.border }, + { "CursorLine", self.hls.cursorline }, { "CursorLineNr", self.hls.cursorlinenr }, }, prev = { - { "Normal", self.hls.preview_normal }, - { "NormalFloat", self.hls.preview_normal }, - { "FloatBorder", self.hls.preview_border }, - { "CursorLine", self.hls.cursorline }, + { "Normal", self.hls.preview_normal }, + { "NormalFloat", self.hls.preview_normal }, + { "FloatBorder", self.hls.preview_border }, + { "CursorLine", self.hls.cursorline }, { "CursorLineNr", self.hls.cursorlinenr }, }, } @@ -517,7 +544,9 @@ function FzfWin:reset_win_highlights(win) end end -- set win option is slow with bigfile - if vim.wo[win].winhighlight ~= hl then vim.wo[win].winhighlight = hl end + if vim.wo[win].winhighlight ~= hl then + vim.wo[win].winhighlight = hl + end end ---@param exit_code integer @@ -527,7 +556,9 @@ function FzfWin:check_exit_status(exit_code, fzf_bufnr) if fzf_bufnr and fzf_bufnr ~= self.fzf_bufnr then return end - if not self:validate() then return end + if not self:validate() then + return + end -- from 'man fzf': -- 0 Normal exit -- 1 No match @@ -535,8 +566,9 @@ function FzfWin:check_exit_status(exit_code, fzf_bufnr) -- 130 Interrupted with CTRL-C or ESC if exit_code == 2 then local lines = vim.api.nvim_buf_get_lines(self.fzf_bufnr, 0, 1, false) - utils.warn(string.format("fzf error %d: %s", exit_code, - lines and #lines[1] > 0 and lines[1] or "")) + utils.warn( + string.format("fzf error %d: %s", exit_code, lines and #lines[1] > 0 and lines[1] or "") + ) end end @@ -550,18 +582,24 @@ function FzfWin:_set_autoclose(autoclose) end function FzfWin.set_autoclose(autoclose) - if not _self then return nil end + if not _self then + return nil + end return _self:_set_autoclose(autoclose) end function FzfWin.autoclose() - if not _self then return nil end + if not _self then + return nil + end return _self._autoclose end function FzfWin:set_backdrop() -- No backdrop for split, only floats / tmux - if self.winopts.split then return end + if self.winopts.split then + return + end -- Called from redraw? if self.backdrop_win then if vim.api.nvim_win_is_valid(self.backdrop_win) then @@ -574,15 +612,18 @@ function FzfWin:set_backdrop() end -- Validate backdrop hlgroup and opacity - self.hls.backdrop = type(self.hls.backdrop) == "string" - and self.hls.backdrop or "FzfLuaBackdrop" + self.hls.backdrop = type(self.hls.backdrop) == "string" and self.hls.backdrop or "FzfLuaBackdrop" self.winopts.backdrop = tonumber(self.winopts.backdrop) - or self.winopts.backdrop == true and 60 - or 100 - if self.winopts.backdrop < 0 or self.winopts.backdrop > 99 then return end + or self.winopts.backdrop == true and 60 + or 100 + if self.winopts.backdrop < 0 or self.winopts.backdrop > 99 then + return + end -- Neovim bg has no color, will look weird - if #utils.hexcol_from_hl("Normal", "bg") == 0 then return end + if #utils.hexcol_from_hl("Normal", "bg") == 0 then + return + end -- Code from lazy.nvim (#1344) self.backdrop_buf = vim.api.nvim_create_buf(false, true) @@ -607,7 +648,9 @@ function FzfWin:set_backdrop() end function FzfWin:close_backdrop() - if not self.backdrop_win or not self.backdrop_buf then return end + if not self.backdrop_win or not self.backdrop_buf then + return + end if self.backdrop_win and vim.api.nvim_win_is_valid(self.backdrop_win) then vim.api.nvim_win_close(self.backdrop_win, true) end @@ -655,13 +698,13 @@ function FzfWin:new(o) s._previewer:clear_cached_buffers() end end) - end + end, }) self.hls = o.hls self.actions = o.actions self.fullscreen = o.winopts.fullscreen self.winopts = self:normalize_winopts(self.fullscreen) - self.preview_wrap = not not o.winopts.preview.wrap -- force boolean + self.preview_wrap = not not o.winopts.preview.wrap -- force boolean self.preview_hidden = not not o.winopts.preview.hidden -- force boolean self.keymap = o.keymap self.previewer = o.previewer @@ -676,9 +719,12 @@ function FzfWin:new(o) if fg and #fg > 0 then local hlgroup = "FzfLuaScrollBorderBackCompat" self.hls.scrollfloat_f = hlgroup - vim.api.nvim_set_hl(0, hlgroup, + 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) }) + or { default = false, ctermfg = tonumber(bg), ctermbg = tonumber(fg) } + ) end end end @@ -687,7 +733,9 @@ function FzfWin:new(o) end function FzfWin:get_winopts(win, opts) - if not win or not api.nvim_win_is_valid(win) then return end + if not win or not api.nvim_win_is_valid(win) then + return + end local ret = {} for opt, _ in pairs(opts) do if utils.nvim_has_option(opt) then @@ -698,7 +746,9 @@ function FzfWin:get_winopts(win, opts) end function FzfWin:set_winopts(win, opts, ignore_events) - if not win or not api.nvim_win_is_valid(win) then return end + 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 @@ -736,9 +786,9 @@ end function FzfWin:validate_preview() return not self.closing - and tonumber(self.preview_winid) - and self.preview_winid > 0 - and api.nvim_win_is_valid(self.preview_winid) + and tonumber(self.preview_winid) + and self.preview_winid > 0 + and api.nvim_win_is_valid(self.preview_winid) end function FzfWin:redraw_preview() @@ -762,8 +812,11 @@ function FzfWin:redraw_preview() else local tmp_buf = self._previewer:get_tmp_buffer() -- No autocmds, can only be sent with 'nvim_open_win' - self.preview_winid = api.nvim_open_win(tmp_buf, false, - vim.tbl_extend("force", self.layout.preview, { noautocmd = true })) + 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) end @@ -773,8 +826,7 @@ function FzfWin:redraw_preview() end function FzfWin:validate() - return self.fzf_winid and self.fzf_winid > 0 - and api.nvim_win_is_valid(self.fzf_winid) + return self.fzf_winid and self.fzf_winid > 0 and api.nvim_win_is_valid(self.fzf_winid) end function FzfWin:redraw() @@ -789,26 +841,34 @@ function FzfWin:redraw() end function FzfWin:redraw_main() - if self.winopts.split then return end + if self.winopts.split then + return + end self:generate_layout() - local winopts = vim.tbl_extend("keep", (function() - if type(self.winopts.title) ~= "string" and type(self.winopts.title) ~= "table" then - return {} - end - return { - title = type(self.winopts.title) == "string" and type(self.hls.title) == "string" - and { { self.winopts.title, self.hls.title } } - or self.winopts.title, - title_pos = self.winopts.title_pos, - } - end)(), self.layout.fzf) + local winopts = vim.tbl_extend( + "keep", + (function() + if type(self.winopts.title) ~= "string" and type(self.winopts.title) ~= "table" then + return {} + end + return { + title = type(self.winopts.title) == "string" and type(self.hls.title) == "string" and { + { self.winopts.title, self.hls.title }, + } or self.winopts.title, + title_pos = self.winopts.title_pos, + } + end)(), + self.layout.fzf + ) if self:validate() then - if self._previewer - and self._previewer.clear_on_redraw - and self._previewer.clear_preview_buf then + if + self._previewer + and self._previewer.clear_on_redraw + and self._previewer.clear_preview_buf + then self._previewer:clear_preview_buf(true) self._previewer:clear_cached_buffers() end @@ -843,7 +903,9 @@ function FzfWin:_nvim_create_autocmd(e, callback) end function FzfWin:set_redraw_autocmd() - self:_nvim_create_autocmd("VimResized", function() self:redraw() end) + self:_nvim_create_autocmd("VimResized", function() + self:redraw() + end) end function FzfWin:set_winleave_autocmd() @@ -856,13 +918,18 @@ function FzfWin:treesitter_detach(buf) end function FzfWin:treesitter_attach() - if not self._o.winopts.treesitter then return end + if not self._o.winopts.treesitter then + return + end -- local utf8 = require("fzf-lua.lib.utf8") - local function trim(s) return (string.gsub(s, "^%s*(.-)%s*$", "%1")) end - ---@type fun(filepath: string, _lnum: string, text: string) - local line_parser = vim.is_callable(self._o._treesitter) and self._o._treesitter or function(line) - return line:match("(.-):?(%d+)[: ](.+)$") + local function trim(s) + return (string.gsub(s, "^%s*(.-)%s*$", "%1")) end + ---@type fun(filepath: string, _lnum: string, text: string) + local line_parser = vim.is_callable(self._o._treesitter) and self._o._treesitter + or function(line) + return line:match("(.-):?(%d+)[: ](.+)$") + end vim.api.nvim_buf_attach(self.fzf_bufnr, false, { on_lines = function(_, bufnr) local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false) @@ -873,9 +940,10 @@ function FzfWin:treesitter_attach() -- the native fzf preview window local min_col, max_col, trim_right = (function() local min, max, tr = 0, nil, 4 - if not self.preview_hidden - and (not self.previewer_is_builtin or self.winopts.split) - and vim.api.nvim_win_is_valid(self.fzf_winid) + if + not self.preview_hidden + and (not self.previewer_is_builtin or self.winopts.split) + and vim.api.nvim_win_is_valid(self.fzf_winid) then local win_width = vim.api.nvim_win_get_width(self.fzf_winid) local layout = self:fzf_preview_layout_str() @@ -898,30 +966,43 @@ function FzfWin:treesitter_attach() -- linetext (lines|blines) ---@diagnostic disable-next-line: unused-local local filepath, _lnum, text, _ft = line_parser(line:sub(min_col)) - if not text or text == 0 then return end + if not text or text == 0 then + return + end text = text:gsub("^%d+:", "") -- remove col nr if exists - filepath = trim(filepath) -- trim spaces + 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 + 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 -- IMPORTANT: use the `__CTX` version that doesn't trigger a new context 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 or (ft_bufnr and vim.bo[tonumber(ft_bufnr)].ft - or vim.filetype.match({ filename = path.tail(filepath) })) - if not ft then return end + local ft = _ft + or ( + ft_bufnr and vim.bo[tonumber(ft_bufnr)].ft + or vim.filetype.match({ filename = path.tail(filepath) }) + ) + if not ft then + return + end local lang = vim.treesitter.language.get_lang(ft) local loaded = lang and utils.has_ts_parser(lang) - if not loaded then return end + if not loaded then + return + end -- NOTE: if the line contains unicode characters `#line > win_width` -- as both `#str` and `string.len` count bytes and not characters @@ -941,12 +1022,14 @@ function FzfWin:treesitter_attach() end TSInjector.attach(bufnr, empty_regions) TSInjector.attach(bufnr, regions) - end + end, }) end function FzfWin:set_tmp_buffer(no_wipe) - if not self:validate() then return end + if not self:validate() then + return + end -- Store the [would be] detached buffer number local detached = self.fzf_bufnr -- replace the attached buffer with a new temp buffer, setting `self.fzf_bufnr` @@ -977,9 +1060,7 @@ function FzfWin:set_tmp_buffer(no_wipe) end function FzfWin:set_style_minimal(winid) - if not tonumber(winid) or - not api.nvim_win_is_valid(winid) - then + if not tonumber(winid) or not api.nvim_win_is_valid(winid) then return end vim.wo[winid].number = false @@ -1013,8 +1094,7 @@ function FzfWin:create() 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 + if self.winopts.on_create and type(self.winopts.on_create) == "function" then self.winopts.on_create({ winid = self.fzf_winid, bufnr = self.fzf_bufnr }) end -- not sure why but when using a split and reusing the window, @@ -1124,10 +1204,14 @@ function FzfWin:close(fzf_bufnr, do_not_clear_cache) -- 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) - if self.winopts and self.winopts.split - and self.src_winid and self.src_winid > 0 - and self.src_winid ~= vim.api.nvim_get_current_win() - and vim.api.nvim_win_is_valid(self.src_winid) then + if + self.winopts + and self.winopts.split + and self.src_winid + and self.src_winid > 0 + and self.src_winid ~= vim.api.nvim_get_current_win() + and vim.api.nvim_win_is_valid(self.src_winid) + then vim.api.nvim_set_current_win(self.src_winid) end if self.winopts.split then @@ -1168,7 +1252,9 @@ end function FzfWin.win_leave() local self = _self - if not self or self.closing then return end + if not self or self.closing then + return + end self:close() end @@ -1180,10 +1266,14 @@ end function FzfWin.hide() local self = _self - if not self or self:hidden() then return end + if not self or self:hidden() then + return + end -- Note: we should never get here with a tmux profile as neovim binds (default: ) -- do not apply to tmux, validate anyways in case called directly using the API - if not self or self._o._is_fzf_tmux then return end + if not self or self._o._is_fzf_tmux then + return + end self:detach_fzf_buf() self:close(nil, true) -- save the current window size (VimResized won't emit when buffer hidden) @@ -1194,32 +1284,38 @@ end function FzfWin:hidden() return tonumber(self._hidden_fzf_bufnr) - and tonumber(self._hidden_fzf_bufnr) > 0 - and vim.api.nvim_buf_is_valid(self._hidden_fzf_bufnr) + and tonumber(self._hidden_fzf_bufnr) > 0 + and vim.api.nvim_buf_is_valid(self._hidden_fzf_bufnr) end -- True after a `:new()` call for a different picker, used in `core.fzf` -- to avoid post processing an fzf process that was discarded function FzfWin:was_hidden() return tonumber(self._hidden_fzf_bufnr) - and tonumber(self._hidden_fzf_bufnr) > 0 - and not vim.api.nvim_buf_is_valid(self._hidden_fzf_bufnr) + and tonumber(self._hidden_fzf_bufnr) > 0 + and not vim.api.nvim_buf_is_valid(self._hidden_fzf_bufnr) end function FzfWin.unhide() local self = _self - if not self or not self:hidden() then return end + if not self or not self:hidden() then + return + end self._o.__CTX = utils.CTX({ includeBuflist = true }) self._o._unhide_called = true -- Send SIGWINCH to to trigger resize in the fzf process -- We will use the trigger to reload necessary buffer lists local pid = fn.jobpid(vim.bo[self._hidden_fzf_bufnr].channel) - vim.tbl_map(function(_pid) libuv.process_kill(_pid, 28) end, api.nvim_get_proc_children(pid)) + vim.tbl_map(function(_pid) + libuv.process_kill(_pid, 28) + end, api.nvim_get_proc_children(pid)) vim.bo[self._hidden_fzf_bufnr].bufhidden = "wipe" self.fzf_bufnr = self._hidden_fzf_bufnr self._hidden_fzf_bufnr = nil self:create() - if not vim.deep_equal(self._hidden_save_size, { vim.o.lines, vim.o.columns, vim.o.cmdheight }) then + if + not vim.deep_equal(self._hidden_save_size, { vim.o.lines, vim.o.columns, vim.o.cmdheight }) + then self:redraw() end self._hidden_save_size = nil @@ -1258,9 +1354,11 @@ function FzfWin:close_preview_scrollbar() end function FzfWin:update_preview_scrollbar() - if not self.winopts.preview.scrollbar - or self.winopts.preview.scrollbar == "none" - or not self:validate_preview() then + if + not self.winopts.preview.scrollbar + or self.winopts.preview.scrollbar == "none" + or not self:validate_preview() + then return end @@ -1271,8 +1369,8 @@ function FzfWin:update_preview_scrollbar() local topline, height = o.wininfo.topline, o.wininfo.height if api.nvim_win_text_height then - topline = topline == 1 and topline or - api.nvim_win_text_height(self.preview_winid, { end_row = topline - 1 }).all + 1 + topline = topline == 1 and topline + or api.nvim_win_text_height(self.preview_winid, { end_row = topline - 1 }).all + 1 end o.bar_height = math.min(height, math.ceil(height * height / o.line_count)) o.bar_offset = math.min(height - o.bar_height, math.floor(height * topline / o.line_count)) @@ -1284,8 +1382,10 @@ function FzfWin:update_preview_scrollbar() end local scrolloff = self.winopts.preview.scrollbar == "border" - and self.layout.preview.border ~= "none" and 0 - or tonumber(self.winopts.preview.scrolloff) or -1 + and self.layout.preview.border ~= "none" + and 0 + or tonumber(self.winopts.preview.scrolloff) + or -1 local empty = { style = "minimal", @@ -1316,8 +1416,12 @@ function FzfWin:update_preview_scrollbar() self._swin1 = utils.nvim_open_win0(self._sbuf1, false, empty) self:set_winopts(self._swin1, { eventignorewin = "WinResized" }) 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) + vim.wo[self._swin1].winhighlight = ("Normal:%s,NormalNC:%s,NormalFloat:%s,EndOfBuffer:%s"):format( + hl, + hl, + hl, + hl + ) end end if self._swin2 and vim.api.nvim_win_is_valid(self._swin2) then @@ -1328,8 +1432,12 @@ function FzfWin:update_preview_scrollbar() self._swin2 = utils.nvim_open_win0(self._sbuf2, false, full) self:set_winopts(self._swin2, { eventignorewin = "WinResized" }) 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) + vim.wo[self._swin2].winhighlight = ("Normal:%s,NormalNC:%s,NormalFloat:%s,EndOfBuffer:%s"):format( + hl, + hl, + hl, + hl + ) end end @@ -1340,20 +1448,24 @@ function FzfWin.update_win_title(winid, winopts, o) if type(o.title) ~= "string" and type(o.title) ~= "table" then return end - utils.fast_win_set_config(winid, + utils.fast_win_set_config( + winid, -- NOTE: although we can set the title without winopts we add these -- so we don't fail with "title requires border to be set" on wins -- without top border vim.tbl_extend("force", winopts, { - title = type(o.hl) == "string" and type(o.title) == "string" - and { { o.title, o.hl } } or o.title, + title = type(o.hl) == "string" and type(o.title) == "string" and { { o.title, o.hl } } + or o.title, title_pos = o.title_pos, - })) + }) + ) end function FzfWin:update_main_title(title) -- Can be called from fzf-tmux on ctrl-g - if not self.layout or self.winopts.split then return end + if not self.layout or self.winopts.split then + return + end self.winopts.title = title self._o.winopts.title = title self.update_win_title(self.fzf_winid, self.layout.fzf, { @@ -1381,14 +1493,18 @@ end -- keybind methods below function FzfWin.toggle_fullscreen() - if not _self or _self.winopts.split then return end + if not _self or _self.winopts.split then + return + end local self = _self self.fullscreen = not self.fullscreen self:redraw() end function FzfWin.toggle_preview() - if not _self then return end + if not _self then + return + end local self = _self self.preview_hidden = not self.preview_hidden if self._fzf_toggle_prev_bind then @@ -1414,7 +1530,9 @@ function FzfWin.toggle_preview() end function FzfWin.toggle_preview_wrap() - if not _self or not _self:validate_preview() then return end + if not _self or not _self:validate_preview() then + return + end local self = _self self.preview_wrap = not vim.wo[self.preview_winid].wrap if self and self:validate_preview() then @@ -1423,9 +1541,7 @@ function FzfWin.toggle_preview_wrap() end function FzfWin.toggle_preview_cw(direction) - if not _self - or _self.winopts.split - or not _self:validate_preview() then + if not _self or _self.winopts.split or not _self:validate_preview() then return end local self = _self @@ -1437,41 +1553,47 @@ function FzfWin.toggle_preview_cw(direction) break end end - if not idx then return end + if not idx then + return + end local newidx = direction > 0 and idx + 1 or idx - 1 - if newidx < 1 then newidx = #pos end - if newidx > #pos then newidx = 1 end + if newidx < 1 then + newidx = #pos + end + if newidx > #pos then + newidx = 1 + end self._preview_pos_force = pos[newidx] self:redraw() end function FzfWin.toggle_preview_ts_ctx() - if not _self then return end + if not _self then + return + end local self = _self - if self:validate_preview() - and self._previewer - and self._previewer.ts_ctx_toggle then + if self:validate_preview() and self._previewer and self._previewer.ts_ctx_toggle then self._previewer:ts_ctx_toggle() end end function FzfWin.preview_ts_ctx_inc_dec(num) - if not _self then return end + if not _self then + return + end local self = _self - if self:validate_preview() - and self._previewer - and self._previewer.ts_ctx_inc_dec_maxlines then + if self:validate_preview() and self._previewer and self._previewer.ts_ctx_inc_dec_maxlines then self._previewer:ts_ctx_inc_dec_maxlines(num) end end ---@param direction "top"|"bottom"|"half-page-up"|"half-page-down"|"page-up"|"page-down"|"line-up"|"line-down"|"reset" function FzfWin.preview_scroll(direction) - if not _self then return end + if not _self then + return + end local self = _self - if self:validate_preview() - and self._previewer - and self._previewer.scroll then + if self:validate_preview() and self._previewer and self._previewer.scroll then -- Do not trigger "ModeChanged" local save_ei = vim.o.eventignore vim.o.eventignore = "all" @@ -1498,7 +1620,9 @@ function FzfWin.close_help() end function FzfWin.toggle_help() - if not _self then return end + if not _self then + return + end local self = _self if self.km_winid then @@ -1522,8 +1646,8 @@ function FzfWin.toggle_help() local function format_bind(m, k, v, ml, kl, vl) return ("%s%%-%ds %%-%ds %%-%ds") - :format(opts.column_padding, ml, kl, vl) - :format("`" .. m .. "`", "|" .. k .. "|", "*" .. v .. "*") + :format(opts.column_padding, ml, kl, vl) + :format("`" .. m .. "`", "|" .. k .. "|", "*" .. v .. "*") end local keymaps = {} @@ -1546,8 +1670,10 @@ function FzfWin.toggle_help() if m == "builtin" then k = utils.neovim_bind_to_fzf(k) end - table.insert(keymaps, - format_bind(m, k, v, opts.mode_width, opts.keybind_width, opts.name_width)) + table.insert( + keymaps, + format_bind(m, k, v, opts.mode_width, opts.keybind_width, opts.name_width) + ) end end end @@ -1556,7 +1682,9 @@ function FzfWin.toggle_help() -- action keymaps if self.actions then for k, v in pairs(self.actions) do - if k == "default" then k = "enter" end + if k == "default" then + k = "enter" + end if type(v) == "table" then v = v.desc or config.get_action_helpstr(v[1]) or config.get_action_helpstr(v.fn) or v elseif v then @@ -1564,10 +1692,17 @@ function FzfWin.toggle_help() end if v then -- skips 'v == false' - table.insert(keymaps, - format_bind("action", k, + table.insert( + keymaps, + format_bind( + "action", + k, ("%s"):format(tostring(v)):gsub(" ", ""), - opts.mode_width, opts.keybind_width, opts.name_width)) + opts.mode_width, + opts.keybind_width, + opts.name_width + ) + ) end end end @@ -1606,8 +1741,7 @@ function FzfWin.toggle_help() for c = 0, math.floor(vim.o.columns / (opts.column_width + #opts.column_padding)) do for i = 1, height do local idx = height * c + i - lines[i] = c == 0 and keymaps[idx] or - lines[i] .. (keymaps[idx] or "") + lines[i] = c == 0 and keymaps[idx] or lines[i] .. (keymaps[idx] or "") end end @@ -1631,8 +1765,8 @@ function FzfWin.toggle_help() winopts.border = "single" end - local nvim_open_win = type(self._o.help_open_win) == "function" - and self._o.help_open_win or vim.api.nvim_open_win + local nvim_open_win = type(self._o.help_open_win) == "function" and self._o.help_open_win + or vim.api.nvim_open_win self.km_bufnr = vim.api.nvim_create_buf(false, true) vim.bo[self.km_bufnr].modifiable = true @@ -1640,7 +1774,7 @@ function FzfWin.toggle_help() self.km_winid = nvim_open_win(self.km_bufnr, false, winopts) vim.api.nvim_buf_set_name(self.km_bufnr, "_FzfLuaHelp") vim.wo[self.km_winid].winhl = - string.format("Normal:%s,FloatBorder:%s", opts.normal_hl, opts.border_hl) + string.format("Normal:%s,FloatBorder:%s", opts.normal_hl, opts.border_hl) vim.wo[self.km_winid].winblend = opts.winblend vim.wo[self.km_winid].foldenable = false vim.wo[self.km_winid].wrap = false diff --git a/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'fd'-} b/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'fd'-} index 0b2f2fd30..872af9248 100644 --- a/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'fd'-} +++ b/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'fd'-} @@ -2,7 +2,7 @@ 01| 02|~ 03|~ ╭─────────────────── Files h ────────────────────╮ -04|~ │> 112/112 (0) │ +04|~ │> 113/113 (0) │ 05|~ │──────────────────────────────────────────────── │ 06|~ │▌ [DEBUG] fd --hidden --color=never --type f -··││ 07|~ │ .editorconfig ││ diff --git a/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'find-dir'-} b/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'find-dir'-} index 842ef408e..554023093 100644 --- a/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'find-dir'-} +++ b/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'find-dir'-} @@ -2,7 +2,7 @@ 01| 02|~ 03|~ ╭───────────────────── Files ─────────────────────╮ -04|~ │> 112/112 (0) │ +04|~ │> 113/113 (0) │ 05|~ │──────────────────────────────────────────────── │ 06|~ │▌ [DEBUG] find . -type f \! -path '*/.git/*' \··││ 07|~ │ .editorconfig ││ diff --git a/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'rg'-} b/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'rg'-} index cbd2fe5c2..faa9da411 100644 --- a/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'rg'-} +++ b/tests/screenshots/tests-file-ui_spec.lua---files()---executable---1-+-args-{-'rg'-} @@ -2,7 +2,7 @@ 01| 02|~ 03|~ ╭─────────────────── Files h ────────────────────╮ -04|~ │> 112/112 (0) │ +04|~ │> 113/113 (0) │ 05|~ │──────────────────────────────────────────────── │ 06|~ │▌ [DEBUG] rg --hidden --files -g "!.git" --sor··││ 07|~ │ .editorconfig ││