refactor previewers

main
bhagwan 3 years ago
parent cf583fe211
commit ec2e870614

@ -185,7 +185,6 @@ require'fzf-lua'.setup {
'ctrl-a:toggle-all',
'ctrl-l:clear-query',
},
preview_cmd = '', -- 'head -n $FZF_PREVIEW_LINES',
preview_border = 'border', -- border|noborder
preview_wrap = 'nowrap', -- wrap|nowrap
preview_opts = 'nohidden', -- hidden|nohidden
@ -193,9 +192,27 @@ require'fzf-lua'.setup {
preview_horizontal = 'right:60%', -- right|left:size
preview_layout = 'flex', -- horizontal|vertical|flex
flip_columns = 120, -- #cols to switch to horizontal on flex
bat_theme = 'Coldark-Dark', -- bat preview theme (bat --list-themes)
-- default_previewer = "bat", -- override the default previewer?
-- by default auto-detect bat|cat
previewers = {
cat = {
cmd = "cat",
args = "--number",
},
bat = {
cmd = "bat",
args = "--style=numbers,changes --color always",
theme = 'Coldark-Dark', -- bat preview theme (bat --list-themes)
config = nil, -- nil uses $BAT_CONFIG_PATH
},
head = {
cmd = "head",
args = nil,
},
},
-- provider setup
files = {
-- previewer = "cat", -- uncomment to override previewer
prompt = 'Files ',
cmd = '', -- "find . -type f -printf '%P\n'",
git_icons = true, -- show git icons?

@ -54,7 +54,6 @@ M.globals = {
'ctrl-a:toggle-all',
'ctrl-l:clear-query',
},
preview_cmd = nil, -- auto detect head|bat
preview_border = 'border',
preview_wrap = 'nowrap',
preview_opts = 'nohidden',
@ -62,8 +61,33 @@ M.globals = {
preview_horizontal = 'right:60%',
preview_layout = 'flex',
flip_columns = 120,
bat_theme = nil,
bat_opts = "--italic-text=always --style=numbers,changes --color always",
default_previewer = utils._if(vim.fn.executable("bat")==1, "bat", "cat"),
previewers = {
cat = {
cmd = "cat",
args = "--number",
-- we use function here instead of the object due to
-- vim.tbl_deep_extend not copying metatables and
-- metamethods (__index and __call)
_new = function() return require 'fzf-lua.previewer'.cmd end,
},
bat = {
cmd = "bat",
args = "--italic-text=always --style=numbers,changes --color always",
theme = nil,
config = nil,
_new = function() return require 'fzf-lua.previewer'.bat end,
},
head = {
cmd = "head",
args = nil,
_new = function() return require 'fzf-lua.previewer'.head end,
},
builtin = {
treesitter = true,
_new = function() return require 'fzf-lua.previewer'.builtin end,
},
},
files = {
prompt = '> ',
cmd = nil, -- default: auto detect find|fd
@ -317,6 +341,9 @@ function M.normalize_opts(opts, defaults)
if not opts.winopts then opts.winopts = {} end
opts.winopts = vim.tbl_deep_extend("keep", opts.winopts, defaults.winopts)
end
if not opts.previewer or not M.globals.previewers[opts.previewer] then
opts.previewer = M.globals.default_previewer
end
return opts
end

@ -16,40 +16,13 @@ M.get_devicon = function(file, ext)
return icon
end
M.preview_cmd = function(opts)
opts = opts or {}
opts.filespec = opts.filespec or '{}'
opts.preview_cmd = opts.preview_cmd or config.globals.preview_cmd
opts.preview_args = opts.preview_args or ''
opts.bat_opts = opts.bat_opts or config.globals.bat_opts
local preview = nil
if not opts.cwd then opts.cwd = ''
elseif #opts.cwd > 0 then
opts.cwd = path.add_trailing(opts.cwd)
end
if opts.preview_cmd and #opts.preview_cmd > 0 then
preview = string.format("%s %s -- %s%s", opts.preview_cmd, opts.preview_args, opts.cwd, opts.filespec)
elseif vim.fn.executable("bat") == 1 then
preview = string.format("bat %s %s -- %s%s", opts.bat_opts, opts.preview_args, opts.cwd, opts.filespec)
else
preview = string.format("head -n $FZF_PREVIEW_LINES %s -- %s%s", opts.preview_args, opts.cwd, opts.filespec)
end
if preview ~= nil then
-- We use bash to do math on the environment variable, so
-- let's make sure this command runs in bash
-- preview = "bash -c " .. vim.fn.shellescape(preview)
preview = vim.fn.shellescape(preview)
end
return preview
end
M.build_fzf_cli = function(opts)
opts.prompt = opts.prompt or config.globals.default_prompt
opts.preview_offset = opts.preview_offset or ''
opts.fzf_bin = opts.fzf_bin or config.globals.fzf_bin
local cli = string.format(
[[ %s --layout=%s --bind=%s --prompt=%s]] ..
[[ --preview-window='%s%s' --preview=%s]] ..
[[ --preview-window=%s%s --preview=%s]] ..
[[ --height=100%% --ansi]] ..
[[ %s %s %s %s %s]],
opts.fzf_args or config.globals.fzf_args or '',
@ -59,13 +32,13 @@ M.build_fzf_cli = function(opts)
vim.fn.shellescape(opts.prompt),
utils._if(opts.preview_window, opts.preview_window, config.preview_window()),
utils._if(#opts.preview_offset>0, ":"..opts.preview_offset, ''),
utils._if(opts.preview, opts.preview, M.preview_cmd(opts)),
utils._if(opts.preview, vim.fn.shellescape(opts.preview), "''"),
-- HACK: support skim (rust version of fzf)
utils._if(opts.fzf_bin and opts.fzf_bin:find('sk')~=nil, "--inline-info", "--info=inline"),
utils._if(actions.expect(opts.actions), actions.expect(opts.actions), ''),
utils._if(opts.nomulti, '--no-multi', '--multi'),
utils._if(opts.fzf_cli_args, opts.fzf_cli_args, ''),
utils._if(opts.cli_args, opts.cli_args, '')
utils._if(opts._fzf_cli_args, opts._fzf_cli_args, '')
)
-- print(cli)
return cli
@ -145,14 +118,28 @@ M.make_entry_file = function(opts, x)
prefix = prefix .. utils._if(#prefix>0, utils.nbsp, '') .. icon
end
if #prefix > 0 then
x = prefix .. " " .. x
x = prefix .. utils.nbsp .. x
end
return x
end
local function trim_entry(string)
string = string:gsub("^[^ ]* ", "")
return string
M.set_fzf_line_args = function(opts)
opts._line_placeholder = 2
-- delimiters are ':' and <tab>
opts._fzf_cli_args = (opts._fzf_cli_args or '') .. " --delimiter='[:\\t]'"
--[[
#
# Explanation of the fzf preview offset options:
#
# ~3 Top 3 lines as the fixed header
# +{2} Base scroll offset extracted from the second field
# +3 Extra offset to compensate for the 3-line header
# /2 Put in the middle of the preview area
#
'--preview-window '~3:+{2}+3/2''
]]
opts.preview_offset = string.format("+{%d}-/2", opts._line_placeholder)
return opts
end
M.fzf_files = function(opts)
@ -177,6 +164,14 @@ M.fzf_files = function(opts)
opts.filespec = utils._if(has_prefix, "{2}", "{1}")
end
local preview_opts = config.globals.previewers[opts.previewer]
if preview_opts then
local preview = preview_opts._new()(preview_opts, opts)
opts.preview = preview:cmdline()
-- opts.preview = preview:action()
end
local selected = fzf.fzf(opts.fzf_fn,
M.build_fzf_cli(opts),
config.winopts(opts))
@ -189,13 +184,7 @@ M.fzf_files = function(opts)
if #selected > 1 then
for i = 2, #selected do
if has_prefix then
selected[i] = trim_entry(selected[i])
end
if opts.cwd and #opts.cwd>0 and
not path.starts_with_separator(selected[i]) then
selected[i] = path.join({opts.cwd, selected[i]})
end
selected[i] = path.entry_to_file(selected[i], opts.cwd).noicons
if opts.cb_selected then
local cb_ret = opts.cb_selected(opts, selected[i])
if cb_ret then selected[i] = cb_ret end

@ -14,23 +14,26 @@ function M.setup(opts)
for k, _ in pairs(globals.winopts) do
if opts[k] ~= nil then globals.winopts[k] = opts[k] end
end
-- empty BAT_CONFIG_PATH so we don't conflict
-- with '$XDG_DATA_HOME/bat/config'
vim.env.BAT_CONFIG_PATH = ''
-- override BAT_CONFIG_PATH to prevent a
-- conflct with '$XDG_DATA_HOME/bat/config'
if globals.previewers.bat.config then
vim.env.BAT_CONFIG_PATH = vim.fn.expand(globals.previewers.bat.config)
end
-- override the bat preview theme if set by caller
if globals.bat_theme and #globals.bat_theme > 0 then
vim.env.BAT_THEME = globals.bat_theme
if globals.previewers.bat.theme and #globals.previewers.bat.theme > 0 then
vim.env.BAT_THEME = globals.previewers.bat.theme
end
-- reset default window opts if set by user
fzf.default_window_options = config.winopts()
-- set the fzf binary if set by the user
if globals.fzf_bin ~= nil then
if fzf.default_options ~= nil and
vim.fn.executable(globals.fzf_bin) == 1 then
fzf.default_options.fzf_binary = globals.fzf_bin
else
globals.fzf_bin = nil
end
if globals.fzf_bin ~= nil and vim.fn.executable(globals.fzf_bin) ~= 1 then
globals.fzf_bin = nil
end
-- ignore if using an older version of nvim-fzf
if fzf.default_options ~= nil then
fzf.default_options.fzf_binary = globals.fzf_bin
else
globals.fzf_bin = nil
end
-- reset our globals based on user opts
-- this doesn't happen automatically

@ -1,3 +1,5 @@
local utils = require "fzf-lua.utils"
local M = {}
M.separator = function()
@ -100,4 +102,45 @@ function M.shorten(path, max_length)
end
end
local function strsplit(inputstr, sep)
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
--[[ local function lastIndexOf(haystack, needle)
local i, j
local k = 0
repeat
i = j
j, k = string.find(haystack, needle, k + 1, true)
until j == nil
return i
end ]]
local function lastIndexOf(haystack, needle)
local i=haystack:match(".*"..needle.."()")
if i==nil then return nil else return i-1 end
end
function M.entry_to_file(entry, cwd)
local sep = ":"
local s = strsplit(entry, sep)
local file = s[1]:match("[^"..utils.nbsp.."]*$")
local idx = lastIndexOf(s[1], utils.nbsp) or 0
local line = s[2]
local col = s[3]
if cwd and #cwd>0 and not M.starts_with_separator(file) then
file = M.join({cwd, file})
end
return {
noicons = string.sub(entry, idx+1),
path = file,
line = line or 1,
col = col or 1,
}
end
return M

@ -0,0 +1,124 @@
local path = require "fzf-lua.path"
local utils = require "fzf-lua.utils"
local raw_action = require("fzf.actions").raw_action
local Previewer = {}
Previewer.base = {}
Previewer.head = {}
Previewer.cmd = {}
Previewer.bat = {}
Previewer.buffer = {}
-- Constructors call on Previewer.<o>()
for c, _ in pairs(Previewer) do
setmetatable(Previewer[c], {
__call = function (cls, ...)
return cls:new(...)
end,
})
end
-- Previewer base object
function Previewer.base:new(o, opts)
o = o or {}
self = setmetatable({}, { __index = self })
self.type = "cmd";
self.cmd = o.cmd;
self.args = o.args or "";
self.opts = opts;
return self
end
function Previewer.base:filespec(entry)
local file = path.entry_to_file(entry, nil, true)
print(file.file, file.line, file.col)
return file
end
-- Generic shell command previewer
function Previewer.cmd:new(o, opts)
self = setmetatable(Previewer.base(o, opts), {
__index = vim.tbl_deep_extend("keep",
self, Previewer.base
)})
return self
end
function Previewer.cmd:cmdline(o)
o = o or {}
o.action = o.action or self:action(o)
return string.format("%s %s `%s`", self.cmd, self.args, o.action)
end
function Previewer.cmd:action(o)
o = o or {}
local filespec = "{+}"
if self.opts._line_placeholder then
filespec = "{1}"
end
local act = raw_action(function (items, fzf_lines, _)
-- only preview first item
local file = path.entry_to_file(items[1], self.opts.cwd)
return file.path
end, filespec)
return act
end
-- Specialized bat previewer
function Previewer.bat:new(o, opts)
self = setmetatable(Previewer.cmd(o, opts), {
__index = vim.tbl_deep_extend("keep",
self, Previewer.cmd, Previewer.base
)})
self.theme = o.theme
return self
end
function Previewer.bat:cmdline(o)
o = o or {}
o.action = o.action or self:action(o)
local highlight_line = ""
if self.opts._line_placeholder then
highlight_line = string.format("--highlight-line={%d}", self.opts._line_placeholder)
end
return string.format("%s %s %s -- `%s`",
self.cmd, self.args, highlight_line, self:action(o))
--[[ return string.format("%s %s `%s` -- `%s`",
self.cmd, self.args, self:action_line(), o.action) ]]
end
-- not in use
function Previewer.bat:action_line(o)
o = o or {}
local act = raw_action(function (items, _, _)
local file = path.entry_to_file(items[1], self.opts.cwd)
return string.format("--highlight-line=%s", tostring(file.line))
end)
return act
end
-- Specialized head previewer
function Previewer.head:new(o, opts)
self = setmetatable(Previewer.cmd(o, opts), {
__index = vim.tbl_deep_extend("keep",
self, Previewer.cmd, Previewer.base
)})
self.theme = o.theme
return self
end
function Previewer.head:cmdline(o)
o = o or {}
o.action = o.action or self:action(o)
local lines = ""
if self.opts._line_placeholder then
lines = string.format("--lines={%d}", self.opts._line_placeholder)
end
return string.format("%s %s %s -- `%s`",
self.cmd, self.args, lines, self:action(o))
--[[ return string.format("%s %s `%s` -- `%s`",
self.cmd, self.args, self:action_line(), o.action) ]]
end
return Previewer

@ -2,7 +2,7 @@ if not pcall(require, "fzf") then
return
end
local action = require("fzf.actions").action
local action = require("fzf.actions").raw_action
local core = require "fzf-lua.core"
local path = require "fzf-lua.path"
local utils = require "fzf-lua.utils"
@ -118,7 +118,7 @@ M.buffers = function(opts)
end
opts.preview = act
opts.cli_args = utils._if(
opts._fzf_cli_args = utils._if(
header_line and not opts.ignore_current_buffer,
'--header-lines=1', ''
)

@ -3,7 +3,7 @@ if not pcall(require, "fzf") then
end
local fzf = require "fzf"
local action = require("fzf.actions").action
local action = require("fzf.actions").raw_action
local core = require "fzf-lua.core"
local utils = require "fzf-lua.utils"
local config = require "fzf-lua.config"

@ -73,20 +73,7 @@ M.grep = function(opts)
return x
end ]]
opts.cli_args = "--delimiter='[: ]'"
opts.preview_args = "--highlight-line={3}" -- bat higlight
--[[
# Preview with bat, matching line in the middle of the window below
# the fixed header of the top 3 lines
#
# ~3 Top 3 lines as the fixed header
# +{2} Base scroll offset extracted from the second field
# +3 Extra offset to compensate for the 3-line header
# /2 Put in the middle of the preview area
#
'--preview-window '~3:+{2}+3/2''
]]
opts.preview_offset = "+{3}-/2"
opts = core.set_fzf_line_args(opts)
core.fzf_files(opts)
opts.search = nil
end
@ -100,20 +87,15 @@ M.live_grep_sk = function(opts)
-- TODO: how to open without a query with special char support
local sk_args = get_grep_cmd(opts , "'{}'", true)
opts.cli_args = "--delimiter='[: ]' " ..
string.format("--cmd-prompt='%s' -i -c %s",
opts._fzf_cli_args = string.format("--cmd-prompt='%s' -i -c %s",
opts.prompt,
vim.fn.shellescape(sk_args))
opts.git_icons = false
opts.file_icons = false
opts.filespec = '{1}'
opts.preview_offset = "+{2}-/2"
opts.preview_args = "--highlight-line={2}"
opts.fzf_fn = nil --function(_) end
opts = core.set_fzf_line_args(opts)
core.fzf_files(opts)
opts.search = nil
end
@ -141,8 +123,7 @@ M.live_grep = function(opts)
local initial_command = get_grep_cmd(opts, opts.search)
local reload_command = get_grep_cmd(opts, "{q}", true) .. " || true"
opts.cli_args = "--delimiter='[: ]' " ..
string.format("--phony --query=%s --bind=%s",
opts._fzf_cli_args = string.format("--phony --query=%s --bind=%s",
utils._if(opts.search and #opts.search>0,
vim.fn.shellescape(utils.rg_escape(opts.search)),
[['']]),
@ -154,9 +135,6 @@ M.live_grep = function(opts)
-- with the extension parsing
opts.git_icons = false
opts.file_icons = false
opts.filespec = '{1}'
opts.preview_offset = "+{2}-/2"
opts.preview_args = "--highlight-line={2}" -- bat higlight
opts.fzf_fn = fzf_helpers.cmd_line_transformer(
initial_command,
@ -164,6 +142,7 @@ M.live_grep = function(opts)
return core.make_entry_file(opts, x)
end)
opts = core.set_fzf_line_args(opts)
core.fzf_files(opts)
opts.search = nil
end

@ -104,7 +104,7 @@ M.helptags = function(opts)
-- local prev_act = action(function (args) end)
opts.cli_args = opts.cli_args or "--nth 1"
opts._fzf_cli_args = "--nth 1"
opts.preview_window = opts.preview_window or 'right:0'
opts.nomulti = utils._if(opts.nomulti~=nil, opts.nomulti, true)

@ -74,11 +74,7 @@ local function diagnostics_handler(opts, cb, _, entry)
if opts.color_icons then
icon = utils.ansi_codes[severity.color or "dark_grey"](icon)
end
if opts.file_icons or opts.git_icons then
entry = icon .. utils.nbsp .. utils.nbsp .. entry
else
entry = icon .. utils.nbsp .. " " .. entry
end
entry = icon .. utils.nbsp .. utils.nbsp .. entry
end
cb(entry, function(err)
if err then return end
@ -171,19 +167,6 @@ local function set_lsp_fzf_fn(opts)
return opts
end
local set_fzf_files_args = function(opts)
local line_placeholder = 2
if opts.file_icons or opts.git_icons or opts.lsp_icons then
line_placeholder = line_placeholder+1
end
opts.cli_args = opts.cli_args or "--delimiter='[: \\t]'"
opts.filespec = string.format("{%d}", line_placeholder-1)
opts.preview_args = string.format("--highlight-line={%d}", line_placeholder)
opts.preview_offset = string.format("+{%d}-/2", line_placeholder)
return opts
end
local normalize_lsp_opts = function(opts, cfg)
opts = config.normalize_opts(opts, cfg)
@ -204,7 +187,7 @@ end
local function fzf_lsp_locations(opts)
opts = normalize_lsp_opts(opts, config.globals.lsp)
opts = set_fzf_files_args(opts)
opts = core.set_fzf_line_args(opts)
opts = set_lsp_fzf_fn(opts)
return core.fzf_files(opts)
end
@ -241,7 +224,7 @@ end
M.workspace_symbols = function(opts)
opts = normalize_lsp_opts(opts, config.globals.lsp)
opts.lsp_params = {query = ''}
opts = set_fzf_files_args(opts)
opts = core.set_fzf_line_args(opts)
opts = set_lsp_fzf_fn(opts)
return core.fzf_files(opts)
end
@ -273,7 +256,7 @@ M.code_actions = function(opts)
opts.nomulti = true
opts.preview_window = 'right:0'
opts.cli_args = "--delimiter=':'"
opts._fzf_cli_args = "--delimiter=':'"
opts = set_lsp_fzf_fn(opts)
coroutine.wrap(function ()
@ -422,7 +405,7 @@ M.diagnostics = function(opts)
end)()
end
opts = set_fzf_files_args(opts)
opts = core.set_fzf_line_args(opts)
return core.fzf_files(opts)
end

@ -41,7 +41,7 @@ M.manpages = function(opts)
utils.ansi_codes.red(man), desc)
end)
opts.cli_args = opts.cli_args or "--tiebreak begin --nth 1,2"
opts._fzf_cli_args = "--tiebreak begin --nth 1,2"
opts.preview_window = opts.preview_window or 'right:0'
opts.nomulti = utils._if(opts.nomulti~=nil, opts.nomulti, true)

@ -3,7 +3,7 @@ if not pcall(require, "fzf") then
end
local fzf = require "fzf"
local action = require("fzf.actions").action
local action = require("fzf.actions").raw_action
local core = require "fzf-lua.core"
local config = require "fzf-lua.config"
local actions = require "fzf-lua.actions"

@ -2,9 +2,9 @@ if not pcall(require, "fzf") then
return
end
-- local fzf = require "fzf"
-- 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"
@ -39,26 +39,7 @@ local quickfix_run = function(opts, cfg, locations)
return x
end ]]
local line_placeholder = 2
if opts.file_icons == true or opts.git_icons == true then
line_placeholder = line_placeholder+1
end
opts.cli_args = "--delimiter='[: \\t]'"
opts.filespec = string.format("{%d}", line_placeholder-1)
opts.preview_args = string.format("--highlight-line={%d}", line_placeholder)
--[[
# Preview with bat, matching line in the middle of the window below
# the fixed header of the top 3 lines
#
# ~3 Top 3 lines as the fixed header
# +{2} Base scroll offset extracted from the second field
# +3 Extra offset to compensate for the 3-line header
# /2 Put in the middle of the preview area
#
'--preview-window '~3:+{2}+3/2''
]]
opts.preview_offset = string.format("+{%d}-/2", line_placeholder)
opts = core.set_fzf_line_args(opts)
return core.fzf_files(opts)
end

@ -207,7 +207,6 @@ function M.delayed_cb(cb, fn)
vim.defer_fn(function()
cb(nil, fn)
end, 20)
end
return M

Loading…
Cancel
Save