You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
8.0 KiB
Lua
270 lines
8.0 KiB
Lua
local path = require "fzf-lua.path"
|
|
local shell = require "fzf-lua.shell"
|
|
local utils = require "fzf-lua.utils"
|
|
local Object = require "fzf-lua.class"
|
|
|
|
local Previewer = {}
|
|
|
|
Previewer.base = Object:extend()
|
|
|
|
-- Previewer base object
|
|
function Previewer.base:new(o, opts)
|
|
o = o or {}
|
|
self.type = "cmd";
|
|
self.cmd = o.cmd;
|
|
self.args = o.args or "";
|
|
self.relative = o.relative
|
|
self.opts = opts;
|
|
return self
|
|
end
|
|
|
|
function Previewer.base:preview_window(_)
|
|
return nil
|
|
end
|
|
|
|
function Previewer.base:preview_offset()
|
|
--[[
|
|
#
|
|
# 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''
|
|
]]
|
|
if self.opts.line_field_index then
|
|
return ("+{%d}-/2"):format(self.opts.line_field_index)
|
|
end
|
|
end
|
|
|
|
function Previewer.base:fzf_delimiter()
|
|
if not self.opts.line_field_index then return end
|
|
-- set delimiter to ':'
|
|
-- entry format is 'file:line:col: text'
|
|
local delim = self.opts.fzf_opts and self.opts.fzf_opts["--delimiter"]
|
|
if not delim then
|
|
delim = '[:]'
|
|
elseif not delim:match(":") then
|
|
if delim:match("%[.*%]")then
|
|
delim = delim:match("(%[.*)%]") .. ':]'
|
|
else
|
|
delim = '[' ..
|
|
utils.rg_escape(delim:match("^'?(.*)'$?")):gsub("%]", "\\]")
|
|
.. ':]'
|
|
end
|
|
end
|
|
return delim
|
|
end
|
|
|
|
-- Generic shell command previewer
|
|
Previewer.cmd = Previewer.base:extend()
|
|
|
|
function Previewer.cmd:new(o, opts)
|
|
Previewer.cmd.super.new(self, o, opts)
|
|
return self
|
|
end
|
|
|
|
function Previewer.cmd:cmdline(o)
|
|
o = o or {}
|
|
o.action = o.action or self:action(o)
|
|
return vim.fn.shellescape(string.format('sh -c "%s %s `%s`"',
|
|
self.cmd, self.args, o.action))
|
|
end
|
|
|
|
function Previewer.cmd:action(o)
|
|
o = o or {}
|
|
local act = shell.raw_action(function (items, _, _)
|
|
-- only preview first item
|
|
local entry = path.entry_to_file(items[1], not self.relative and self.opts.cwd)
|
|
return entry.bufname or entry.path
|
|
end, self.opts.field_index_expr or "{}")
|
|
return act
|
|
end
|
|
|
|
-- Specialized bat previewer
|
|
Previewer.bat = Previewer.cmd:extend()
|
|
|
|
function Previewer.bat:new(o, opts)
|
|
Previewer.bat.super.new(self, o, opts)
|
|
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_field_index then
|
|
highlight_line = string.format("--highlight-line={%d}", self.opts.line_field_index)
|
|
end
|
|
return vim.fn.shellescape(string.format('sh -c "%s %s %s `%s`"',
|
|
self.cmd, self.args, highlight_line, self:action(o)))
|
|
end
|
|
|
|
-- Specialized head previewer
|
|
Previewer.head = Previewer.cmd:extend()
|
|
|
|
function Previewer.head:new(o, opts)
|
|
Previewer.head.super.new(self, o, opts)
|
|
return self
|
|
end
|
|
|
|
function Previewer.head:cmdline(o)
|
|
o = o or {}
|
|
o.action = o.action or self:action(o)
|
|
local lines = "--lines=-0"
|
|
-- print all lines instead
|
|
-- if self.opts.line_field_index then
|
|
-- lines = string.format("--lines={%d}", self.opts.line_field_index)
|
|
-- end
|
|
return vim.fn.shellescape(string.format('sh -c "%s %s %s `%s`"',
|
|
self.cmd, self.args, lines, self:action(o)))
|
|
end
|
|
|
|
-- new async_action from nvim-fzf
|
|
Previewer.cmd_async = Previewer.base:extend()
|
|
|
|
function Previewer.cmd_async:new(o, opts)
|
|
Previewer.cmd_async.super.new(self, o, opts)
|
|
return self
|
|
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)
|
|
o = o or {}
|
|
local act = shell.preview_action_cmd(function(items)
|
|
local filepath, _, errcmd = self:parse_entry_and_verify(items[1])
|
|
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
|
|
-- cmd = vim.fn.shellescape(cmd)
|
|
return cmd
|
|
end, "{}")
|
|
return act
|
|
end
|
|
|
|
Previewer.bat_async = Previewer.cmd_async:extend()
|
|
|
|
function Previewer.bat_async:new(o, opts)
|
|
Previewer.bat_async.super.new(self, o, opts)
|
|
self.theme = o.theme
|
|
return self
|
|
end
|
|
|
|
function Previewer.bat_async:cmdline(o)
|
|
o = o or {}
|
|
local act = shell.preview_action_cmd(function(items)
|
|
local filepath, entry, errcmd = self:parse_entry_and_verify(items[1])
|
|
local cmd = errcmd or ('%s %s %s %s'):format(
|
|
self.cmd, self.args,
|
|
self.opts.line_field_index and
|
|
("--highlight-line=%d"):format(entry.line) or '',
|
|
vim.fn.shellescape(filepath))
|
|
-- uncomment to see the command in the preview window
|
|
-- cmd = vim.fn.shellescape(cmd)
|
|
return cmd
|
|
end, "{}")
|
|
return act
|
|
end
|
|
|
|
Previewer.git_diff = Previewer.base:extend()
|
|
|
|
function Previewer.git_diff:new(o, opts)
|
|
Previewer.git_diff.super.new(self, o, opts)
|
|
self.cmd_deleted = path.git_cwd(o.cmd_deleted, opts.cwd)
|
|
self.cmd_modified = path.git_cwd(o.cmd_modified, opts.cwd)
|
|
self.cmd_untracked = path.git_cwd(o.cmd_untracked, opts.cwd)
|
|
self.pager = o.pager
|
|
do
|
|
-- populate the icon mappings
|
|
local icons_overrides = o._fn_git_icons and o._fn_git_icons()
|
|
self.git_icons = {}
|
|
for _, i in ipairs({ "D", "M", "R", "A", "C", "?" }) do
|
|
self.git_icons[i] =
|
|
icons_overrides and icons_overrides[i] and
|
|
utils.lua_regex_escape(icons_overrides[i].icon) or i
|
|
end
|
|
end
|
|
return self
|
|
end
|
|
|
|
function Previewer.git_diff:cmdline(o)
|
|
o = o or {}
|
|
local act = shell.preview_action_cmd(function(items, fzf_lines, fzf_columns)
|
|
if not items or vim.tbl_isempty(items) then
|
|
utils.warn("shell error while running preview action.")
|
|
return
|
|
end
|
|
local is_deleted = items[1]:match(self.git_icons['D']..utils.nbsp) ~= nil
|
|
local is_modified = items[1]:match("[" ..
|
|
self.git_icons['M'] ..
|
|
self.git_icons['R'] ..
|
|
self.git_icons['A'] ..
|
|
"]" ..utils.nbsp) ~= nil
|
|
local is_untracked = items[1]:match("[" ..
|
|
self.git_icons['?'] ..
|
|
self.git_icons['C'] ..
|
|
"]"..utils.nbsp) ~= nil
|
|
local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd)
|
|
local cmd = nil
|
|
if is_modified then cmd = self.cmd_modified
|
|
elseif is_deleted then cmd = self.cmd_deleted
|
|
elseif is_untracked then cmd = self.cmd_untracked end
|
|
local pager = ""
|
|
if self.pager and #self.pager>0 and
|
|
vim.fn.executable(self.pager:match("[^%s]+")) == 1 then
|
|
pager = '| ' .. self.pager
|
|
end
|
|
cmd = string.format('FZF_PREVIEW_LINES=%d;FZF_PREVIEW_COLUMNS=%d;%s %s %s',
|
|
fzf_lines, fzf_columns, cmd, vim.fn.shellescape(file.path), pager)
|
|
cmd = 'sh -c ' .. vim.fn.shellescape(cmd)
|
|
if self.opts.debug then
|
|
print("[DEBUG]: "..cmd.."\n")
|
|
end
|
|
-- uncomment to see the command in the preview window
|
|
-- cmd = vim.fn.shellescape(cmd)
|
|
return cmd
|
|
-- we need to add '--' to mark the end of command options
|
|
-- as git icon customization may contain special shell chars
|
|
-- which will otherwise choke our preview cmd ('+', '-', etc)
|
|
end, "-- {}")
|
|
return act
|
|
end
|
|
|
|
Previewer.man_pages = Previewer.base:extend()
|
|
|
|
function Previewer.man_pages:new(o, opts)
|
|
Previewer.man_pages.super.new(self, o, opts)
|
|
self.cmd = self.cmd or "man"
|
|
return self
|
|
end
|
|
|
|
function Previewer.man_pages:cmdline(o)
|
|
o = o or {}
|
|
local act = shell.preview_action_cmd(function(items)
|
|
-- local manpage = require'fzf-lua.providers.manpages'.getmanpage(items[1])
|
|
local manpage = items[1]:match("[^[,( ]+")
|
|
local cmd = ("%s %s %s"):format(
|
|
self.cmd, self.args, vim.fn.shellescape(manpage))
|
|
-- uncomment to see the command in the preview window
|
|
-- cmd = vim.fn.shellescape(cmd)
|
|
return cmd
|
|
end, "{}")
|
|
return act
|
|
end
|
|
|
|
return Previewer
|