normaize fzf FIELD INDEX EXPRESSION, see below:

- refactor fzf field index experssion and line field number options
- enable native fzf previewers (bat/cat/head) for all file/buffer providers
- buffers|lines|blines|tabs now respect default previewer
This commit is contained in:
bhagwan 2022-02-11 23:02:53 -08:00
parent 027068511a
commit 9a0f625804
12 changed files with 85 additions and 53 deletions

View File

@ -586,7 +586,7 @@ require'fzf-lua'.setup {
fzf_opts = { fzf_opts = {
-- do not include bufnr in fuzzy matching -- do not include bufnr in fuzzy matching
-- tiebreak by line no. -- tiebreak by line no.
['--delimiter'] = vim.fn.shellescape('[]]'), ['--delimiter'] = vim.fn.shellescape('[\\]:]'),
["--nth"] = '2..', ["--nth"] = '2..',
["--tiebreak"] = 'index', ["--tiebreak"] = 'index',
}, },

View File

@ -628,7 +628,7 @@ Consult the list below for available settings:
fzf_opts = { fzf_opts = {
-- do not include bufnr in fuzzy matching -- do not include bufnr in fuzzy matching
-- tiebreak by line no. -- tiebreak by line no.
['--delimiter'] = vim.fn.shellescape('[]]'), ['--delimiter'] = vim.fn.shellescape('[\\]:]'),
["--nth"] = '2..', ["--nth"] = '2..',
["--tiebreak"] = 'index', ["--tiebreak"] = 'index',
}, },

View File

@ -169,6 +169,10 @@ M.globals = {
cmd = "man -c %s | col -bx", cmd = "man -c %s | col -bx",
_ctor = previewers.builtin.man_pages, _ctor = previewers.builtin.man_pages,
}, },
man_native = {
cmd = "man",
_ctor = previewers.fzf.man_pages,
},
builtin = { builtin = {
syntax = true, syntax = true,
syntax_delay = 0, syntax_delay = 0,
@ -309,7 +313,7 @@ M.globals.loclist = {
_actions = function() return M.globals.actions.files end, _actions = function() return M.globals.actions.files end,
} }
M.globals.buffers = { M.globals.buffers = {
previewer = "builtin", previewer = M._default_previewer_fn,
prompt = 'Buffers> ', prompt = 'Buffers> ',
file_icons = true and M._has_devicons, file_icons = true and M._has_devicons,
color_icons = true, color_icons = true,
@ -323,7 +327,7 @@ M.globals.buffers = {
}, },
} }
M.globals.tabs = { M.globals.tabs = {
previewer = "builtin", previewer = M._default_previewer_fn,
prompt = 'Tabs> ', prompt = 'Tabs> ',
tab_title = "Tab", tab_title = "Tab",
tab_marker = "<<", tab_marker = "<<",
@ -336,21 +340,21 @@ M.globals.tabs = {
}, },
} }
M.globals.lines = { M.globals.lines = {
previewer = "builtin", previewer = M._default_previewer_fn,
prompt = 'Lines> ', prompt = 'Lines> ',
file_icons = true and M._has_devicons, file_icons = true and M._has_devicons,
color_icons = true, color_icons = true,
show_unlisted = false, show_unlisted = false,
no_term_buffers = true, no_term_buffers = true,
fzf_opts = { fzf_opts = {
['--delimiter'] = vim.fn.shellescape('[]]'), ['--delimiter'] = vim.fn.shellescape('[\\]:]'),
["--nth"] = '2..', ["--nth"] = '2..',
["--tiebreak"] = 'index', ["--tiebreak"] = 'index',
}, },
_actions = function() return M.globals.actions.buffers end, _actions = function() return M.globals.actions.buffers end,
} }
M.globals.blines = { M.globals.blines = {
previewer = "builtin", previewer = M._default_previewer_fn,
prompt = 'BLines> ', prompt = 'BLines> ',
file_icons = true and M._has_devicons, file_icons = true and M._has_devicons,
color_icons = true, color_icons = true,
@ -540,7 +544,7 @@ M.globals.dap = {
previewer = M._default_previewer_fn, previewer = M._default_previewer_fn,
_actions = function() return M.globals.actions.files end, _actions = function() return M.globals.actions.files end,
fzf_opts = { fzf_opts = {
['--delimiter'] = vim.fn.shellescape('[]]'), ['--delimiter'] = vim.fn.shellescape('[\\]:]'),
["--with-nth"] = '2..', ["--with-nth"] = '2..',
}, },
}, },

View File

@ -416,8 +416,22 @@ M.make_entry_lcol = function(opts, entry)
(opts.trim_entry and vim.trim(entry.text)) or entry.text) (opts.trim_entry and vim.trim(entry.text)) or entry.text)
end end
M.set_fzf_line_args = function(opts) -- given the default delimiter ':' this is the
opts._line_placeholder = 2 -- fzf experssion field index for the line number
-- when entry format is 'file:line:col: text'
-- this is later used with native fzf previewers
-- for setting the preview offset (and on some
-- cases the highlighted line)
M.set_fzf_field_index = function(opts, default_idx, default_expr)
opts.line_field_index = opts.line_field_index or default_idx or 2
-- when entry contains lines we set the fzf FIELD INDEX EXPRESSION
-- to the below so that only the filename is sent to the preview
-- action, otherwise we will have issues with entries with text
-- containing '--' as fzf won't know how to interpret the cmd
-- this works when the delimiter is only ':', when using multiple
-- or different delimiters (e.g. in 'lines') we need to use a different
-- field index experssion such as "{..-2}" (all fields but the last 2)
opts.field_index_expr = opts.field_index_expr or default_expr or "{1}"
return opts return opts
end end

View File

@ -210,6 +210,8 @@ function M.entry_to_file(entry, cwd, force_uri)
return { return {
stripped = stripped, stripped = stripped,
bufnr = 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, terminal = terminal,
path = file, path = file,
line = tonumber(line) or 1, line = tonumber(line) or 1,

View File

@ -34,13 +34,13 @@ function Previewer.base:preview_offset()
# #
'--preview-window '~3:+{2}+3/2'' '--preview-window '~3:+{2}+3/2''
]] ]]
if self.opts._line_placeholder then if self.opts.line_field_index then
return ("+{%d}-/2"):format(self.opts._line_placeholder) return ("+{%d}-/2"):format(self.opts.line_field_index)
end end
end end
function Previewer.base:fzf_delimiter() function Previewer.base:fzf_delimiter()
if not self.opts._line_placeholder then return end if not self.opts.line_field_index then return end
-- set delimiter to ':' -- set delimiter to ':'
-- entry format is 'file:line:col: text' -- entry format is 'file:line:col: text'
local delim = self.opts.fzf_opts and self.opts.fzf_opts["--delimiter"] local delim = self.opts.fzf_opts and self.opts.fzf_opts["--delimiter"]
@ -50,7 +50,9 @@ function Previewer.base:fzf_delimiter()
if delim:match("%[.*%]")then if delim:match("%[.*%]")then
delim = delim:match("(%[.*)%]") .. ':]' delim = delim:match("(%[.*)%]") .. ':]'
else else
delim = '[' .. delim:match("[^[^']+") .. ':]' delim = '[' ..
utils.rg_escape(delim:match("^'?(.*)'$?")):gsub("%]", "\\]")
.. ':]'
end end
end end
return delim return delim
@ -73,15 +75,11 @@ end
function Previewer.cmd:action(o) function Previewer.cmd:action(o)
o = o or {} o = o or {}
local filespec = "{}"
if self.opts._line_placeholder then
filespec = "{1}"
end
local act = shell.raw_action(function (items, _, _) local act = shell.raw_action(function (items, _, _)
-- only preview first item -- only preview first item
local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) local entry = path.entry_to_file(items[1], not self.relative and self.opts.cwd)
return file.path return entry.bufname or entry.path
end, filespec) end, self.opts.field_index_expr or "{}")
return act return act
end end
@ -98,8 +96,8 @@ function Previewer.bat:cmdline(o)
o = o or {} o = o or {}
o.action = o.action or self:action(o) o.action = o.action or self:action(o)
local highlight_line = "" local highlight_line = ""
if self.opts._line_placeholder then if self.opts.line_field_index then
highlight_line = string.format("--highlight-line={%d}", self.opts._line_placeholder) highlight_line = string.format("--highlight-line={%d}", self.opts.line_field_index)
end end
return vim.fn.shellescape(string.format('sh -c "%s %s %s `%s`"', return vim.fn.shellescape(string.format('sh -c "%s %s %s `%s`"',
self.cmd, self.args, highlight_line, self:action(o))) self.cmd, self.args, highlight_line, self:action(o)))
@ -116,10 +114,11 @@ end
function Previewer.head:cmdline(o) function Previewer.head:cmdline(o)
o = o or {} o = o or {}
o.action = o.action or self:action(o) o.action = o.action or self:action(o)
local lines = "" local lines = "--lines=-0"
if self.opts._line_placeholder then -- print all lines instead
lines = string.format("--lines={%d}", self.opts._line_placeholder) -- if self.opts.line_field_index then
end -- lines = string.format("--lines={%d}", self.opts.line_field_index)
-- end
return vim.fn.shellescape(string.format('sh -c "%s %s %s `%s`"', return vim.fn.shellescape(string.format('sh -c "%s %s %s `%s`"',
self.cmd, self.args, lines, self:action(o))) self.cmd, self.args, lines, self:action(o)))
end end
@ -132,11 +131,24 @@ function Previewer.cmd_async:new(o, opts)
return self return self
end end
function Previewer.cmd_async:parse_entry_and_verify(entrystr)
local entry = path.entry_to_file(entrystr, not self.relative and self.opts.cwd)
local filepath = entry.bufname or entry.path or ''
local errcmd = nil
-- verify the file exists on disk and is accessible
if #filepath==0 or not vim.loop.fs_stat(filepath) then
errcmd = ('echo "%s: NO SUCH FILE OR ACCESS DENIED"'):format(
filepath and #filepath>0 and vim.fn.shellescape(filepath) or "<null>")
end
return filepath, entry, errcmd
end
function Previewer.cmd_async:cmdline(o) function Previewer.cmd_async:cmdline(o)
o = o or {} o = o or {}
local act = shell.preview_action_cmd(function(items) local act = shell.preview_action_cmd(function(items)
local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) local filepath, _, errcmd = self:parse_entry_and_verify(items[1])
local cmd = string.format('%s %s %s', self.cmd, self.args, vim.fn.shellescape(file.path)) local cmd = errcmd or ('%s %s %s'):format(
self.cmd, self.args, vim.fn.shellescape(filepath))
-- uncomment to see the command in the preview window -- uncomment to see the command in the preview window
-- cmd = vim.fn.shellescape(cmd) -- cmd = vim.fn.shellescape(cmd)
return cmd return cmd
@ -154,17 +166,13 @@ end
function Previewer.bat_async:cmdline(o) function Previewer.bat_async:cmdline(o)
o = o or {} o = o or {}
local highlight_line = ""
if self.opts._line_placeholder then
highlight_line = string.format("--highlight-line=", self.opts._line_placeholder)
end
local act = shell.preview_action_cmd(function(items) local act = shell.preview_action_cmd(function(items)
local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) local filepath, entry, errcmd = self:parse_entry_and_verify(items[1])
local cmd = string.format('%s %s %s%s "%s"', local cmd = errcmd or ('%s %s %s %s'):format(
self.cmd, self.args, self.cmd, self.args,
highlight_line, self.opts.line_field_index and
utils._if(#highlight_line>0, tostring(file.line), ""), ("--highlight-line=%d"):format(entry.line) or '',
file.path) vim.fn.shellescape(filepath))
-- uncomment to see the command in the preview window -- uncomment to see the command in the preview window
-- cmd = vim.fn.shellescape(cmd) -- cmd = vim.fn.shellescape(cmd)
return cmd return cmd
@ -172,7 +180,7 @@ function Previewer.bat_async:cmdline(o)
return act return act
end end
Previewer.git_diff = Previewer.cmd_async:extend() Previewer.git_diff = Previewer.base:extend()
function Previewer.git_diff:new(o, opts) function Previewer.git_diff:new(o, opts)
Previewer.git_diff.super.new(self, o, opts) Previewer.git_diff.super.new(self, o, opts)
@ -236,7 +244,7 @@ function Previewer.git_diff:cmdline(o)
return act return act
end end
Previewer.man_pages = Previewer.cmd_async:extend() Previewer.man_pages = Previewer.base:extend()
function Previewer.man_pages:new(o, opts) function Previewer.man_pages:new(o, opts)
Previewer.man_pages.super.new(self, o, opts) Previewer.man_pages.super.new(self, o, opts)

View File

@ -186,6 +186,8 @@ M.buffers = function(opts)
opts.fzf_opts['--header-lines'] = opts.fzf_opts['--header-lines'] =
(not opts.ignore_current_buffer and opts.sort_lastused) and '1' (not opts.ignore_current_buffer and opts.sort_lastused) and '1'
opts = core.set_fzf_field_index(opts)
core.fzf_wrap(opts, contents, function(selected) core.fzf_wrap(opts, contents, function(selected)
if not selected then return end if not selected then return end
@ -260,7 +262,7 @@ M.buffer_lines = function(opts)
opts.fzf_opts['--query'] = vim.fn.shellescape(opts.search) opts.fzf_opts['--query'] = vim.fn.shellescape(opts.search)
end end
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts, 3, "{..-2}")
core.fzf_wrap(opts, items, function(selected) core.fzf_wrap(opts, items, function(selected)
if not selected then return end if not selected then return end
@ -343,8 +345,10 @@ M.tabs = function(opts)
-- opts.fzf_opts["--no-multi"] = '' -- opts.fzf_opts["--no-multi"] = ''
opts.fzf_opts["--preview-window"] = 'hidden:right:0' opts.fzf_opts["--preview-window"] = 'hidden:right:0'
opts.fzf_opts["--delimiter"] = vim.fn.shellescape('[\\)]') opts.fzf_opts["--delimiter"] = vim.fn.shellescape('[\\):]')
opts.fzf_opts["--with-nth"] = '2' opts.fzf_opts["--with-nth"] = '2..'
opts = core.set_fzf_field_index(opts, 3)
core.fzf_wrap(opts, contents, function(selected) core.fzf_wrap(opts, contents, function(selected)

View File

@ -162,7 +162,7 @@ M.breakpoints = function(opts)
:format(utils.ansi_codes.yellow("<Ctrl-x>"))) :format(utils.ansi_codes.yellow("<Ctrl-x>")))
end end
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts, 3, "{..-2}")
core.fzf_wrap(opts, contents, function(selected) core.fzf_wrap(opts, contents, function(selected)

View File

@ -104,7 +104,7 @@ M.grep = function(opts)
contents = contents .. " 2>&1" contents = contents .. " 2>&1"
end end
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
core.fzf_files(opts, contents) core.fzf_files(opts, contents)
opts.search = nil opts.search = nil
end end
@ -157,7 +157,7 @@ M.live_grep_st = function(opts)
-- conflicts with 'change:reload' event -- conflicts with 'change:reload' event
opts.global_resume_query = false opts.global_resume_query = false
opts.__FNCREF__ = opts.__FNCREF__ or utils.__FNCREF__() opts.__FNCREF__ = opts.__FNCREF__ or utils.__FNCREF__()
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
opts = core.set_fzf_interactive_cmd(opts) opts = core.set_fzf_interactive_cmd(opts)
core.fzf_files(opts) core.fzf_files(opts)
end end
@ -280,7 +280,7 @@ M.live_grep_mt = function(opts)
-- conflicts with 'change:reload' event -- conflicts with 'change:reload' event
opts.global_resume_query = false opts.global_resume_query = false
opts.__FNCREF__ = opts.__FNCREF__ or utils.__FNCREF__() opts.__FNCREF__ = opts.__FNCREF__ or utils.__FNCREF__()
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
core.fzf_files(opts) core.fzf_files(opts)
opts.search = nil opts.search = nil
end end

View File

@ -294,7 +294,7 @@ end
local function fzf_lsp_locations(opts) local function fzf_lsp_locations(opts)
opts = normalize_lsp_opts(opts, config.globals.lsp) opts = normalize_lsp_opts(opts, config.globals.lsp)
if not opts then return end if not opts then return end
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
if opts.force_uri == nil then opts.force_uri = true end if opts.force_uri == nil then opts.force_uri = true end
opts = set_lsp_fzf_fn(opts) opts = set_lsp_fzf_fn(opts)
if not opts.fzf_fn then return end if not opts.fzf_fn then return end
@ -335,7 +335,7 @@ M.workspace_symbols = function(opts)
opts = normalize_lsp_opts(opts, config.globals.lsp) opts = normalize_lsp_opts(opts, config.globals.lsp)
if not opts then return end if not opts then return end
opts.lsp_params = {query = opts.query or ''} opts.lsp_params = {query = opts.query or ''}
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
if opts.force_uri == nil then opts.force_uri = true end if opts.force_uri == nil then opts.force_uri = true end
opts = set_lsp_fzf_fn(opts) opts = set_lsp_fzf_fn(opts)
if not opts.fzf_fn then return end if not opts.fzf_fn then return end
@ -633,7 +633,7 @@ M.diagnostics = function(opts)
end)() end)()
end end
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
if opts.force_uri == nil then opts.force_uri = true end if opts.force_uri == nil then opts.force_uri = true end
return core.fzf_files(opts) return core.fzf_files(opts)
end end
@ -694,7 +694,7 @@ M.live_workspace_symbols = function(opts)
opts.global_resume_query = false opts.global_resume_query = false
opts.__FNCREF__ = M.live_workspace_symbols opts.__FNCREF__ = M.live_workspace_symbols
opts = core.set_fzf_interactive_cb(opts) opts = core.set_fzf_interactive_cb(opts)
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
if opts.force_uri == nil then opts.force_uri = true end if opts.force_uri == nil then opts.force_uri = true end
core.fzf_files(opts) core.fzf_files(opts)
opts.search = nil opts.search = nil

View File

@ -31,7 +31,7 @@ local quickfix_run = function(opts, cfg, locations)
utils.delayed_cb(cb) utils.delayed_cb(cb)
end end
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
return core.fzf_files(opts, contents) return core.fzf_files(opts, contents)
end end

View File

@ -144,7 +144,7 @@ local fzf_tags = function(opts)
-- signal actions this is a ctag -- signal actions this is a ctag
opts._ctag = true opts._ctag = true
opts = core.set_header(opts, 2) opts = core.set_header(opts, 2)
opts = core.set_fzf_line_args(opts) opts = core.set_fzf_field_index(opts)
return core.fzf_files(opts, contents) return core.fzf_files(opts, contents)
end end