Major refactor, read below if you're having issues

This patch is quite massive, hopefully I got everything right in
testing, changes include:
- New API interface for "live" queries, for usage refer to:
  https://github.com/ibhagwan/fzf-lua/wiki/Advanced
- All providers now use 'fzf_exec' API (previously 'fzf_wrap')
- All "live" queries now use 'fzf_live' API
- Better resume support for "live" queries
- Fzf initial command now uses $FZF_DEFAULT_COMMAND instead of piping the
  command, this delegates the responsiblity to fzf which kills the
  command on exit resulting in better responsibness when exiting fzf
- Added 'silent_fail' option (default:'true') to prevent fzf from
  displaying [Command failed:...] when commands exit with error code
- Exposed 'config.globals' as 'require'fzf-lua'.defaults'
- Fix: 'libuv.shellescape' with special chars in fish shells
- Manpages: moved fzf option `--tiebreak=begin' to config
- Buffer actions: navigate to line if exists
- Lsp_diagnostics: properly use a coroutine
- make_entry signatures changed (entry before opts)
- Removed make_entry shortcuts from 'core'
- Removed 'coroutine.yield' where unecessary
- Fix: 'git_icons' with 'live_grep({multiprocess=false})'
- tagstack: use relative paths and replace '$HOME' with '~'
- Deprecated 'core.fzf_files'
- Fix: resume query if cancelled while loading indicator is shown
- Fix: resume query when command failed with 'silent_fail=false'
main
bhagwan 2 years ago
parent 341f0641ea
commit 817df87a8e

@ -8,9 +8,10 @@
![Demo](https://raw.githubusercontent.com/wiki/ibhagwan/fzf-lua/demo.gif)
[fzf](https://github.com/junegunn/fzf) changed my life, it can change yours too, if you allow it.
[fzf](https://github.com/junegunn/fzf) changed my command life, it can change
yours too, if you allow it.
</div>
</div>
## Rationale
@ -30,9 +31,9 @@ the new shiny fuzzy finders for neovim.
## Why Fzf-Lua
... and not, to name a few,
[telescope](https://github.com/nvim-telescope/telescope.nvim) or
[vim-clap](https://github.com/liuchengxu/vim-clap)?
... and not
[telescope](https://github.com/nvim-telescope/telescope.nvim)
or any other vim/neovim household name?
As [@junegunn](https://github.com/junegunn) himself put it, “because you can
and you love `fzf`”.
@ -55,7 +56,7 @@ at it. That, **and colorful file icons and git indicators!**.
(optional)
> `fzf` version > `0.27` is recommended but it's still possible to use `fzf`
> version > `0.24` by setting `fzf_opts = { ['--border'] = false }`, see
> version > `0.25` by setting `fzf_opts = { ['--border'] = false }`, see
> [Customization](#customization).
### Optional dependencies
@ -249,9 +250,14 @@ vim.api.nvim_set_keymap('n', '<c-P>',
## Customization
I tried to make it as customizable as possible, if you find you need to change something that isnt below, open an issue and Ill do my best to add it.
> **[ADVANCED CUSTOMIZATION](https://github.com/ibhagwan/fzf-lua/wiki/Advanced)
: to create your own fzf-lua commands see
[Wiki/ADVANCED](https://github.com/ibhagwan/fzf-lua/wiki/Advanced)**
customization can be achieved by calling the `setup()` function or individually sending parameters to a builtin command, for example:
I tried to make this plugin as customizable as possible, if you find you need to
change something that isnt below, open an issue and Ill do my best to add it.
Customization can be achieved by calling the `setup()` function or individually sending parameters to a builtin command, for example:
```lua
:lua require('fzf-lua').files({ fzf_opts = {['--layout'] = 'reverse-list'} })
```
@ -603,7 +609,7 @@ require'fzf-lua'.setup {
-- 'rg_glob_fn' to return a pair:
-- first returned argument is the new search query
-- second returned argument are addtional rg flags
-- rg_glob_fn = function(opts, query)
-- rg_glob_fn = function(query, opts)
-- ...
-- return new_query, flags
-- end,
@ -810,7 +816,7 @@ and plugin codes that I probably forgot where I found some samples from so if
I missed your name feel free to contact me and I'll add it below:
- [@vijaymarupudi](https://github.com/vijaymarupudi/) for his wonderful
[nvim-fzf](https://github.com/vijaymarupudi/nvim-fzf) plugin which is in the
[nvim-fzf](https://github.com/vijaymarupudi/nvim-fzf) plugin which is at the
core of this plugin
- [@tjdevries](https://github.com/tjdevries/) for too many great things to
list here and for borrowing some of his

@ -66,7 +66,7 @@ DEPENDENCIES *fzf-lua-dependencies*
- nvim-web-devicons <https://github.com/kyazdani42/nvim-web-devicons>
(optional)
`fzf` version > `0.27` is recommended but it's still possible to use `fzf`
version > `0.24` by setting `fzf_opts = { ['--border'] = false }`, see
version > `0.25` by setting `fzf_opts = { ['--border'] = false }`, see
Customization <#customization>.
@ -648,7 +648,7 @@ Consult the list below for available settings:
-- 'rg_glob_fn' to return a pair:
-- first returned argument is the new search query
-- second returned argument are addtional rg flags
-- rg_glob_fn = function(opts, query)
-- rg_glob_fn = function(query, opts)
-- ...
-- return new_query, flags
-- end,
@ -874,4 +874,4 @@ I missed your name feel free to contact me and I'll add it below:
as baseline for the builtin previewer and his must have plugin nvim-bqf
<https://github.com/kevinhwang91/nvim-bqf>
vim:tw=78:ts=8:ft=help:norl:
vim:tw=78:ts=8:ft=help:norl:

@ -213,27 +213,37 @@ M.file_switch_or_edit = function(...)
end
-- buffer actions
M.vimcmd_buf = function(vimcmd, selected, _)
M.vimcmd_buf = function(vimcmd, selected, opts)
local curbuf = vim.api.nvim_get_current_buf()
local lnum = vim.api.nvim_win_get_cursor(0)[1]
local is_term = utils.is_term_buffer(0)
for i = 1, #selected do
local bufnr = string.match(selected[i], "%[(%d+)")
if bufnr then
if vimcmd == 'b'
and curbuf ~= tonumber(bufnr)
and not vim.o.hidden and
utils.buffer_is_dirty(nil, true) then
-- warn the user when trying to switch from a dirty buffer
-- when `:set nohidden`
return
end
if vimcmd ~= "b" or curbuf ~= tonumber(bufnr) then
local cmd = vimcmd .. " " .. bufnr
local ok, res = pcall(vim.cmd, cmd)
if not ok then
utils.warn(("':%s' failed: %s"):format(cmd, res))
end
local entry = path.entry_to_file(selected[i], opts)
if not entry.bufnr then return end
assert(type(entry.bufnr) == 'number')
if vimcmd == 'b'
and curbuf ~= entry.bufnr
and not vim.o.hidden and
utils.buffer_is_dirty(nil, true) then
-- warn the user when trying to switch from a dirty buffer
-- when `:set nohidden`
return
end
-- add current location to jumplist
if not is_term then vim.cmd("normal! m`") end
if vimcmd ~= "b" or curbuf ~= entry.bufnr then
local cmd = vimcmd .. " " .. entry.bufnr
local ok, res = pcall(vim.cmd, cmd)
if not ok then
utils.warn(("':%s' failed: %s"):format(cmd, res))
end
end
if curbuf ~= entry.bufnr or lnum ~= entry.line then
-- make sure we have valid column
entry.col = entry.col and entry.col>0 and entry.col or 1
vim.api.nvim_win_set_cursor(0, {tonumber(entry.line), tonumber(entry.col)-1})
end
if not is_term then vim.cmd("norm! zvzz") end
end
end
@ -431,19 +441,25 @@ M.help_tab = function(selected)
M.vimcmd(vimcmd, helptags(selected), true)
end
local function mantags(s)
return vim.tbl_map(function(x)
return x:match("[^[,( ]+")
end, s)
end
M.man = function(selected)
local vimcmd = "Man"
M.vimcmd(vimcmd, selected)
M.vimcmd(vimcmd, mantags(selected))
end
M.man_vert = function(selected)
local vimcmd = "vert Man"
M.vimcmd(vimcmd, selected)
M.vimcmd(vimcmd, mantags(selected))
end
M.man_tab = function(selected)
local vimcmd = "tab Man"
M.vimcmd(vimcmd, selected)
M.vimcmd(vimcmd, mantags(selected))
end
@ -586,8 +602,7 @@ end
M.grep_lgrep = function(_, opts)
-- 'FNCREF' is set only on 'M.live_grep' calls
-- 'MODULE' is set on 'M.grep' and 'live_grep' calls
-- 'MODULE' is set on 'grep' and 'live_grep' calls
assert(opts.__MODULE__
and type(opts.__MODULE__.grep) == 'function'
or type(opts.__MODULE__.live_grep) == 'function')
@ -601,7 +616,8 @@ M.grep_lgrep = function(_, opts)
requires_processing = opts.rg_glob or opts.__call_opts.rg_glob,
}, opts.__call_opts or {})
if opts.__FNCREF__ then
-- 'fn_reload' is set only on 'live_grep' calls
if opts.fn_reload then
opts.__MODULE__.grep(o)
else
opts.__MODULE__.live_grep(o)
@ -609,3 +625,4 @@ M.grep_lgrep = function(_, opts)
end
return M

@ -484,6 +484,7 @@ M.globals.manpages = {
["ctrl-v"] = actions.man_vert,
["ctrl-t"] = actions.man_tab,
},
fzf_opts = { ['--tiebreak'] = 'begin' },
previewer = "man",
}
M.globals.lsp = {

@ -10,6 +10,73 @@ local make_entry = require "fzf-lua.make_entry"
local M = {}
-- Main API, see:
-- https://github.com/ibhagwan/fzf-lua/wiki/Advanced
M.fzf_exec = function(contents, opts)
if not opts or not opts._normalized then
opts = config.normalize_opts(opts or {}, {})
if not opts then return end
end
opts.fn_selected = opts.fn_selected or function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end
-- 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,
pid_cb = opts._pid_cb,
},
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), utlizes fzf's 'change:reload'
-- event trigger or skim's "interactive" mode
if type(opts.fn_reload) == 'string' then
if not opts.fn_transform then
-- TODO: add support for 'fn_transform' using 'mt_cmd_wrapper'
-- functions can be stored using 'config.bytecode' which uses
-- 'string.dump' to convert to function code to bytes
opts = M.setup_fzf_interactive_native(opts.fn_reload, opts)
contents = opts.__fzf_init_cmd
else
-- the caller requested to transform, we need to convert
-- to a function that returns string so that libuv.spawn
-- is called
local cmd = opts.fn_reload
opts.fn_reload = function(q)
if cmd:match(M.fzf_query_placeholder) then
return cmd:gsub(M.fzf_query_placeholder, q or '')
else
return string.format("%s %s", cmd, q or '')
end
end
end
end
if type(opts.fn_reload) == 'function' then
opts.__fn_transform = opts.fn_transform
opts.__fn_reload = function(query)
if config.__resume_data then
config.__resume_data.last_query = query
end
return opts.fn_reload(query)
end
opts = M.setup_fzf_interactive_wrap(opts)
contents = opts.__fzf_init_cmd
end
return M.fzf_wrap(opts, contents)()
end
M.fzf_live = function(contents, opts)
assert(contents)
opts = opts or {}
opts.fn_reload = contents
return M.fzf_exec(nil, opts)
end
M.fzf_resume = function(opts)
if not config.__resume_data or not config.__resume_data.opts then
utils.info("No resume data available, is 'global_resume' enabled?")
@ -17,26 +84,16 @@ M.fzf_resume = function(opts)
end
opts = vim.tbl_deep_extend("force", config.__resume_data.opts, opts or {})
local last_query = config.__resume_data.last_query
if last_query and #last_query>0 then
last_query = vim.fn.shellescape(last_query)
else
if not last_query or #last_query==0 then
-- in case we continue from another resume
-- reset the previous query which was saved
-- inside "fzf_opts['--query']" argument
last_query = false
end
opts.__resume = true
if opts.__FNCREF__ then
-- HACK for 'live_grep' and 'lsp_live_workspace_symbols'
opts.cmd = nil
opts.query = nil
opts.search = nil
opts.resume = true
opts.__FNCREF__(opts)
else
opts.fzf_opts['--query'] = last_query
M.fzf_wrap(opts, config.__resume_data.contents)()
end
opts.query = last_query
opts.fzf_opts['--query'] = last_query and vim.fn.shellescape(last_query)
M.fzf_exec(config.__resume_data.contents, opts)
end
M.fzf_wrap = function(opts, contents, fn_selected)
@ -50,26 +107,10 @@ M.fzf_wrap = function(opts, contents, fn_selected)
end)
end
M.fzf_exec = function(contents, opts)
opts = config.normalize_opts(opts or {}, {})
opts.fn_selected = opts.fn_selected or function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end
-- wrapper for command transformer
if type(contents) == 'string' and opts.fn_transform then
contents = libuv.spawn_nvim_fzf_cmd({
cmd = contents,
cwd = opts.cwd,
}, opts.fn_transform)
end
return M.fzf_wrap(opts, contents)()
end
M.fzf = function(opts, contents)
-- normalize with globals if not already normalized
if not opts._normalized then
opts = config.normalize_opts(opts, {})
if not opts or not opts._normalized then
opts = config.normalize_opts(opts or {}, {})
if not opts then return end
end
if opts.fn_pre_win then
@ -163,9 +204,12 @@ M.fzf = function(opts, contents)
opts.fzf_opts['--preview-window'] = 'hidden:right:0'
end
-- 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
-- some functions such as buffers|tabs
-- need to reacquire current buffer|tab state
opts.fn_pre_fzf(opts)
end
@ -175,7 +219,7 @@ M.fzf = function(opts, contents)
-- lose overrides by 'winopts_fn|winopts_raw'
opts.winopts.preview = fzf_win.winopts.preview
local selected, exit_code = fzf.raw_fzf(contents, M.build_fzf_cli(opts),
{ fzf_binary = opts.fzf_bin, fzf_cwd = opts.cwd })
{ fzf_bin = opts.fzf_bin, cwd = opts.cwd, silent_fail = opts.silent_fail })
-- This was added by 'resume':
-- when '--print-query' is specified
-- we are guaranteed to have the query
@ -191,6 +235,9 @@ M.fzf = function(opts, contents)
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
@ -227,10 +274,12 @@ M.get_color = function(hl_group, what)
end
-- Create fzf --color arguments from a table of vim highlight groups.
M.create_fzf_colors = function(colors)
if not colors then
return ""
M.create_fzf_colors = function(opts)
local colors = opts and opts.fzf_colors
if type(colors) == 'function' then
colors = colors(opts)
end
if not colors then return end
local tbl = {}
for highlight, list in pairs(colors) do
@ -247,7 +296,7 @@ M.create_fzf_colors = function(colors)
end
end
return string.format("--color=%s", table.concat(tbl, ","))
return not vim.tbl_isempty(tbl) and table.concat(tbl, ",")
end
M.create_fzf_binds = function(binds)
@ -282,7 +331,7 @@ M.build_fzf_cli = function(opts)
end
opts.fzf_opts["--bind"] = M.create_fzf_binds(opts.keymap.fzf)
if opts.fzf_colors then
opts.fzf_opts["--color"] = M.create_fzf_colors(opts.fzf_colors)
opts.fzf_opts["--color"] = M.create_fzf_colors(opts)
end
opts.fzf_opts["--expect"] = actions.expect(opts.actions)
opts.fzf_opts["--preview"] = opts.preview or opts.fzf_opts["--preview"]
@ -399,8 +448,10 @@ M.mt_cmd_wrapper = function(opts)
-- command does not require any processing
return opts.cmd
elseif opts.multiprocess then
local fn_preprocess = opts._fn_preprocess_str or [[return require("make_entry").preprocess]]
local fn_transform = opts._fn_transform_str or [[return require("make_entry").file]]
assert(not opts.__mt_transform or type(opts.__mt_transform) == 'string')
assert(not opts.__mt_preprocess or type(opts.__mt_preprocess) == 'string')
local fn_preprocess = opts.__mt_preprocess or [[return require("make_entry").preprocess]]
local fn_transform = opts.__mt_transform or [[return require("make_entry").file]]
-- replace all below 'fn.shellescape' with our version
-- replacing the surrounding single quotes with double
-- as this was causing resume to fail with fish shell
@ -427,40 +478,23 @@ M.mt_cmd_wrapper = function(opts)
end
return cmd
else
assert(not opts.__mt_transform or type(opts.__mt_transform) == 'function')
assert(not opts.__mt_preprocess or type(opts.__mt_preprocess) == 'function')
return libuv.spawn_nvim_fzf_cmd(opts,
function(x)
return opts._fn_transform
and opts._fn_transform(opts, x)
or make_entry.file(opts, 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._fn_preprocess
and opts._fn_preprocess(o)
return opts.__mt_preprocess
and opts.__mt_preprocess(o)
or make_entry.preprocess(o)
end)
end
end
-- shortcuts to make_entry
M.get_devicon = make_entry.get_devicon
M.make_entry_file = make_entry.file
M.make_entry_preprocess = make_entry.preprocess
M.make_entry_lcol = function(opts, entry)
if not entry then return nil end
local filename = entry.filename or vim.api.nvim_buf_get_name(entry.bufnr)
return string.format("%s:%s:%s:%s%s",
-- uncomment to test URIs
-- "file://" .. filename,
filename, --utils.ansi_codes.magenta(filename),
utils.ansi_codes.green(tostring(entry.lnum)),
utils.ansi_codes.blue(tostring(entry.col)),
entry.text and #entry.text>0 and " " or "",
not entry.text and "" or
(opts.trim_entry and vim.trim(entry.text)) or entry.text)
end
-- given the default delimiter ':' this is the
-- fzf experssion field index for the line number
-- when entry format is 'file:line:col: text'
@ -542,7 +576,7 @@ M.set_header = function(opts, hdr_tbl)
if opts.no_header_i then return end
for k, v in pairs(opts.actions) do
if type(v) == 'table' and v[1] == actions.grep_lgrep then
local to = opts.__FNCREF__ and 'Grep' or 'Live Grep'
local to = opts.fn_reload and 'Grep' or 'Live Grep'
return (':: <%s> to %s'):format(
utils.ansi_codes.yellow(k),
utils.ansi_codes.red(to))
@ -583,127 +617,108 @@ M.set_header = function(opts, hdr_tbl)
return opts
end
-- NOT IN USE, here for backward compat
M.fzf_files = function(opts, contents)
utils.warn("'core.fzf_files' is deprecated, use 'fzf_exec' instead,"
.. " see github@fzf-lua/wiki/Advanced.")
M.fzf_exec(contents or opts and opts.fzf_fn and opts.fzf_fn, opts)
end
if not opts then return end
M.setup_fzf_interactive_flags = function(command, fzf_field_expression, opts)
-- query cannot be 'nil'
opts.query = opts.query or ''
M.fzf_wrap(opts, contents or opts.fzf_fn, function(selected)
-- by redirecting the error stream to stdout
-- we make sure a clear error message is displayed
-- when the user enters bad regex expressions
local initial_command = command
if (opts.stderr_to_stdout ~= false) and
not initial_command:match("2>") then
initial_command = command .. " 2>&1"
end
if opts.post_select_cb then
opts.post_select_cb()
local reload_command = initial_command
if not opts.exec_empty_query then
reload_command = ('[ -z %s ] || %s'):format(fzf_field_expression, reload_command)
end
if opts._is_skim then
-- skim interactive mode does not need a piped command
opts.__fzf_init_cmd = nil
opts.prompt = opts.prompt or opts.fzf_opts['--prompt']
if opts.prompt then
opts.fzf_opts['--prompt'] = opts.prompt:match("[^%*]+")
opts.fzf_opts['--cmd-prompt'] = libuv.shellescape(opts.prompt)
opts.prompt = nil
end
if not selected then return end
if #selected > 1 then
local idx = utils.tbl_length(opts.actions)>1 and 2 or 1
for i = idx, #selected do
selected[i] = path.entry_to_file(selected[i], opts).stripped
end
-- '--query' was set by 'resume()', skim has the option to switch back and
-- forth between interactive command and fuzzy matching (using 'ctrl-q')
-- setting both '--query' and '--cmd-query' will use <query> to fuzzy match
-- on top of our result set double filtering our results (undesierable)
opts.fzf_opts['--query'] = nil
-- since we surrounded the skim placeholder with quotes
-- we need to escape them in the initial query
opts.fzf_opts['--cmd-query'] = libuv.shellescape(utils.sk_escape(opts.query))
opts._fzf_cli_args = string.format("--interactive --cmd %s",
vim.fn.shellescape(reload_command))
else
-- send an empty table to avoid running $FZF_DEFAULT_COMMAND
opts.__fzf_init_cmd = {}
if opts.exec_empty_query or (opts.query and #opts.query > 0) then
opts.__fzf_init_cmd = initial_command:gsub(fzf_field_expression,
libuv.shellescape(opts.query:gsub("%%", "%%%%")))
end
opts.fzf_opts['--disabled'] = ''
opts.fzf_opts['--query'] = libuv.shellescape(opts.query)
-- OR with true to avoid fzf's "Command failed:" message
if opts.silent_fail ~= false then
reload_command = ("%s || true"):format(reload_command)
end
opts._fzf_cli_args = string.format('--bind=%s',
vim.fn.shellescape(("change:reload:%s"):format(
("%s"):format(reload_command))))
end
actions.act(opts.actions, selected, opts)
end)()
return opts
end
M.set_fzf_interactive_cmd = function(opts)
if not opts then return end
-- query placeholder for "live" queries
M.fzf_query_placeholder = "<query>"
M.fzf_field_expression = function(opts)
-- fzf already adds single quotes around the placeholder when expanding
-- for skim we surround it with double quotes or single quote searches fail
local placeholder = utils._if(opts._is_skim, '"{}"', '{q}')
local raw_async_act = shell.reload_action_cmd(opts, placeholder)
return M.set_fzf_interactive(opts, raw_async_act, placeholder)
return opts and opts._is_skim and '"{}"' or '{q}'
end
M.set_fzf_interactive_cb = function(opts)
if not opts then return end
-- fzf already adds single quotes around the placeholder when expanding
-- for skim we surround it with double quotes or single quote searches fail
local placeholder = utils._if(opts._is_skim, '"{}"', '{q}')
local uv = vim.loop
local raw_async_act = shell.raw_async_action(function(pipe, args)
-- Sets up the flags and commands require for running a "live" interface
-- @param fn_reload :function called for reloading contents
-- @param fn_transform :function to transform entries when using shell cmd
M.setup_fzf_interactive_wrap = function(opts)
coroutine.wrap(function()
assert(opts and opts.__fn_reload)
local co = coroutine.running()
local results = opts._reload_action(args[1])
local close_pipe = function()
if pipe and not uv.is_closing(pipe) then
uv.close(pipe)
pipe = nil
end
coroutine.resume(co)
end
-- neovim shell wrapper for parsing the query and loading contents
local fzf_field_expression = M.fzf_field_expression(opts)
local command = shell.reload_action_cmd(opts, fzf_field_expression)
return M.setup_fzf_interactive_flags(command, fzf_field_expression, opts)
if type(results) == 'table' and not vim.tbl_isempty(results) then
uv.write(pipe,
vim.tbl_map(function(x) return x.."\n" end, results),
function(_)
close_pipe()
end)
-- wait for write to finish
coroutine.yield()
end
-- does nothing if write finished successfully
close_pipe()
end)()
end, placeholder, opts.debug)
return M.set_fzf_interactive(opts, raw_async_act, placeholder)
end
M.set_fzf_interactive = function(opts, act_cmd, placeholder)
M.setup_fzf_interactive_native = function(command, opts)
if not opts or not act_cmd or not placeholder then return end
local fzf_field_expression = M.fzf_field_expression(opts)
-- cannot be nil
local query = opts.query or ''
if opts._is_skim then
-- do not run an empty string query unless the user requested
if not opts.exec_empty_query then
act_cmd = "sh -c " .. vim.fn.shellescape(
("[ -z %s ] || %s"):format(placeholder, act_cmd))
else
act_cmd = vim.fn.shellescape(act_cmd)
end
-- skim interactive mode does not need a piped command
opts.fzf_fn = nil
opts.fzf_opts['--prompt'] = opts.prompt:match("[^%*]+")
opts.fzf_opts['--cmd-prompt'] = libuv.shellescape(opts.prompt)
opts.prompt = nil
-- since we surrounded the skim placeholder with quotes
-- we need to escape them in the initial query
opts.fzf_opts['--cmd-query'] = libuv.shellescape(utils.sk_escape(query))
opts._fzf_cli_args = string.format( "-i -c %s", act_cmd)
-- replace placeholder with the field index expression
-- if the command doesn't contain our placeholder append
-- the field index expression instead
if command:match(M.fzf_query_placeholder) then
command = opts.fn_reload:gsub(M.fzf_query_placeholder, fzf_field_expression)
else
-- fzf already adds single quotes
-- around the place holder
opts.fzf_fn = {}
if opts.exec_empty_query or (query and #query>0) then
opts.fzf_fn = act_cmd:gsub(placeholder,
#query>0 and utils.lua_escape(libuv.shellescape(query)) or "''")
end
opts.fzf_opts['--phony'] = ''
opts.fzf_opts['--query'] = libuv.shellescape(query)
opts._fzf_cli_args = string.format('--bind=%s',
vim.fn.shellescape(string.format("change:reload:%s || true", act_cmd)))
command = ("%s %s"):format(command, fzf_field_expression)
end
return opts
return M.setup_fzf_interactive_flags(command, fzf_field_expression, opts)
end
return M

@ -7,15 +7,6 @@ local uv = vim.loop
local M = {}
local function get_lines_from_file(file)
local t = {}
for v in file:lines() do
table.insert(t, v)
end
return t
end
-- workaround to a potential 'tempname' bug? (#222)
-- neovim doesn't guarantee the existence of the
-- parent temp dir potentially failing `mkfifo`
@ -41,21 +32,31 @@ end
-- behavior.
function M.raw_fzf(contents, fzf_cli_args, opts)
if not coroutine.running() then
error("please run function in a coroutine")
error("[Fzf-lua] function must be called inside a coroutine.")
end
if not opts then opts = {} end
local cwd = opts.fzf_cwd or opts.cwd
local cmd = opts.fzf_binary or opts.fzf_bin or 'fzf'
local cmd = opts.fzf_bin or 'fzf'
local fifotmpname = tempname()
local outputtmpname = tempname()
-- we use a temporary env $FZF_DEFAULT_COMMAND instead of piping
-- the command to fzf, this way fzf kills the command when it exits
-- this is especially important with our shell helper as io.write fails
-- to delect when the pipe is broken (EPIPE) so the neovim headless
-- instance never terminates which hangs fzf on exit
local FZF_DEFAULT_COMMAND = nil
if fzf_cli_args then cmd = cmd .. " " .. fzf_cli_args end
if opts.fzf_cli_args then cmd = cmd .. " " .. opts.fzf_cli_args end
if contents then
if type(contents) == "string" and #contents>0 then
cmd = ("%s | %s"):format(contents, cmd)
if opts.silent_fail ~= false then
contents = ("%s || true"):format(contents)
end
FZF_DEFAULT_COMMAND = contents
else
cmd = ("%s < %s"):format(cmd, vim.fn.shellescape(fifotmpname))
end
@ -134,11 +135,20 @@ function M.raw_fzf(contents, fzf_cli_args, opts)
local co = coroutine.running()
vim.fn.termopen({"sh", "-c", cmd}, {
cwd = cwd,
env = { ['SHELL'] = 'sh' },
env = {
['SHELL'] = 'sh',
['FZF_DEFAULT_COMMAND'] = FZF_DEFAULT_COMMAND,
['SKIM_DEFAULT_COMMAND'] = FZF_DEFAULT_COMMAND,
},
on_exit = function(_, rc, _)
local output = {}
local f = io.open(outputtmpname)
local output = get_lines_from_file(f)
f:close()
if f then
for v in f:lines() do
table.insert(output, v)
end
f:close()
end
finish(1)
vim.fn.delete(fifotmpname)
vim.fn.delete(outputtmpname)

@ -155,9 +155,11 @@ M.dap_frames = require'fzf-lua.providers.dap'.frames
-- API shortcuts
M.fzf = require'fzf-lua.core'.fzf
M.fzf_raw = require'fzf-lua.fzf'.raw_fzf
M.fzf_wrap = require'fzf-lua.core'.fzf_wrap
M.fzf_exec = require'fzf-lua.core'.fzf_exec
M.raw_fzf = require'fzf-lua.fzf'.raw_fzf
M.fzf_live = require'fzf-lua.core'.fzf_live
M.defaults = config.globals
-- exported modules
M._exported_modules = {
@ -169,15 +171,18 @@ M._exported_modules = {
'shell',
'config',
'actions',
'make_entry',
}
-- excluded from builtin / auto-complete
M._excluded_meta = {
'setup',
'fzf',
'fzf_raw',
'fzf_wrap',
'fzf_exec',
'raw_fzf',
'fzf_live',
'defaults',
'_excluded_meta',
'_excluded_metamap',
'_exported_modules',

@ -418,7 +418,7 @@ M.spawn_stdio = function(opts, fn_transform, fn_preprocess)
cb_err = on_err,
},
fn_transform and function(x)
return fn_transform(opts, x)
return fn_transform(x, opts)
end)
end
@ -443,7 +443,11 @@ M.shellescape = function(s)
-- replace surrounding single quote with double quotes
-- temporarily replace all single quotes with double
-- quotes and restore after the call to shellescape
ret = vim.fn.shellescape(s:gsub([[']], [["]]))
-- NOTE: we use '({s:gsub(...)})[1]' to extract the
-- modified string without the multival # of changes
-- otherwise the number will be sent to shellescape
-- as {special} triggering an escape for ! % and #
ret = vim.fn.shellescape(({s:gsub([[']], [["]])})[1])
ret = [["]] .. ret:gsub([["]], [[']]):sub(2, #ret-1) .. [["]]
else
ret = vim.fn.shellescape(s)

@ -206,12 +206,12 @@ M.get_diff_files = function(opts)
return diff_files
end
M.glob_parse = function(opts, query)
M.glob_parse = function(query, opts)
if not query or not query:find(opts.glob_separator) then
return query, nil
end
if config.globals.grep.rg_glob_fn then
return config.globals.grep.rg_glob_fn(opts, query)
return config.globals.grep.rg_glob_fn(query, opts)
end
local glob_args = ""
local search_query, glob_str = query:match("(.*)"..opts.glob_separator.."(.*)")
@ -245,7 +245,7 @@ M.preprocess = function(opts)
-- live_grep replace pattern with last argument
local argvz = "{argvz}"
local has_argvz = opts.cmd:match(argvz)
local has_argvz = opts.cmd and opts.cmd:match(argvz)
-- save our last search argument for resume
if opts.argv_expr and has_argvz then
@ -261,7 +261,7 @@ M.preprocess = function(opts)
-- mannipulation needs to be done before the argv hack
if opts.rg_glob and has_argvz then
local query = argv()
local search_query, glob_args = M.glob_parse(opts, query)
local search_query, glob_args = M.glob_parse(query, opts)
if glob_args then
-- gsub doesn't like single % on rhs
search_query = search_query:gsub("%%", "%%%%")
@ -284,7 +284,22 @@ M.preprocess = function(opts)
return opts
end
M.file = function(opts, x)
M.lcol = function(entry, opts)
if not entry then return nil end
local filename = entry.filename or vim.api.nvim_buf_get_name(entry.bufnr)
return string.format("%s:%s:%s:%s%s",
-- uncomment to test URIs
-- "file://" .. filename,
filename, --utils.ansi_codes.magenta(filename),
utils.ansi_codes.green(tostring(entry.lnum)),
utils.ansi_codes.blue(tostring(entry.col)),
entry.text and #entry.text>0 and " " or "",
not entry.text and "" or
(opts and opts.trim_entry and vim.trim(entry.text)) or entry.text)
end
M.file = function(x, opts)
opts = opts or {}
local ret = {}
local icon, hl
local file = utils.strip_ansi_coloring(string.match(x, '[^:]*'))
@ -351,7 +366,7 @@ M.file = function(opts, x)
return table.concat(ret)
end
M.tag = function(opts, x)
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
text = text:match('(.*);"') or text -- remove ctag comments
@ -364,7 +379,7 @@ M.tag = function(opts, x)
local line, tag = text:match("(%d-);?(/.*/)")
line = line and #line>0 and tonumber(line)
return ("%s%s: %s %s"):format(
M.file(opts, file),
M.file(file, opts),
not line and "" or ":"..utils.ansi_codes.green(tostring(line)),
utils.ansi_codes.magenta(name),
utils.ansi_codes.green(tag))

@ -164,7 +164,6 @@ local grep_tag = function(file, tag)
else
utils.warn(("previewer: unable to find pattern '%s' in file '%s'"):format(pattern, file))
end
-- if line == 1 then print(cmd) end
return line
end

@ -2,7 +2,7 @@ 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 = {}
@ -143,11 +143,11 @@ local function gen_buffer_entry(opts, buf, hl_curbuf)
if opts.file_icons then
if utils.is_term_bufname(buf.info.name) then
-- get shell-like icon for terminal buffers
buficon, hl = core.get_devicon(buf.info.name, "sh")
buficon, hl = make_entry.get_devicon(buf.info.name, "sh")
else
local filename = path.tail(buf.info.name)
local extension = path.extension(filename)
buficon, hl = core.get_devicon(filename, extension)
buficon, hl = make_entry.get_devicon(filename, extension)
end
if opts.color_icons then
buficon = utils.ansi_codes[hl](buficon)
@ -193,13 +193,7 @@ M.buffers = function(opts)
opts = core.set_fzf_field_index(opts)
core.fzf_wrap(opts, contents, function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end)()
core.fzf_exec(contents, opts)
end
M.lines = function(opts)
@ -239,7 +233,7 @@ M.buffer_lines = function(opts)
if opts.file_icons then
local filename = path.tail(bufname)
local extension = path.extension(filename)
buficon, hl = core.get_devicon(filename, extension)
buficon, hl = make_entry.get_devicon(filename, extension)
if opts.color_icons then
buficon = utils.ansi_codes[hl](buficon)
end
@ -267,23 +261,7 @@ M.buffer_lines = function(opts)
opts = core.set_fzf_field_index(opts, 3, opts._is_skim and "{}" or "{..-2}")
core.fzf_wrap(opts, items, function(selected)
if not selected then return end
-- get the line number
local line = tonumber(selected[2]:match(":(%d+):"))
actions.act(opts.actions, selected, opts)
if line then
-- add current location to jumplist
local is_term = utils.is_term_buffer(0)
if not is_term then vim.cmd("normal! m`") end
vim.api.nvim_win_set_cursor(0, {line, 0})
if not is_term then vim.cmd("norm! zz") end
end
end)()
core.fzf_exec(items, opts)
end
M.tabs = function(opts)
@ -351,13 +329,7 @@ M.tabs = function(opts)
opts = core.set_fzf_field_index(opts, 3, "{}")
core.fzf_wrap(opts, contents, function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end)()
core.fzf_exec(contents, opts)
end
return M

@ -115,12 +115,7 @@ M.highlights = function(opts)
opts.fzf_opts['--no-multi'] = ''
core.fzf_wrap(opts, contents, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(contents, opts)
end
return M

@ -3,6 +3,7 @@ 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 _has_dap, _dap = nil, nil
@ -42,12 +43,7 @@ M.commands = function(opts)
opts.fzf_opts['--no-multi'] = ''
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
M.configurations = function(opts)
@ -83,12 +79,7 @@ M.configurations = function(opts)
opts.fzf_opts['--no-multi'] = ''
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
M.breakpoints = function(opts)
@ -133,14 +124,14 @@ M.breakpoints = function(opts)
local contents = function (cb)
local entries = {}
for _, entry in ipairs(opts._locations) do
table.insert(entries, core.make_entry_lcol(opts, entry))
table.insert(entries, make_entry.lcol(entry, opts))
end
for i, x in ipairs(entries) do
x = ("[%s] %s"):format(
-- tostring(opts._locations[i].bufnr),
utils.ansi_codes.yellow(tostring(opts._locations[i].bufnr)),
core.make_entry_file(opts, x))
make_entry.file(x, opts))
if x then
cb(x, function(err)
if err then return end
@ -160,12 +151,7 @@ M.breakpoints = function(opts)
opts = core.set_fzf_field_index(opts, 3, opts._is_skim and "{}" or "{..-2}")
core.fzf_wrap(opts, contents, function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end)()
core.fzf_exec(contents, opts)
end
@ -197,12 +183,7 @@ M.variables = function(opts)
end
end
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
@ -249,12 +230,7 @@ M.frames = function(opts)
opts.fzf_opts['--no-multi'] = ''
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end)()
core.fzf_exec(entries, opts)
end

@ -1,6 +1,7 @@
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 = {}
@ -39,7 +40,7 @@ M.files = function(opts)
opts.cmd = get_files_cmd(opts)
local contents = core.mt_cmd_wrapper(opts)
opts = core.set_header(opts, opts.headers or {"cwd"})
return core.fzf_files(opts, contents)
return core.fzf_exec(contents, opts)
end
M.args = function(opts)
@ -54,7 +55,7 @@ M.args = function(opts)
local contents = function (cb)
local function add_entry(x, co)
x = core.make_entry_file(opts, x)
x = make_entry.file(x, opts)
if not x then return end
cb(x, function(err)
coroutine.resume(co)
@ -89,14 +90,13 @@ M.args = function(opts)
-- end; print("took", os.time()-start, "seconds.")
-- done
cb(nil, function() coroutine.resume(co) end)
coroutine.yield()
cb(nil)
end)()
end
opts = core.set_header(opts, opts.headers or {"cwd"})
return core.fzf_files(opts, contents)
return core.fzf_exec(contents, opts)
end
return M

@ -2,9 +2,9 @@ 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 libuv = require "fzf-lua.libuv"
local shell = require "fzf-lua.shell"
local make_entry = require "fzf-lua.make_entry"
local M = {}
@ -23,7 +23,7 @@ M.files = function(opts)
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_files(opts, contents)
return core.fzf_exec(contents, opts)
end
M.status = function(opts)
@ -67,8 +67,8 @@ M.status = function(opts)
if f1:match("%s%->%s") then
f1, f2 = f1:match("(.*)%s%->%s(.*)")
end
f1 = f1 and core.make_entry_file(opts, f1)
f2 = f2 and core.make_entry_file(opts, f2)
f1 = f1 and make_entry.file(f1, opts)
f2 = f2 and make_entry.file(f2, opts)
local staged = git_iconify(x:sub(1,1):gsub("?", " "))
local unstaged = git_iconify(x:sub(2,2))
local entry = ("%s%s%s%s%s"):format(
@ -77,20 +77,17 @@ M.status = function(opts)
return entry
end,
function(o)
return core.make_entry_preprocess(o)
return make_entry.preprocess(o)
end)
opts = core.set_header(opts, opts.headers or {"cwd"})
return core.fzf_files(opts, contents)
return core.fzf_exec(contents, opts)
end
local function git_cmd(opts)
opts = set_git_cwd_args(opts)
if not opts.cwd then return end
opts = core.set_header(opts, opts.headers or {"cwd"})
core.fzf_wrap(opts, opts.cmd, function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end)()
core.fzf_exec(opts.cmd, opts)
end
M.commits = function(opts)

@ -53,7 +53,7 @@ local get_grep_cmd = function(opts, search_query, no_esc)
end
if opts.rg_glob then
local new_query, glob_args = make_entry.glob_parse(opts, search_query)
local new_query, glob_args = make_entry.glob_parse(search_query, opts)
if glob_args then
-- since the search string mixes both the query and
-- glob separators we cannot used unescaped strings
@ -126,9 +126,6 @@ M.grep = function(opts)
opts.search = utils.input(opts.input_prompt) or ''
end
-- search query in header line
opts = core.set_header(opts, opts.headers or {"actions","cwd","search"})
-- get the grep command before saving the last search
-- incase the search string is overwritten by 'rg_glob'
opts.cmd = get_grep_cmd(opts, opts.search, no_esc)
@ -163,8 +160,10 @@ M.grep = function(opts)
end
end
-- search query in header line
opts = core.set_header(opts, opts.headers or {"actions","cwd","search"})
opts = core.set_fzf_field_index(opts)
core.fzf_files(opts, contents)
core.fzf_exec(contents, opts)
end
-- single threaded version
@ -195,10 +194,7 @@ M.live_grep_st = function(opts)
set_last_search(opts, opts.query, true)
end
-- search query in header line
opts = core.set_header(opts, opts.headers or {"actions","cwd"})
opts._reload_command = function(query)
opts.fn_reload = function(query)
if query and not (opts.save_last_search == false) then
set_last_search(opts, query, true)
end
@ -209,9 +205,13 @@ 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 core.make_entry_file(opts, x)
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
@ -228,13 +228,10 @@ M.live_grep_st = function(opts)
end
end
-- disable global resume
-- conflicts with 'change:reload' event
opts.global_resume_query = false
opts.__FNCREF__ = opts.__FNCREF__ or utils.__FNCREF__()
-- search query in header line
opts = core.set_header(opts, opts.headers or {"actions","cwd"})
opts = core.set_fzf_field_index(opts)
opts = core.set_fzf_interactive_cmd(opts)
core.fzf_files(opts)
core.fzf_exec(nil, opts)
end
@ -264,29 +261,26 @@ M.live_grep_mt = function(opts)
opts.search, no_esc = get_last_search(opts)
end
local query = opts.search or ''
-- interactive interface uses 'query' parameter
opts.query = opts.search or ''
if opts.search and #opts.search>0 then
-- escape unless the user requested not to
if not (no_esc or opts.no_esc) then
query = utils.rg_escape(opts.search)
opts.query = utils.rg_escape(opts.search)
end
-- save the search query so the use can
-- call the same search again
set_last_search(opts, query, true)
set_last_search(opts, opts.query, true)
end
-- search query in header line
opts = core.set_header(opts, opts.headers or {"actions","cwd"})
-- signal to preprocess we are looking to replace {argvz}
opts.argv_expr = true
-- fzf already adds single quotes around the placeholder when expanding
-- for skim we surround it with double quotes or single quote searches fail
local placeholder = utils._if(opts._is_skim, '"{}"', '{q}')
opts.cmd = get_grep_cmd(opts , placeholder, 2)
local initial_command = core.mt_cmd_wrapper(opts)
if initial_command ~= opts.cmd then
-- this will be replaced by the approperiate fzf
-- FIELD INDEX EXPRESSION by 'fzf_exec'
opts.cmd = get_grep_cmd(opts , core.fzf_query_placeholder, 2)
local command = core.mt_cmd_wrapper(opts)
if command ~= opts.cmd then
-- this means mt_cmd_wrapper wrapped the command
-- since now the `rg` command is wrapped inside
-- the shell escaped '--headless .. --cmd' we won't
@ -297,41 +291,14 @@ M.live_grep_mt = function(opts)
-- * preprocess then relaces it with vim.fn.argv(1)
-- NOTE: since we cannot guarantee the positional index
-- of arguments (#291) we use the last argument instead
initial_command = initial_command:gsub(placeholder, "{argvz}")
.. " " .. placeholder
end
-- by redirecting the error stream to stdout
-- we make sure a clear error message is displayed
-- when the user enters bad regex expressions
initial_command = initial_command .. " 2>&1"
local reload_command = initial_command
if not opts.exec_empty_query then
reload_command = ('[ -z %s ] || %s'):format(placeholder, reload_command)
end
if opts._is_skim then
-- skim interactive mode does not need a piped command
opts.fzf_fn = nil
opts.fzf_opts['--prompt'] = opts.prompt:match("[^%*]+")
opts.fzf_opts['--cmd-prompt'] = vim.fn.shellescape(opts.prompt)
opts.prompt = nil
-- since we surrounded the skim placeholder with quotes
-- we need to escape them in the initial query
opts.fzf_opts['--cmd-query'] = libuv.shellescape(utils.sk_escape(query))
opts._fzf_cli_args = string.format("-i -c %s",
vim.fn.shellescape(reload_command))
else
opts.fzf_fn = {}
if opts.exec_empty_query or (opts.search and #opts.search > 0) then
opts.fzf_fn = initial_command:gsub(placeholder,
libuv.shellescape(query:gsub("%%", "%%%%")))
end
opts.fzf_opts['--phony'] = ''
opts.fzf_opts['--query'] = libuv.shellescape(query)
opts._fzf_cli_args = string.format('--bind=%s',
vim.fn.shellescape(("change:reload:%s"):format(
("%s || true"):format(reload_command))))
command = command:gsub(core.fzf_query_placeholder, "{argvz}")
.. " " .. core.fzf_query_placeholder
end
-- signal 'fzf_exec' to set 'change:reload' parameters
-- or skim's "interactive" mode (AKA "live query")
opts.fn_reload = command
-- when running 'live_grep' with 'exec_empty_query=false' (default)
-- an empty typed query will not be saved as the 'neovim --headless'
-- command isn't executed resulting in '_last_search.query' never
@ -359,13 +326,10 @@ M.live_grep_mt = function(opts)
end
end
-- disable global resume
-- conflicts with 'change:reload' event
opts.global_resume_query = false
opts.__FNCREF__ = opts.__FNCREF__ or utils.__FNCREF__()
-- search query in header line
opts = core.set_header(opts, opts.headers or {"actions","cwd"})
opts = core.set_fzf_field_index(opts)
core.fzf_files(opts)
opts.search = nil
core.fzf_exec(nil, opts)
end
M.live_grep_glob_st = function(opts)
@ -399,18 +363,12 @@ end
M.live_grep_native = function(opts)
-- backward compatibility, by setting git|files icons to false
-- we forces mt_cmd_wrapper to pipe the command as is so fzf
-- we force 'mt_cmd_wrapper' to pipe the command as is so fzf
-- runs the command directly in the 'change:reload' event
opts = opts or {}
opts.git_icons = false
opts.file_icons = false
opts.rg_glob = false
-- disable ctrl-g switch by default
if not opts.actions or not opts.actions["ctrl-g"] then
opts.actions = opts.actions or {}
opts.actions["ctrl-g"] = false
end
opts.__FNCREF__ = utils.__FNCREF__()
return M.live_grep_mt(opts)
end
@ -418,8 +376,6 @@ M.live_grep = function(opts)
opts = config.normalize_opts(opts, config.globals.grep)
if not opts then return end
opts.__FNCREF__ = opts.__FNCREF__ or utils.__FNCREF__()
if opts.multiprocess then
return M.live_grep_mt(opts)
else
@ -431,8 +387,6 @@ M.live_grep_glob = function(opts)
opts = config.normalize_opts(opts, config.globals.grep)
if not opts then return end
opts.__FNCREF__ = opts.__FNCREF__ or utils.__FNCREF__()
if opts.multiprocess then
return M.live_grep_glob_mt(opts)
else

@ -2,12 +2,11 @@ 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 actions = require "fzf-lua.actions"
local M = {}
local fzf_function = function (cb)
local fzf_fn = function (cb)
local opts = {}
opts.lang = config.globals.helptags.lang or vim.o.helplang
opts.fallback = utils._if(config.globals.helptags.fallback ~= nil, config.globals.helptags.fallback, true)
@ -82,11 +81,7 @@ local fzf_function = function (cb)
end
end
end
-- done, we can't call utils.delayed_cb here
-- because sleep() messes up the coroutine
-- cb(nil, function() coroutine.resume(co) end)
utils.delayed_cb(cb, function() coroutine.resume(co) end)
coroutine.yield()
cb(nil)
end)()
end
@ -96,18 +91,10 @@ M.helptags = function(opts)
opts = config.normalize_opts(opts, config.globals.helptags)
if not opts then return end
-- local prev_act = action(function (args) end)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview-window'] = 'hidden:right:0'
core.fzf_wrap(opts, fzf_function, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(fzf_fn, opts)
end

@ -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 make_entry = require "fzf-lua.make_entry"
local M = {}
@ -39,8 +39,8 @@ local function location_handler(opts, cb, _, result, ctx, _)
for _, entry in ipairs(items) do
if not opts.current_buffer_only or
vim.api.nvim_buf_get_name(opts.bufnr) == entry.filename then
entry = core.make_entry_lcol(opts, entry)
entry = core.make_entry_file(opts, entry)
entry = make_entry.lcol(entry, opts)
entry = make_entry.file(entry, opts)
if entry then
cb(entry, function(err)
if err then return end
@ -61,8 +61,8 @@ local function call_hierarchy_handler(opts, cb, _, result, _, _)
lnum = range.start.line + 1,
col = range.start.character + 1,
}
entry = core.make_entry_lcol(opts, entry)
entry = core.make_entry_file(opts, entry)
entry = make_entry.lcol(entry, opts)
entry = make_entry.file(entry, opts)
if entry then
cb(entry, function(err)
if err then return end
@ -88,8 +88,8 @@ local function symbol_handler(opts, cb, _, result, _, _)
entry.text = entry.text:gsub("%[.-%]", M._sym2style[kind])
end
end
entry = core.make_entry_lcol(opts, entry)
entry = core.make_entry_file(opts, entry)
entry = make_entry.lcol(entry, opts)
entry = make_entry.file(entry, opts)
if entry then
cb(entry, function(err)
if err then return end
@ -121,10 +121,10 @@ local function code_action_handler(opts, cb, _, code_actions, context, _)
end
end
local function diagnostics_handler(opts, cb, _, entry)
local function diagnostics_handler(opts, cb, co, entry)
local type = entry.type
entry = core.make_entry_lcol(opts, entry)
entry = core.make_entry_file(opts, entry)
entry = make_entry.lcol(entry, opts)
entry = make_entry.file(entry, opts)
if not entry then return end
if opts.lsp_icons and opts._severity_icons[type] then
local severity = opts._severity_icons[type]
@ -134,9 +134,7 @@ local function diagnostics_handler(opts, cb, _, entry)
end
entry = icon .. utils.nbsp .. utils.nbsp .. entry
end
cb(entry, function(err)
if err then return end
end)
cb(entry, function() coroutine.resume(co) end)
end
-- see neovim #15504
@ -181,7 +179,7 @@ local function wrap_handler(handler, opts, cb, co)
if opts.num_callbacks == opts.num_clients then
-- close the pipe to fzf, this
-- removes the loading indicator in fzf
utils.delayed_cb(cb)
cb(nil)
end
end
return ret
@ -275,15 +273,13 @@ local function set_lsp_fzf_fn(opts)
-- cancel all remaining LSP requests
-- once the user made their selection
-- or closed the fzf popup
opts.post_select_cb = function()
opts._fn_post_fzf = function()
if opts._cancel_all then
opts._cancel_all()
opts._cancel_all = nil
end
end
-- coroutine.yield()
end)()
end
@ -303,7 +299,6 @@ local normalize_lsp_opts = function(opts, cfg)
opts = config.normalize_opts(opts, cfg)
if not opts then return end
if not opts.cwd then opts.cwd = vim.loop.cwd() end
if not opts.prompt and opts.prompt_postfix then
opts.prompt = opts.lsp_handler.label .. (opts.prompt_postfix or '')
end
@ -327,7 +322,7 @@ local function fzf_lsp_locations(opts)
if opts.force_uri == nil then opts.force_uri = true end
opts = set_lsp_fzf_fn(opts)
if not opts.fzf_fn then return end
return core.fzf_files(opts)
return core.fzf_exec(opts.fzf_fn, opts)
end
-- define the functions for wrap_module_fncs
@ -441,7 +436,7 @@ M.document_symbols = function(opts)
opts.fn_pre_fzf = function() gen_sym2style_map(opts) end
opts.fn_post_fzf = function() M._sym2style = nil end
end
return core.fzf_files(opts)
return core.fzf_exec(opts.fzf_fn, opts)
end
M.workspace_symbols = function(opts)
@ -458,7 +453,7 @@ M.workspace_symbols = function(opts)
opts.fn_pre_fzf = function() gen_sym2style_map(opts) end
opts.fn_post_fzf = function() M._sym2style = nil end
end
return core.fzf_files(opts)
return core.fzf_exec(opts.fzf_fn, opts)
end
-- Converts 'vim.diagnostic.get' to legacy style 'get_line_diagnostics()'
@ -627,17 +622,7 @@ M.code_actions = function(opts)
opts.fzf_opts["--no-multi"] = ''
opts.fzf_opts["--preview-window"] = 'right:0'
core.fzf_wrap(opts, opts.fzf_fn, function(selected)
if opts.post_select_cb then
opts.post_select_cb()
end
if not selected then return end
actions.act(opts.actions, selected, opts)
end)()
core.fzf_exec(opts.fzf_fn, opts)
end
@ -761,7 +746,7 @@ M.diagnostics = function(opts)
return buffer_diag
end
opts.fzf_fn = function (cb)
opts.fzf_fn = function (fzf_cb)
coroutine.wrap(function ()
local co = coroutine.running()
@ -771,8 +756,13 @@ M.diagnostics = function(opts)
-- empty tables for unused buffers
if not vim.tbl_isempty(diag) then
if filter_diag_severity(opts, diag.severity) then
diagnostics_handler(opts, cb, co,
preprocess_diag(diag, bufnr))
-- wrap with 'vim.scheudle' or calls to vim.{fn|api} fail:
-- E5560: vimL function must not be called in a lua loop callback
vim.schedule(function()
diagnostics_handler(opts, fzf_cb, co, preprocess_diag(diag, bufnr))
end)
-- wait here for 'diagnostics_handler' to return
coroutine.yield()
end
end
end
@ -787,14 +777,14 @@ M.diagnostics = function(opts)
end
-- close the pipe to fzf, this
-- removes the loading indicator
cb(nil)
fzf_cb(nil)
end)()
end
opts = core.set_header(opts, opts.headers or {"cwd"})
opts = core.set_fzf_field_index(opts)
if opts.force_uri == nil then opts.force_uri = true end
return core.fzf_files(opts)
return core.fzf_exec(opts.fzf_fn, opts)
end
M.workspace_diagnostics = function(opts)
@ -826,7 +816,7 @@ M.live_workspace_symbols = function(opts)
opts.bufnr = vim.api.nvim_get_current_buf()
opts.winid = vim.api.nvim_get_current_win()
opts._reload_action = function(query)
opts.fn_reload = function(query)
if query and not (opts.save_last_query == false) then
last_search = { query = query }
config.__resume_data.last_query = query
@ -838,19 +828,13 @@ M.live_workspace_symbols = function(opts)
return opts.fzf_fn
end
-- disable global resume
-- conflicts with 'change:reload' event
opts.global_resume_query = false
opts.__FNCREF__ = M.live_workspace_symbols
opts = core.set_fzf_interactive_cb(opts)
opts = core.set_fzf_field_index(opts)
if opts.force_uri == nil then opts.force_uri = true 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
end
core.fzf_files(opts)
opts.search = nil
core.fzf_exec(nil, opts)
end
local function check_capabilities(feature)

@ -1,60 +1,25 @@
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 libuv = require "fzf-lua.libuv"
local M = {}
M.getmanpage = function(line)
--[[ -- extract section from the last pair of parentheses
local name, section = line:match("^(.*)%((.-)%)[^()]-$")
if name:sub(-1) == " " then
-- man-db
name = name:sub(1, -2)
else
-- mandoc
name = name:match("^[^, ]+")
section = section:match("^[^, ]+")
end
return name .. "(" .. section .. ")" ]]
return line:match("[^[,( ]+")
end
M.manpages = function(opts)
opts = config.normalize_opts(opts, config.globals.manpages)
if not opts then return end
local fzf_fn = libuv.spawn_nvim_fzf_cmd(
{ cmd = opts.cmd, cwd = opts.cwd, pid_cb = opts._pid_cb },
function(x)
-- split by first occurence of ' - ' (spaced hyphen)
local man, desc = x:match("^(.-) %- (.*)$")
return string.format("%-45s %s",
utils.ansi_codes.magenta(man), desc)
end)
opts.fn_transform = function(x)
-- split by first occurence of ' - ' (spaced hyphen)
local man, desc = x:match("^(.-) %- (.*)$")
return string.format("%-45s %s",
utils.ansi_codes.magenta(man), desc)
end
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview-window'] = 'hidden:right:0'
opts.fzf_opts['--tiebreak'] = 'begin'
opts.fzf_opts['--nth'] = '1,2'
core.fzf_wrap(opts, fzf_fn, function(selected)
if not selected then return end
if #selected > 1 then
for i = 2, #selected do
selected[i] = M.getmanpage(selected[i])
end
end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(opts.cmd, opts)
end
return M

@ -1,7 +1,6 @@
local core = require "fzf-lua.core"
local shell = require "fzf-lua.shell"
local config = require "fzf-lua.config"
local actions = require "fzf-lua.actions"
local M = {}
@ -35,13 +34,7 @@ M.metatable = function(opts)
-- as the behavior might confuse users (#267)
opts.global_resume = false
core.fzf_wrap(opts, methods, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(methods, opts)
end

@ -3,7 +3,7 @@ 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 make_entry = require "fzf-lua.make_entry"
local M = {}
@ -40,12 +40,7 @@ M.commands = function(opts)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview'] = prev_act
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
@ -64,12 +59,7 @@ local history = function(opts, str)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview-window'] = 'hidden:right:0'
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
local arg_header = function(sel_key, edit_key, text)
@ -119,12 +109,7 @@ M.jumps = function(opts)
opts.fzf_opts['--no-multi'] = ''
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end)()
core.fzf_exec(entries, opts)
end
M.tagstack = function(opts)
@ -154,12 +139,13 @@ M.tagstack = function(opts)
local entries = {}
for i, tag in ipairs(tags) do
local bufname = tag.filename
local bufname = path.HOME_to_tilde(
path.relative(tag.filename, vim.loop.cwd()))
local buficon, hl
if opts.file_icons then
local filename = path.tail(bufname)
local extension = path.extension(filename)
buficon, hl = core.get_devicon(filename, extension)
buficon, hl = make_entry.get_devicon(filename, extension)
if opts.color_icons then
buficon = utils.ansi_codes[hl](buficon)
end
@ -181,12 +167,7 @@ M.tagstack = function(opts)
opts.fzf_opts['--no-multi'] = ''
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected, opts)
end)()
core.fzf_exec(entries, opts)
end
@ -226,12 +207,7 @@ M.marks = function(opts)
-- opts.fzf_opts['--preview'] = prev_act
opts.fzf_opts['--no-multi'] = ''
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
M.registers = function(opts)
@ -285,12 +261,7 @@ M.registers = function(opts)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview'] = prev_act
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
M.keymaps = function(opts)
@ -343,12 +314,7 @@ M.keymaps = function(opts)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview'] = prev_act
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
M.spell_suggest = function(opts)
@ -365,12 +331,7 @@ M.spell_suggest = function(opts)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview-window'] = 'hidden:right:0'
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
@ -385,12 +346,7 @@ M.filetypes = function(opts)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview-window'] = 'hidden:right:0'
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
@ -406,12 +362,7 @@ M.packadd = function(opts)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview-window'] = 'hidden:right:0'
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end
@ -448,12 +399,7 @@ M.menus = function(opts)
opts.fzf_opts['--no-multi'] = ''
opts.fzf_opts['--preview-window'] = 'hidden:right:0'
core.fzf_wrap(opts, entries, function(selected)
if not selected then return end
actions.act(opts.actions, selected)
end)()
core.fzf_exec(entries, opts)
end

@ -1,5 +1,6 @@
local core = require "fzf-lua.core"
local config = require "fzf-lua.config"
local make_entry = require "fzf-lua.make_entry"
local M = {}
@ -29,14 +30,14 @@ M.oldfiles = function(opts)
local contents = function (cb)
local function add_entry(x, co)
x = core.make_entry_file(opts, x)
x = make_entry.file(x, opts)
if not x then return end
cb(x, function(err)
coroutine.resume(co)
if err then
-- close the pipe to fzf, this
-- removes the loading indicator in fzf
cb(nil, function() end)
cb(nil)
end
end)
coroutine.yield()
@ -60,14 +61,13 @@ M.oldfiles = function(opts)
-- end; print("took", os.time()-start, "seconds.")
-- done
cb(nil, function() coroutine.resume(co) end)
coroutine.yield()
cb(nil)
end)()
end
opts = core.set_header(opts, opts.headers or {"cwd"})
return core.fzf_files(opts, contents)
return core.fzf_exec(contents, opts)
end
return M

@ -1,6 +1,7 @@
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 = {}
@ -14,12 +15,12 @@ local quickfix_run = function(opts, cfg, locations)
if not opts.cwd then opts.cwd = vim.loop.cwd() end
for _, entry in ipairs(locations) do
table.insert(results, core.make_entry_lcol(opts, entry))
table.insert(results, make_entry.lcol(entry, opts))
end
local contents = function(cb)
for _, x in ipairs(results) do
x = core.make_entry_file(opts, x)
x = make_entry.file(x, opts)
if x then
cb(x, function(err)
if err then return end
@ -29,11 +30,11 @@ local quickfix_run = function(opts, cfg, locations)
end)
end
end
utils.delayed_cb(cb)
cb(nil)
end
opts = core.set_fzf_field_index(opts)
return core.fzf_files(opts, contents)
return core.fzf_exec(contents, opts)
end
M.quickfix = function(opts)

@ -76,7 +76,7 @@ local function tags(opts)
})
local ok, lines, err = pcall(utils.io_systemlist, cmd)
if ok and err == 0 and lines and not vim.tbl_isempty(lines) then
local tag, line = make_entry.tag(opts, lines[1])
local tag, line = make_entry.tag(lines[1], opts)
if tag and not line then
-- tags file does not contain lines
-- remove preview offset field index
@ -87,8 +87,11 @@ local function tags(opts)
-- prevents 'file|git_icons=false' from overriding processing
opts.requires_processing = true
opts._fn_transform = make_entry.tag -- multiprocess=false
opts._fn_transform_str = [[return require("make_entry").tag]] -- multiprocess=true
if opts.multiprocess then
opts.__mt_transform = [[return require("make_entry").tag]]
else
opts.__mt_transform = make_entry.tag
end
if opts.lgrep then
-- live_grep requested by caller ('tags_live_grep')
@ -101,9 +104,9 @@ local function tags(opts)
if opts.multiprocess then
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(opts, x)
-- '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)
end
@ -159,7 +162,6 @@ M.live_grep = function(opts)
opts = config.normalize_opts(opts, config.globals.tags)
if not opts then return end
opts.lgrep = true
opts.__FNCREF__ = utils.__FNCREF__()
return tags(opts)
end

@ -37,9 +37,14 @@ function M.raw_async_action(fn, fzf_field_expression, debug)
local pipe = uv.new_pipe(false)
local args = {...}
uv.pipe_connect(pipe, pipe_path, function(err)
vim.schedule(function ()
fn(pipe, unpack(args))
end)
if err then
error(string.format("pipe_connect(%s) failed with error: %s",
pipe_path, err))
else
vim.schedule(function ()
fn(pipe, unpack(args))
end)
end
end)
end
@ -131,45 +136,134 @@ end
M.reload_action_cmd = function(opts, fzf_field_expression)
local _pid = nil
if opts.fn_preprocess and type(opts.fn_preprocess) == 'function' then
-- run the preprocessing fn
opts = vim.tbl_deep_extend("keep", opts, opts.fn_preprocess(opts))
end
return M.raw_async_action(function(pipe, args)
local function on_pid(pid)
_pid = pid
if opts.pid_cb then
opts.pid_cb(pid)
end
end
local function on_finish(_, _)
if pipe and not uv.is_closing(pipe) then
-- get the type of contents from the caller
local reload_contents = opts.__fn_reload(args[1])
local write_cb_count = 0
local pipe_want_close = false
-- 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
pipe_want_close = true
if write_cb_count==0 then
-- only close if all our uv.write calls are completed
uv.close(pipe)
pipe = nil
end
end
local function on_write(data, cb)
if not pipe then
cb(true)
local on_write = function(data, cb, co)
-- pipe can be nil when using a shell command with spawn
-- and typing quickly, the process will terminate and
assert(not co or (co and pipe and not uv.is_closing(pipe)))
if not pipe then return end
if not data then
on_finish(nil, nil, 5)
if cb then cb(nil) end
else
uv.write(pipe, data, cb)
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 err then
-- force close on error
write_cb_count = 0
on_finish(nil, nil, 2)
end
if write_cb_count == 0 and pipe_want_close then
on_finish(nil, nil, 3)
end
end)
-- yield returns when uv.write compeletes
-- or when a new coroutine calls resume(1)
if co and coroutine.yield() == 1 then
-- we have a new routine in opts.__co, this
-- routine is no longer relevant so kill it
write_cb_count = 0
on_finish(nil, nil, 4)
end
end
end
-- terminate previously running commands
libuv.process_kill(_pid)
if type(reload_contents) == 'string' then
-- string will be used as a shell command
-- terminate previously running commands
libuv.process_kill(opts.__pid)
opts.__pid = nil
-- return libuv.spawn({
return libuv.async_spawn({
-- spawn/async_spawn already async, no need to send opts.__co
-- also, we can't call coroutine.yield inside a libuv callback
-- due to: "attempt to yield across C-call boundary"
libuv.async_spawn({
cwd = opts.cwd,
cmd = opts._reload_command(args[1]),
cmd = reload_contents,
cb_finish = on_finish,
cb_write = on_write,
cb_pid = on_pid,
cb_pid = function(pid) opts.__pid = pid end,
-- must send false, 'coroutinify' adds callback as last argument
-- which will conflict with the 'fn_transform' argument
}, opts._fn_transform or false)
}, opts.__fn_transform or false)
else
-- table or function runs in a coroutine
-- which isn't required for 'libuv.spawn'
coroutine.wrap(function()
if opts.__co then
local costatus = coroutine.status(opts.__co)
if costatus ~= 'dead' then
-- the previous routine is either 'running' or 'suspended'
-- return 1 from yield to signal abort to 'on_write'
coroutine.resume(opts.__co, 1)
end
assert(coroutine.status(opts.__co) == 'dead')
end
-- reset var to current running routine
opts.__co = coroutine.running()
-- callback with newline
local on_write_nl = function(data, cb)
data = data and tostring(data) .. "\n" or nil
return on_write(data, cb)
end
-- callback with newline and coroutine
local on_write_nl_co = function(data, cb)
data = data and tostring(data) .. "\n" or nil
return on_write(data, cb, opts.__co)
end
-- callback with coroutine (no NL)
local on_write_co = function(data, cb)
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)
end
on_finish()
elseif type(reload_contents) == 'function' then
-- by default we use the async callbacks
if opts.func_async_callback ~= false then
reload_contents(on_write_nl_co, on_write_co)
else
reload_contents(on_write_nl, on_write)
end
else
end
end)()
end
end, fzf_field_expression, opts.debug)
end

@ -413,17 +413,6 @@ function M.feed_keys_termcodes(key)
vim.api.nvim_replace_termcodes(key, true, false, true), 'n', true)
end
function M.delayed_cb(cb, fn)
-- HACK: slight delay to prevent missing results
-- otherwise the input stream closes too fast
-- sleep was causing all sorts of issues
-- vim.cmd("sleep! 10m")
if fn == nil then fn = function() end end
vim.defer_fn(function()
cb(nil, fn)
end, 20)
end
function M.is_term_bufname(bufname)
if bufname and bufname:match("term://") then return true end
return false
@ -590,8 +579,8 @@ function M.io_systemlist(cmd, use_lua_io)
-- last line contains the exit status
rc = tonumber(stdout[#stdout])
stdout[#stdout] = nil
handle:close()
end
handle:close()
return stdout, rc
else
return vim.fn.systemlist(cmd), vim.v.shell_error

@ -29,7 +29,9 @@ function FzfWin.save_query(key)
local query = lines[1]:gsub("^%*+", "")
:gsub("^"..utils.lua_escape(self.prompt:match("[^%*]+")), "")
-- remove '--info=inline'
query = query and query:gsub("<%s%d+/%d+.*$", "")
query = query and query:gsub("[<%-]%s%d+/%d+.*$", "")
-- remove '< [Command failed: ...]
query = query and query:gsub("<%s%[Command failed:.*$", "")
-- trim whitespaces at the end
query = query and query:gsub("%s*$", "")
if self.fn_save_query then

Loading…
Cancel
Save