From fc77943cdf8e2a5e5431eef11f4ee4053f1c4dde Mon Sep 17 00:00:00 2001 From: bhagwan Date: Thu, 3 Mar 2022 22:48:06 -0800 Subject: [PATCH] bat previewer optimization for ctags with no line numbers (#355) --- lua/fzf-lua/path.lua | 4 +-- lua/fzf-lua/previewer/fzf.lua | 58 ++++++++++++++++++++++++++++++++-- lua/fzf-lua/providers/tags.lua | 14 ++++---- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/lua/fzf-lua/path.lua b/lua/fzf-lua/path.lua index a9ca34e..9435922 100644 --- a/lua/fzf-lua/path.lua +++ b/lua/fzf-lua/path.lua @@ -139,9 +139,9 @@ local function stripBeforeLastOccurrenceOf(str, sep) end -function M.entry_to_ctag(entry) +function M.entry_to_ctag(entry, noesc) local scode = entry:match("%:.-/^?\t?(.*)/") - if scode then + if scode and not noesc then -- scode = string.gsub(scode, "[$]$", "") scode = string.gsub(scode, [[\\]], [[\]]) scode = string.gsub(scode, [[\/]], [[/]]) diff --git a/lua/fzf-lua/previewer/fzf.lua b/lua/fzf-lua/previewer/fzf.lua index 9e5179d..dc959ae 100644 --- a/lua/fzf-lua/previewer/fzf.lua +++ b/lua/fzf-lua/previewer/fzf.lua @@ -131,9 +131,53 @@ function Previewer.cmd_async:new(o, opts) return self end +local grep_tag = function(file, tag) + local line = 1 + local filepath = file + local pattern = utils.rg_escape(tag) + if not pattern or not filepath then return line end + local grep_cmd = vim.fn.executable("rg") == 1 + and {"rg", "--line-number"} + or {"grep", "-n", "-P"} + -- ctags uses '$' at the end of short patterns + -- 'rg|grep' does not match these properly when + -- 'fileformat' isn't set to 'unix', when set to + -- 'dos' we need to prepend '$' with '\r$' with 'rg' + -- it is simpler to just ignore it compleley. + --[[ local ff = fileformat(filepath) + if ff == 'dos' then + pattern = pattern:gsub("\\%$$", "\\r%$") + else + pattern = pattern:gsub("\\%$$", "%$") + end --]] + -- equivalent pattern to `rg --crlf` + -- see discussion in #219 + pattern = pattern:gsub("\\%$$", "\\r??%$") + local cmd = utils.tbl_deep_clone(grep_cmd) + table.insert(cmd, pattern) + table.insert(cmd, filepath) + local out = utils.io_system(cmd) + if not utils.shell_error() then + line = out:match("[^:]+") + end + -- if line == 1 then print(cmd) end + return line +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 '' + if self.opts._ctag and entry.line<=1 then + -- tags without line numbers + -- make sure we don't already have line # + -- (in the case the line no. is actually 1) + local line = entry.stripped:match("[^:]+(%d+):") + local ctag = path.entry_to_ctag(entry.stripped, true) + if not line and ctag then + entry.ctag = ctag + entry.line = grep_tag(filepath, entry.ctag) + end + end local errcmd = nil -- verify the file exists on disk and is accessible if #filepath==0 or not vim.loop.fs_stat(filepath) then @@ -166,12 +210,22 @@ end function Previewer.bat_async:cmdline(o) o = o or {} - local act = shell.preview_action_cmd(function(items) + local act = shell.preview_action_cmd(function(items, fzf_lines) local filepath, entry, errcmd = self:parse_entry_and_verify(items[1]) - local cmd = errcmd or ('%s %s %s %s'):format( + local line_range = '' + if entry.ctag then + -- this is a ctag without line numbers, since we can't + -- provide the preview file offset to fzf via the field + -- index expression we use '--line-range' instead + local start_line = math.max(1, entry.line-fzf_lines/2) + local end_line = start_line + fzf_lines-1 + line_range = ("--line-range=%d:%d"):format(start_line, end_line) + end + local cmd = errcmd or ('%s %s %s %s %s'):format( self.cmd, self.args, self.opts.line_field_index and ("--highlight-line=%d"):format(entry.line) or '', + line_range, vim.fn.shellescape(filepath)) -- uncomment to see the command in the preview window -- cmd = vim.fn.shellescape(cmd) diff --git a/lua/fzf-lua/providers/tags.lua b/lua/fzf-lua/providers/tags.lua index 539b0fc..f8a122a 100644 --- a/lua/fzf-lua/providers/tags.lua +++ b/lua/fzf-lua/providers/tags.lua @@ -176,17 +176,19 @@ local function get_tags_cmd(opts) end local function tags(opts) - opts.ctags_file = opts.ctags_file and vim.fn.expand(opts.ctags_file) or "tags" - - if not vim.loop.fs_open(opts.ctags_file, "r", 438) then - utils.info("Tags file does not exists. Create one with ctags -R") - return - end -- signal actions this is a ctag opts._ctag = true + opts.ctags_file = opts.ctags_file and vim.fn.expand(opts.ctags_file) or "tags" opts._ctags_file = opts.cwd and path.join({opts.cwd, opts.ctags_file}) or opts.ctags_file opts._curr_file = opts._curr_file and path.relative(opts._curr_file, opts.cwd or vim.loop.cwd()) + + if not vim.loop.fs_stat(opts._ctags_file) then + utils.info(("Tags file ('%s') does not exists. Create one with ctags -R") + :format(opts._ctags_file)) + return + end + opts.cmd = opts.cmd or get_tags_cmd(opts) opts._fn_transform = make_entry.tag -- multiprocess=false opts._fn_transform_str = [[return require("make_entry").tag]] -- multiprocess=true