2021-07-11 03:16:57 +00:00
|
|
|
if not pcall(require, "fzf") then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local fzf_helpers = require("fzf.helpers")
|
|
|
|
local path = require "fzf-lua.path"
|
|
|
|
local core = require "fzf-lua.core"
|
|
|
|
local utils = require "fzf-lua.utils"
|
|
|
|
local config = require "fzf-lua.config"
|
|
|
|
|
2021-09-05 10:17:53 +00:00
|
|
|
local last_search = {}
|
|
|
|
|
2021-07-11 03:16:57 +00:00
|
|
|
local M = {}
|
|
|
|
|
2021-07-23 04:34:12 +00:00
|
|
|
local get_grep_cmd = function(opts, search_query, no_esc)
|
2021-08-16 21:56:50 +00:00
|
|
|
if opts.raw_cmd and #opts.raw_cmd>0 then
|
|
|
|
return opts.raw_cmd
|
|
|
|
end
|
2021-07-11 03:16:57 +00:00
|
|
|
local command = nil
|
|
|
|
if opts.cmd and #opts.cmd > 0 then
|
|
|
|
command = opts.cmd
|
|
|
|
elseif vim.fn.executable("rg") == 1 then
|
|
|
|
command = string.format("rg %s", opts.rg_opts)
|
|
|
|
else
|
|
|
|
command = string.format("grep %s", opts.grep_opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- filename takes precedence over directory
|
2021-08-16 22:44:48 +00:00
|
|
|
-- filespec takes precedence over all and doesn't shellescape
|
|
|
|
-- this is so user can send a file populating command instead
|
2021-07-11 03:16:57 +00:00
|
|
|
local search_path = ''
|
2021-08-16 22:44:48 +00:00
|
|
|
if opts.filespec and #opts.filespec>0 then
|
|
|
|
search_path = opts.filespec
|
|
|
|
elseif opts.filename and #opts.filename>0 then
|
2021-07-11 03:16:57 +00:00
|
|
|
search_path = vim.fn.shellescape(opts.filename)
|
|
|
|
end
|
|
|
|
|
2021-09-07 01:56:17 +00:00
|
|
|
search_query = search_query or ''
|
|
|
|
if not (no_esc or opts.no_esc) then
|
|
|
|
search_query = utils.rg_escape(search_query)
|
2021-07-23 04:34:12 +00:00
|
|
|
end
|
2021-09-07 08:22:08 +00:00
|
|
|
|
|
|
|
-- do not escape at all
|
|
|
|
if not (no_esc == 2 or opts.no_esc == 2) then
|
|
|
|
search_query = vim.fn.shellescape(search_query)
|
|
|
|
end
|
2021-07-23 04:34:12 +00:00
|
|
|
|
2021-08-17 00:51:20 +00:00
|
|
|
return string.format('%s %s %s', command, search_query, search_path)
|
|
|
|
end
|
|
|
|
|
2021-09-08 00:37:08 +00:00
|
|
|
local function set_search_header(opts, type)
|
2021-08-17 00:51:20 +00:00
|
|
|
if not opts then opts = {} end
|
|
|
|
if opts.no_header then return opts end
|
2021-09-08 00:37:08 +00:00
|
|
|
if not opts.cwd_header then opts.cwd_header = "cwd:" end
|
2021-08-17 00:51:20 +00:00
|
|
|
if not opts.search_header then opts.search_header = "Searching for:" end
|
2021-09-08 00:37:08 +00:00
|
|
|
local header_str
|
|
|
|
local cwd_str = opts.cwd and ("%s %s"):format(opts.cwd_header, opts.cwd)
|
|
|
|
local search_str = opts.search and #opts.search > 0 and
|
|
|
|
("%s %s"):format(opts.search_header, opts.search)
|
|
|
|
-- 1: only search
|
|
|
|
-- 2: only cwd
|
|
|
|
-- otherwise, all
|
|
|
|
if type == 1 and search_str then header_str = search_str
|
|
|
|
elseif type == 2 and cwd_str then header_str = cwd_str
|
|
|
|
else
|
|
|
|
header_str = search_str or ''
|
|
|
|
if #header_str>0 and cwd_str and #cwd_str>0 then
|
|
|
|
header_str = header_str .. ", "
|
|
|
|
end
|
|
|
|
header_str = header_str .. (cwd_str or '')
|
|
|
|
end
|
2021-09-08 04:11:03 +00:00
|
|
|
if not header_str or #header_str==0 then return opts end
|
2021-09-08 00:37:08 +00:00
|
|
|
opts._fzf_header_args = opts._fzf_header_args or ''
|
|
|
|
opts._fzf_header_args = string.format([[%s --header=%s ]],
|
|
|
|
opts._fzf_header_args,
|
|
|
|
vim.fn.shellescape(header_str))
|
2021-08-17 00:51:20 +00:00
|
|
|
return opts
|
2021-07-11 03:16:57 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
M.grep = function(opts)
|
|
|
|
|
2021-07-27 01:08:26 +00:00
|
|
|
opts = config.normalize_opts(opts, config.globals.grep)
|
2021-09-04 22:02:34 +00:00
|
|
|
if not opts then return end
|
2021-07-11 03:16:57 +00:00
|
|
|
|
2021-09-05 10:17:53 +00:00
|
|
|
local no_esc = false
|
2021-07-23 04:34:12 +00:00
|
|
|
if opts.continue_last_search or opts.repeat_last_search then
|
2021-09-05 10:17:53 +00:00
|
|
|
no_esc = last_search.no_esc
|
|
|
|
opts.search = last_search.query
|
2021-07-11 03:16:57 +00:00
|
|
|
end
|
2021-07-23 04:34:12 +00:00
|
|
|
|
|
|
|
-- if user did not provide a search term
|
|
|
|
-- provide an input prompt
|
2021-09-07 08:51:51 +00:00
|
|
|
if not opts.search then
|
|
|
|
opts.search = vim.fn.input(opts.input_prompt) or ''
|
2021-07-11 03:16:57 +00:00
|
|
|
end
|
2021-07-23 04:34:12 +00:00
|
|
|
|
2021-09-07 08:51:51 +00:00
|
|
|
--[[ if not opts.search or #opts.search == 0 then
|
2021-07-23 04:34:12 +00:00
|
|
|
utils.info("Please provide a valid search string")
|
2021-07-11 03:16:57 +00:00
|
|
|
return
|
2021-09-07 08:51:51 +00:00
|
|
|
end ]]
|
2021-07-11 03:16:57 +00:00
|
|
|
|
2021-08-17 00:51:20 +00:00
|
|
|
-- search query in header line
|
|
|
|
opts = set_search_header(opts)
|
|
|
|
|
2021-07-23 04:34:12 +00:00
|
|
|
-- save the search query so the use can
|
|
|
|
-- call the same search again
|
2021-09-05 10:17:53 +00:00
|
|
|
last_search = {}
|
|
|
|
last_search.no_esc = no_esc or opts.no_esc
|
|
|
|
last_search.query = opts.search
|
2021-07-23 04:34:12 +00:00
|
|
|
|
2021-09-07 01:56:17 +00:00
|
|
|
local command = get_grep_cmd(opts, opts.search, no_esc)
|
2021-07-11 03:16:57 +00:00
|
|
|
|
|
|
|
opts.fzf_fn = fzf_helpers.cmd_line_transformer(
|
2021-09-07 23:59:13 +00:00
|
|
|
{cmd = command, cwd = opts.cwd},
|
2021-07-11 03:16:57 +00:00
|
|
|
function(x)
|
|
|
|
return core.make_entry_file(opts, x)
|
|
|
|
end)
|
|
|
|
|
|
|
|
--[[ opts.cb_selected = function(_, x)
|
|
|
|
return x
|
|
|
|
end ]]
|
|
|
|
|
2021-08-03 22:43:51 +00:00
|
|
|
opts = core.set_fzf_line_args(opts)
|
2021-07-11 03:16:57 +00:00
|
|
|
core.fzf_files(opts)
|
2021-07-23 04:34:12 +00:00
|
|
|
opts.search = nil
|
2021-07-11 03:16:57 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
M.live_grep = function(opts)
|
|
|
|
|
2021-07-27 01:08:26 +00:00
|
|
|
opts = config.normalize_opts(opts, config.globals.grep)
|
2021-09-04 22:02:34 +00:00
|
|
|
if not opts then return end
|
2021-07-11 03:16:57 +00:00
|
|
|
|
2021-09-05 10:17:53 +00:00
|
|
|
local no_esc = false
|
2021-07-23 04:34:12 +00:00
|
|
|
if opts.continue_last_search or opts.repeat_last_search then
|
2021-09-05 10:17:53 +00:00
|
|
|
no_esc = last_search.no_esc
|
|
|
|
opts.search = last_search.query
|
|
|
|
end
|
|
|
|
|
|
|
|
opts._live_query = opts.search or ''
|
|
|
|
if opts.search and #opts.search>0 then
|
|
|
|
-- save the search query so the use can
|
|
|
|
-- call the same search again
|
|
|
|
last_search = {}
|
|
|
|
last_search.no_esc = true
|
|
|
|
last_search.query = opts.search
|
|
|
|
-- escape unless the user requested not to
|
2021-09-07 01:56:17 +00:00
|
|
|
if not (no_esc or opts.no_esc) then
|
2021-09-05 10:17:53 +00:00
|
|
|
opts._live_query = utils.rg_escape(opts.search)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-08 00:37:08 +00:00
|
|
|
-- search query in header line
|
|
|
|
opts = set_search_header(opts, 2)
|
|
|
|
|
2021-09-05 10:17:53 +00:00
|
|
|
opts._cb_live_cmd = function(query)
|
|
|
|
if query and #query>0 and not opts.do_not_save_last_search then
|
|
|
|
last_search = {}
|
|
|
|
last_search.no_esc = true
|
|
|
|
last_search.query = query
|
|
|
|
end
|
|
|
|
-- can be nill when called as fzf initial command
|
|
|
|
query = query or ''
|
|
|
|
-- TODO: need to empty filespec
|
|
|
|
-- fix this collision, rename to _filespec
|
|
|
|
opts.no_esc = nil
|
|
|
|
opts.filespec = nil
|
2021-09-07 01:56:17 +00:00
|
|
|
return get_grep_cmd(opts, query, true)
|
2021-09-05 10:17:53 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
core.fzf_files_interactive(opts)
|
|
|
|
end
|
|
|
|
|
2021-09-07 23:59:13 +00:00
|
|
|
M.live_grep_native = function(opts)
|
2021-09-05 10:17:53 +00:00
|
|
|
|
|
|
|
opts = config.normalize_opts(opts, config.globals.grep)
|
|
|
|
if not opts then return end
|
|
|
|
|
|
|
|
local no_esc = false
|
|
|
|
if opts.continue_last_search or opts.repeat_last_search then
|
|
|
|
no_esc = last_search.no_esc
|
|
|
|
opts.search = last_search.query
|
2021-07-23 04:34:12 +00:00
|
|
|
end
|
|
|
|
|
2021-09-04 22:02:34 +00:00
|
|
|
local query = opts.search or ''
|
2021-07-16 17:39:02 +00:00
|
|
|
if opts.search and #opts.search>0 then
|
2021-07-23 04:34:12 +00:00
|
|
|
-- save the search query so the use can
|
|
|
|
-- call the same search again
|
2021-09-05 10:17:53 +00:00
|
|
|
last_search = {}
|
2021-09-08 04:11:03 +00:00
|
|
|
last_search.no_esc = no_esc or opts.no_esc
|
2021-09-05 10:17:53 +00:00
|
|
|
last_search.query = opts.search
|
2021-09-04 22:02:34 +00:00
|
|
|
-- escape unless the user requested not to
|
2021-09-07 01:56:17 +00:00
|
|
|
if not (no_esc or opts.no_esc) then
|
2021-09-05 10:17:53 +00:00
|
|
|
query = utils.rg_escape(opts.search)
|
|
|
|
end
|
2021-07-16 17:39:02 +00:00
|
|
|
end
|
|
|
|
|
2021-09-08 00:37:08 +00:00
|
|
|
-- search query in header line
|
|
|
|
opts = set_search_header(opts, 2)
|
|
|
|
|
2021-09-07 23:59:13 +00:00
|
|
|
-- 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 initial_command = get_grep_cmd(opts , placeholder, 2)
|
|
|
|
local reload_command = initial_command
|
|
|
|
if not opts.exec_empty_query then
|
|
|
|
reload_command = ('[ -z %s ] || %s'):format(placeholder, reload_command)
|
|
|
|
end
|
2021-09-04 22:02:34 +00:00
|
|
|
if opts._is_skim then
|
|
|
|
-- skim interactive mode does not need a piped command
|
|
|
|
opts.fzf_fn = nil
|
|
|
|
opts._fzf_cli_args = string.format(
|
2021-09-07 01:56:17 +00:00
|
|
|
"--prompt='*%s' --cmd-prompt='%s' --cmd-query=%s -i -c %s",
|
|
|
|
opts.prompt, opts.prompt,
|
2021-09-07 08:22:08 +00:00
|
|
|
-- since we surrounded the skim placeholder with quotes
|
|
|
|
-- we need to escape them in the initial query
|
2021-09-08 06:20:54 +00:00
|
|
|
vim.fn.shellescape(utils.sk_escape(query)),
|
2021-09-07 23:59:13 +00:00
|
|
|
vim.fn.shellescape(
|
|
|
|
("(cd %s && %s)"):format(
|
|
|
|
vim.fn.shellescape(opts.cwd or '.'),
|
2021-09-08 04:31:36 +00:00
|
|
|
reload_command)))
|
2021-09-04 22:02:34 +00:00
|
|
|
else
|
2021-09-05 02:40:18 +00:00
|
|
|
opts.fzf_fn = {}
|
2021-09-04 22:02:34 +00:00
|
|
|
if opts.exec_empty_query or (opts.search and #opts.search > 0) then
|
2021-09-05 02:40:18 +00:00
|
|
|
opts.fzf_fn = fzf_helpers.cmd_line_transformer(
|
2021-09-07 23:59:13 +00:00
|
|
|
{cmd = initial_command:gsub(placeholder, vim.fn.shellescape(query)),
|
|
|
|
cwd = opts.cwd},
|
2021-09-04 22:02:34 +00:00
|
|
|
function(x)
|
2021-09-05 02:40:18 +00:00
|
|
|
return core.make_entry_file(opts, x)
|
2021-09-04 22:02:34 +00:00
|
|
|
end)
|
2021-09-05 02:40:18 +00:00
|
|
|
end
|
2021-09-07 01:56:17 +00:00
|
|
|
opts._fzf_cli_args = string.format('--phony --query=%s --bind=%s',
|
|
|
|
vim.fn.shellescape(query),
|
|
|
|
vim.fn.shellescape(("change:reload:%s"):format(
|
2021-09-07 23:59:13 +00:00
|
|
|
("(cd %s && %s || true)"):format(
|
|
|
|
vim.fn.shellescape(opts.cwd or '.'),
|
|
|
|
reload_command))))
|
2021-09-04 11:28:29 +00:00
|
|
|
end
|
|
|
|
|
2021-09-04 22:02:34 +00:00
|
|
|
-- we cannot parse any entries as they're not getting called
|
|
|
|
-- past the initial command, until I can find a solution for
|
|
|
|
-- that icons must be disabled
|
2021-07-11 03:16:57 +00:00
|
|
|
opts.git_icons = false
|
|
|
|
opts.file_icons = false
|
|
|
|
|
2021-08-03 22:43:51 +00:00
|
|
|
opts = core.set_fzf_line_args(opts)
|
2021-07-11 03:16:57 +00:00
|
|
|
core.fzf_files(opts)
|
2021-07-23 04:34:12 +00:00
|
|
|
opts.search = nil
|
2021-07-11 03:16:57 +00:00
|
|
|
end
|
|
|
|
|
2021-09-04 22:02:34 +00:00
|
|
|
M.live_grep_sk = function(opts)
|
|
|
|
if not opts then opts = {} end
|
|
|
|
opts.fzf_bin = "sk"
|
|
|
|
M.live_grep(opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
M.live_grep_fzf = function(opts)
|
|
|
|
if not opts then opts = {} end
|
|
|
|
opts.fzf_bin = "fzf"
|
|
|
|
M.live_grep(opts)
|
|
|
|
end
|
2021-07-30 18:21:23 +00:00
|
|
|
|
2021-09-05 10:50:08 +00:00
|
|
|
M.live_grep_resume = function(opts)
|
|
|
|
if not opts then opts = {} end
|
|
|
|
opts.continue_last_search = true
|
|
|
|
return M.live_grep(opts)
|
|
|
|
end
|
|
|
|
|
2021-07-11 03:16:57 +00:00
|
|
|
M.grep_last = function(opts)
|
|
|
|
if not opts then opts = {} end
|
2021-07-23 04:34:12 +00:00
|
|
|
opts.continue_last_search = true
|
2021-07-11 03:16:57 +00:00
|
|
|
return M.grep(opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
M.grep_cword = function(opts)
|
|
|
|
if not opts then opts = {} end
|
|
|
|
opts.search = vim.fn.expand("<cword>")
|
|
|
|
return M.grep(opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
M.grep_cWORD = function(opts)
|
|
|
|
if not opts then opts = {} end
|
|
|
|
opts.search = vim.fn.expand("<cWORD>")
|
|
|
|
return M.grep(opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
M.grep_visual = function(opts)
|
|
|
|
if not opts then opts = {} end
|
|
|
|
opts.search = utils.get_visual_selection()
|
|
|
|
return M.grep(opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
M.grep_curbuf = function(opts)
|
|
|
|
if not opts then opts = {} end
|
2021-07-27 01:08:26 +00:00
|
|
|
opts.rg_opts = config.globals.grep.rg_opts .. " --with-filename"
|
2021-08-31 17:00:44 +00:00
|
|
|
opts.grep_opts = config.globals.grep.grep_opts .. " --with-filename"
|
2021-09-05 02:40:18 +00:00
|
|
|
if opts.exec_empty_query == nil then
|
|
|
|
opts.exec_empty_query = true
|
|
|
|
end
|
2021-07-11 03:16:57 +00:00
|
|
|
opts.filename = vim.api.nvim_buf_get_name(0)
|
|
|
|
if #opts.filename > 0 then
|
|
|
|
opts.filename = path.relative(opts.filename, vim.loop.cwd())
|
|
|
|
return M.live_grep(opts)
|
|
|
|
else
|
|
|
|
utils.info("Rg current buffer requires actual file on disk")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return M
|