From 0feeb0fdbbcd08fd9da572a76a115b4eef104184 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Thu, 9 Sep 2021 15:27:38 -0700 Subject: [PATCH] more improvements to previewer interface for future extensions --- README.md | 15 +- lua/fzf-lua/config.lua | 26 ++-- lua/fzf-lua/core.lua | 7 + lua/fzf-lua/previewer/builtin.lua | 2 +- lua/fzf-lua/previewer/fzf.lua | 217 +++++++++++++++++++++++++++++ lua/fzf-lua/previewer/init.lua | 220 ++++-------------------------- 6 files changed, 261 insertions(+), 226 deletions(-) create mode 100644 lua/fzf-lua/previewer/fzf.lua diff --git a/README.md b/README.md index 80881b1..8756d8e 100644 --- a/README.md +++ b/README.md @@ -258,12 +258,6 @@ require'fzf-lua'.setup { -- default_previewer = "bat", -- override the default previewer? -- by default uses the builtin previewer previewers = { - cmd = { - -- custom previewer, will execute: - -- ` ` - cmd = "echo", - args = "", - }, cat = { cmd = "cat", args = "--number", @@ -453,16 +447,15 @@ require'fzf-lua'.setup { }, }, -- uncomment to disable the previewer - -- helptags = { previewer = { _new = false } }, - -- manpages = { previewer = { _new = false } }, + -- helptags = { previewer = { _ctor = false } }, + -- manpages = { previewer = { _ctor = false } }, -- uncomment to set dummy win location (help|man bar) -- "topleft" : up -- "botright" : down -- helptags = { previewer = { split = "topleft" } }, -- manpages = { previewer = { split = "topleft" } }, - -- uncomment 2 lines to use `man` command as native fzf previewer - -- manpages = { previewer = { cmd = "man", _new = function() - -- return require 'fzf-lua.previewer'.man_pages end } }, + -- uncomment to use `man` command as native fzf previewer + -- manpages = { previewer = { _ctor = require'fzf-lua.previewer'.fzf.man_pages } }, -- optional override of file extension icon colors -- available colors (terminal): -- clear, bold, black, red, green, yellow diff --git a/lua/fzf-lua/config.lua b/lua/fzf-lua/config.lua index 3b6c99f..9f794ac 100644 --- a/lua/fzf-lua/config.lua +++ b/lua/fzf-lua/config.lua @@ -1,5 +1,6 @@ local utils = require "fzf-lua.utils" local actions = require "fzf-lua.actions" +local previewers = require "fzf-lua.previewer" -- Clear the default command or it would interfere with our options -- not needed anymore, we are pretty much overriding all options @@ -63,41 +64,32 @@ M.globals = { flip_columns = 120, default_previewer = "builtin", previewers = { - cmd = { - -- custom previewer to be overidden by the user - cmd = "", - args = "", - -- 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_async end, - }, cat = { cmd = "cat", args = "--number", - _new = function() return require 'fzf-lua.previewer'.cmd_async end, + _ctor = previewers.fzf.cmd_async, }, bat = { cmd = "bat", args = "--italic-text=always --style=numbers,changes --color always", theme = nil, config = nil, - _new = function() return require 'fzf-lua.previewer'.bat_async end, + _ctor = previewers.fzf.bat_async, }, bat_native = { cmd = "bat", args = "--italic-text=always --style=numbers,changes --color always", - _new = function() return require 'fzf-lua.previewer'.bat end, + _ctor = previewers.fzf.bat, }, head = { cmd = "head", args = nil, - _new = function() return require 'fzf-lua.previewer'.head end, + _ctor = previewers.fzf.head, }, git_diff = { cmd = "git diff", args = "--color", - _new = function() return require 'fzf-lua.previewer'.git_diff end, + _ctor = previewers.fzf.git_diff, }, builtin = { title = true, @@ -121,7 +113,7 @@ M.globals = { page_down = '', -- preview scroll down page_reset = '', -- reset scroll to orig pos }, - _new = function() return require 'fzf-lua.previewer.builtin'.buffer_or_file end, + _ctor = previewers.builtin.buffer_or_file, }, }, } @@ -329,7 +321,7 @@ M.globals.helptags = { ["ctrl-t"] = actions.help_tab, }, previewer = { - _new = function() return require 'fzf-lua.previewer.builtin'.help_tags end, + _ctor = previewers.builtin.help_tags, }, } M.globals.manpages = { @@ -342,7 +334,7 @@ M.globals.manpages = { ["ctrl-t"] = actions.man_tab, }, previewer = { - _new = function() return require 'fzf-lua.previewer.builtin'.man_pages end, + _ctor = previewers.builtin.man_pages, }, } M.globals.lsp = { diff --git a/lua/fzf-lua/core.lua b/lua/fzf-lua/core.lua index f27b337..009f333 100644 --- a/lua/fzf-lua/core.lua +++ b/lua/fzf-lua/core.lua @@ -15,11 +15,18 @@ M.fzf = function(opts, contents) local previewer, preview_opts = nil, nil if opts.previewer and type(opts.previewer) == 'string' then preview_opts = config.globals.previewers[opts.previewer] + if not preview_opts then + utils.warn(("invalid previewer '%s'"):format(opts.previewer)) + end elseif opts.previewer and type(opts.previewer) == 'table' then preview_opts = opts.previewer end if preview_opts and type(preview_opts._new) == 'function' then previewer = preview_opts._new()(preview_opts, opts, fzf_win) + elseif preview_opts and type(preview_opts._ctor) == 'function' then + previewer = preview_opts._ctor()(preview_opts, opts, fzf_win) + end + if previewer then opts.preview = previewer:cmdline() if type(previewer.preview_window) == 'function' then -- do we need to override the preview_window args? diff --git a/lua/fzf-lua/previewer/builtin.lua b/lua/fzf-lua/previewer/builtin.lua index 236555f..9b504b4 100644 --- a/lua/fzf-lua/previewer/builtin.lua +++ b/lua/fzf-lua/previewer/builtin.lua @@ -1,6 +1,6 @@ local path = require "fzf-lua.path" local utils = require "fzf-lua.utils" -local previewer_base = require "fzf-lua.previewer".base +local previewer_base = require "fzf-lua.previewer" local raw_action = require("fzf.actions").raw_action local api = vim.api diff --git a/lua/fzf-lua/previewer/fzf.lua b/lua/fzf-lua/previewer/fzf.lua new file mode 100644 index 0000000..9727388 --- /dev/null +++ b/lua/fzf-lua/previewer/fzf.lua @@ -0,0 +1,217 @@ +local path = require "fzf-lua.path" +local utils = require "fzf-lua.utils" +local helpers = require("fzf.helpers") +local previewer_base = require "fzf-lua.previewer" +local raw_action = require("fzf.actions").raw_action + +local Previewer = {} +Previewer.base = {} +Previewer.head = {} +Previewer.cmd = {} +Previewer.bat = {} +Previewer.cmd_async = {} +Previewer.bat_async = {} +Previewer.git_diff = {} +Previewer.man_pages = {} +Previewer.buffer = {} + +-- Constructors call on Previewer.() +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) + self = setmetatable(previewer_base(o, opts), { + __index = vim.tbl_deep_extend("keep", + self, previewer_base + )}) + self.type = "cmd"; + return self +end + +function Previewer.base:preview_window(_) + return nil +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 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 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], not self.relative and 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 vim.fn.shellescape(string.format('sh -c "%s %s %s `%s`"', + self.cmd, self.args, highlight_line, self:action(o))) +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 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 +function Previewer.cmd_async:new(o, opts) + self = setmetatable(Previewer.base(o, opts), { + __index = vim.tbl_deep_extend("keep", + self, Previewer.base + )}) + return self +end + +function Previewer.cmd_async:cmdline(o) + o = o or {} + local act = helpers.choices_to_shell_cmd_previewer(function(items) + local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) + local cmd = string.format('%s %s %s', self.cmd, self.args, vim.fn.shellescape(file.path)) + -- uncomment to see the command in the preview window + -- cmd = vim.fn.shellescape(cmd) + return cmd + end, "{}") + return act +end + +function Previewer.bat_async:new(o, opts) + self = setmetatable(Previewer.cmd_async(o, opts), { + __index = vim.tbl_deep_extend("keep", + self, Previewer.cmd_async, Previewer.base + )}) + self.theme = o.theme + return self +end + +function Previewer.bat_async:cmdline(o) + 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 = helpers.choices_to_shell_cmd_previewer(function(items) + local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) + local cmd = string.format('%s %s %s%s "%s"', + self.cmd, self.args, + highlight_line, + utils._if(#highlight_line>0, tostring(file.line), ""), + file.path) + -- uncomment to see the command in the preview window + -- cmd = vim.fn.shellescape(cmd) + return cmd + end, "{}") + return act +end + +function Previewer.git_diff:new(o, opts) + self = setmetatable(Previewer.cmd_async(o, opts), { + __index = vim.tbl_deep_extend("keep", + self, Previewer.cmd_async, Previewer.base + )}) + self.cmd = path.git_cwd(self.cmd, opts.cwd) + return self +end + +function Previewer.git_diff:cmdline(o) + o = o or {} + local act = helpers.choices_to_shell_cmd_previewer(function(items) + local is_deleted = items[1]:match("D"..utils.nbsp) ~= nil + local is_untracked = items[1]:match("?"..utils.nbsp) ~= nil + local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) + local cmd = self.cmd + local args = self.args + if is_untracked then args = args .. " --no-index /dev/null" end + if is_deleted then + cmd = self.cmd:gsub("diff", "show HEAD:") + cmd = string.format('%s"%s"', cmd, path.relative(file.path, self.opts.cwd)) + else + cmd = string.format('%s %s %s', cmd, args, vim.fn.shellescape(file.path)) + end + -- uncomment to see the command in the preview window + -- cmd = vim.fn.shellescape(cmd) + return cmd + end, "{}") + return act +end + +function Previewer.man_pages:new(o, opts) + self = setmetatable(Previewer.cmd_async(o, opts), { + __index = vim.tbl_deep_extend("keep", + self, Previewer.cmd_async, Previewer.base + )}) + self.cmd = self.cmd or "man" + return self +end + +function Previewer.man_pages:cmdline(o) + o = o or {} + local act = helpers.choices_to_shell_cmd_previewer(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 diff --git a/lua/fzf-lua/previewer/init.lua b/lua/fzf-lua/previewer/init.lua index 84b7a03..9c71421 100644 --- a/lua/fzf-lua/previewer/init.lua +++ b/lua/fzf-lua/previewer/init.lua @@ -1,33 +1,18 @@ -local path = require "fzf-lua.path" local utils = require "fzf-lua.utils" -local helpers = require("fzf.helpers") -local raw_action = require("fzf.actions").raw_action local Previewer = {} -Previewer.base = {} -Previewer.head = {} -Previewer.cmd = {} -Previewer.bat = {} -Previewer.cmd_async = {} -Previewer.bat_async = {} -Previewer.git_diff = {} -Previewer.man_pages = {} -Previewer.buffer = {} --- Constructors call on Previewer.() -for c, _ in pairs(Previewer) do - setmetatable(Previewer[c], { - __call = function (cls, ...) - return cls:new(...) - end, - }) -end +-- Constructor +setmetatable(Previewer, { + __call = function (cls, ...) + return cls:new(...) + end, +}) -- Previewer base object -function Previewer.base:new(o, opts) +function Previewer:new(o, opts) o = o or {} self = setmetatable({}, { __index = self }) - self.type = "cmd"; self.cmd = o.cmd; self.args = o.args or ""; self.relative = o.relative @@ -35,183 +20,24 @@ function Previewer.base:new(o, opts) return self end -function Previewer.base:preview_window(_) +function Previewer:preview_window(_) + utils.warn("Previewer:preview_window wasn't implemented, will use defaults") return nil 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 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 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], not self.relative and 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 vim.fn.shellescape(string.format('sh -c "%s %s %s `%s`"', - self.cmd, self.args, highlight_line, self:action(o))) -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 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 -function Previewer.cmd_async:new(o, opts) - self = setmetatable(Previewer.base(o, opts), { - __index = vim.tbl_deep_extend("keep", - self, Previewer.base - )}) - return self -end - -function Previewer.cmd_async:cmdline(o) - o = o or {} - local act = helpers.choices_to_shell_cmd_previewer(function(items) - local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) - local cmd = string.format('%s %s %s', self.cmd, self.args, vim.fn.shellescape(file.path)) - -- uncomment to see the command in the preview window - -- cmd = vim.fn.shellescape(cmd) - return cmd - end, "{}") - return act -end - -function Previewer.bat_async:new(o, opts) - self = setmetatable(Previewer.cmd_async(o, opts), { - __index = vim.tbl_deep_extend("keep", - self, Previewer.cmd_async, Previewer.base - )}) - self.theme = o.theme - return self -end - -function Previewer.bat_async:cmdline(o) - 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 = helpers.choices_to_shell_cmd_previewer(function(items) - local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) - local cmd = string.format('%s %s %s%s "%s"', - self.cmd, self.args, - highlight_line, - utils._if(#highlight_line>0, tostring(file.line), ""), - file.path) - -- uncomment to see the command in the preview window - -- cmd = vim.fn.shellescape(cmd) - return cmd - end, "{}") - return act -end - -function Previewer.git_diff:new(o, opts) - self = setmetatable(Previewer.cmd_async(o, opts), { - __index = vim.tbl_deep_extend("keep", - self, Previewer.cmd_async, Previewer.base - )}) - self.cmd = path.git_cwd(self.cmd, opts.cwd) - return self -end - -function Previewer.git_diff:cmdline(o) - o = o or {} - local act = helpers.choices_to_shell_cmd_previewer(function(items) - local is_deleted = items[1]:match("D"..utils.nbsp) ~= nil - local is_untracked = items[1]:match("?"..utils.nbsp) ~= nil - local file = path.entry_to_file(items[1], not self.relative and self.opts.cwd) - local cmd = self.cmd - local args = self.args - if is_untracked then args = args .. " --no-index /dev/null" end - if is_deleted then - cmd = self.cmd:gsub("diff", "show HEAD:") - cmd = string.format('%s"%s"', cmd, path.relative(file.path, self.opts.cwd)) - else - cmd = string.format('%s %s %s', cmd, args, vim.fn.shellescape(file.path)) - end - -- uncomment to see the command in the preview window - -- cmd = vim.fn.shellescape(cmd) - return cmd - end, "{}") - return act -end - -function Previewer.man_pages:new(o, opts) - self = setmetatable(Previewer.cmd_async(o, opts), { - __index = vim.tbl_deep_extend("keep", - self, Previewer.cmd_async, Previewer.base - )}) - return self -end - -function Previewer.man_pages:cmdline(o) - o = o or {} - local act = helpers.choices_to_shell_cmd_previewer(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 +Previewer.fzf = {} +Previewer.fzf.cmd = function() return require 'fzf-lua.previewer.fzf'.cmd end +Previewer.fzf.bat = function() return require 'fzf-lua.previewer.fzf'.bat end +Previewer.fzf.head = function() return require 'fzf-lua.previewer.fzf'.head end +Previewer.fzf.cmd_async = function() return require 'fzf-lua.previewer.fzf'.cmd_async end +Previewer.fzf.bat_async = function() return require 'fzf-lua.previewer.fzf'.bat_async end +Previewer.fzf.git_diff = function() return require 'fzf-lua.previewer.fzf'.git_diff end +Previewer.fzf.man_pages = function() return require 'fzf-lua.previewer.fzf'.man_pages end + +Previewer.builtin = {} +Previewer.builtin.buffer_or_file = function() return require 'fzf-lua.previewer.builtin'.buffer_or_file end +Previewer.builtin.help_tags = function() return require 'fzf-lua.previewer.builtin'.help_tags end +Previewer.builtin.man_pages = function() return require 'fzf-lua.previewer.builtin'.man_pages end +Previewer.builtin.marks = function() return require 'fzf-lua.previewer.builtin'.marks end return Previewer