From b614a9d315512ec4ce9c1df41474e5ab8e12f7df Mon Sep 17 00:00:00 2001 From: bhagwan Date: Fri, 6 May 2022 17:38:41 -0700 Subject: [PATCH] feat: file providers now support 'path_shorten' (#408) --- README.md | 1 + doc/fzf-lua.txt | 1 + lua/fzf-lua/actions.lua | 4 +-- lua/fzf-lua/core.lua | 3 +- lua/fzf-lua/make_entry.lua | 3 ++ lua/fzf-lua/path.lua | 50 +++++++++++++++++++++++-------- lua/fzf-lua/previewer/builtin.lua | 2 +- lua/fzf-lua/previewer/fzf.lua | 6 ++-- lua/fzf-lua/providers/dap.lua | 2 +- 9 files changed, 52 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 86b9b5b..c8c86f4 100644 --- a/README.md +++ b/README.md @@ -477,6 +477,7 @@ require'fzf-lua'.setup { git_icons = true, -- show git icons? file_icons = true, -- show file icons? color_icons = true, -- colorize file|git icons + -- path_shorten = 1, -- 'true' or number, shorten path? -- executed command priority is 'cmd' (if exists) -- otherwise auto-detect prioritizes `fd`:`rg`:`find` -- default options are controlled by 'fd|rg|find|_opts' diff --git a/doc/fzf-lua.txt b/doc/fzf-lua.txt index a2709a2..2f13d5f 100644 --- a/doc/fzf-lua.txt +++ b/doc/fzf-lua.txt @@ -522,6 +522,7 @@ Consult the list below for available settings: git_icons = true, -- show git icons? file_icons = true, -- show file icons? color_icons = true, -- colorize file|git icons + -- path_shorten = 1, -- 'true' or number, shorten path? -- executed command priority is 'cmd' (if exists) -- otherwise auto-detect prioritizes `fd`:`rg`:`find` -- default options are controlled by 'fd|rg|find|_opts' diff --git a/lua/fzf-lua/actions.lua b/lua/fzf-lua/actions.lua index aaf9241..7b7a2b1 100644 --- a/lua/fzf-lua/actions.lua +++ b/lua/fzf-lua/actions.lua @@ -86,7 +86,7 @@ M.vimcmd_file = function(vimcmd, selected, opts) local curbuf = vim.api.nvim_buf_get_name(0) local is_term = utils.is_term_buffer(0) for i = 1, #selected do - local entry = path.entry_to_file(selected[i], opts.cwd, opts.force_uri) + local entry = path.entry_to_file(selected[i], opts) entry.ctag = opts._ctag and path.entry_to_ctag(selected[i]) local fullpath = entry.path or entry.uri and entry.uri:match("^%a+://(.*)") if not path.starts_with_separator(fullpath) then @@ -476,7 +476,7 @@ end local git_exec = function(selected, opts, cmd) for _, e in ipairs(selected) do - local file = path.relative(path.entry_to_file(e, opts.cwd).path, opts.cwd) + local file = path.relative(path.entry_to_file(e, opts).path, opts.cwd) local _cmd = vim.deepcopy(cmd) table.insert(_cmd, file) local output = utils.io_systemlist(_cmd) diff --git a/lua/fzf-lua/core.lua b/lua/fzf-lua/core.lua index 0021357..d52428c 100644 --- a/lua/fzf-lua/core.lua +++ b/lua/fzf-lua/core.lua @@ -345,6 +345,7 @@ M.mt_cmd_wrapper = function(opts) "git_icons", "file_icons", "color_icons", + "path_shorten", "strip_cwd_prefix", "rg_glob", "__module__", @@ -524,7 +525,7 @@ M.fzf_files = function(opts, contents) if #selected > 1 then local idx = utils.tbl_length(opts.actions)>1 and 2 or 1 for i = idx, #selected do - selected[i] = path.entry_to_file(selected[i], opts.cwd).stripped + selected[i] = path.entry_to_file(selected[i], opts).stripped end end diff --git a/lua/fzf-lua/make_entry.lua b/lua/fzf-lua/make_entry.lua index 7aff4e3..102dd71 100644 --- a/lua/fzf-lua/make_entry.lua +++ b/lua/fzf-lua/make_entry.lua @@ -312,6 +312,9 @@ M.file = function(opts, x) -- TODO: does this work if there are ANSI escape codes in x? x = path.relative(x, opts.cwd) end + if opts.path_shorten then + x = path.shorten(x, tonumber(opts.path_shorten)) + end if opts.git_icons then local indicators = opts.diff_files and opts.diff_files[file] or utils.nbsp for i=1,#indicators do diff --git a/lua/fzf-lua/path.lua b/lua/fzf-lua/path.lua index eaede26..324ccc9 100644 --- a/lua/fzf-lua/path.lua +++ b/lua/fzf-lua/path.lua @@ -1,4 +1,5 @@ local utils = require "fzf-lua.utils" +local string_sub = string.sub local string_byte = string.byte local M = {} @@ -115,19 +116,35 @@ function M.remove_trailing(path) return p end -function M.shorten(path, max_length) - if string.len(path) > max_length - 1 then - path = path:sub(string.len(path) - max_length + 1, string.len(path)) - local i = path:match("()" .. M.separator()) - if not i then - return "…" .. path +local function find_next(str, char, start_idx) + local i_char = string_byte(char, 1) + for i=start_idx or 1,#str do + if string_byte(str, i) == i_char then + return i end - return "…" .. path:sub(i, -1) - else - return path end end +function M.shorten(path, max_len) + local sep = M.separator() + local parts = {} + local start_idx = 1 + max_len = max_len or 1 + repeat + local i = find_next(path, sep, start_idx) + local end_idx = i and start_idx+math.min(i-start_idx, max_len)-1 or nil + table.insert(parts, string_sub(path, start_idx, end_idx)) + if i then start_idx = i+1 end + until not i + return table.concat(parts, sep) +end + +function M.lengthen(path) + return vim.fn.glob(path:gsub(M.separator(), "%*"..M.separator()) + -- remove the starting '*/' if any + :gsub("^%*"..M.separator(), M.separator())) +end + local function lastIndexOf(haystack, needle) local i=haystack:match(".*"..needle.."()") if i==nil then return nil else return i-1 end @@ -156,10 +173,13 @@ function M.entry_to_ctag(entry, noesc) return ctag end -function M.entry_to_location(entry) +function M.entry_to_location(entry, opts) local uri, line, col = entry:match("^(.*://.*):(%d+):(%d+):") line = line and tonumber(line) or 1 col = col and tonumber(col) or 1 + if opts and opts.path_shorten then + uri = uri:match("^.*://") .. M.lengthen(uri:match("^.*://(.*)")) + end return { stripped = entry, line = line, @@ -174,7 +194,10 @@ function M.entry_to_location(entry) } end -function M.entry_to_file(entry, cwd, force_uri) +function M.entry_to_file(entry, opts) + opts = opts or {} + local cwd = opts.cwd + local force_uri = opts.force_uri -- Remove ansi coloring and prefixed icons entry = utils.strip_ansi_coloring(entry) local stripped, idx = stripBeforeLastOccurrenceOf(entry, utils.nbsp) @@ -202,7 +225,7 @@ function M.entry_to_file(entry, cwd, force_uri) -- 'lua require('jdtls').open_jdt_link(vim.fn.expand('jdt://...'))' -- Convert to location item so we can use 'jump_to_location' -- This can also work with any 'file://' prefixes - return M.entry_to_location(stripped) + return M.entry_to_location(stripped, opts) end local s = utils.strsplit(stripped, ":") if not s[1] then return {} end @@ -216,6 +239,9 @@ function M.entry_to_file(entry, cwd, force_uri) file, line = stripped:match("([^:]+):(%d+)") end end + if opts.path_shorten then + file = M.lengthen(file) + end return { stripped = stripped, bufnr = tonumber(bufnr), diff --git a/lua/fzf-lua/previewer/builtin.lua b/lua/fzf-lua/previewer/builtin.lua index b50567e..7e01c18 100644 --- a/lua/fzf-lua/previewer/builtin.lua +++ b/lua/fzf-lua/previewer/builtin.lua @@ -280,7 +280,7 @@ function Previewer.buffer_or_file:close() end function Previewer.buffer_or_file:parse_entry(entry_str) - local entry = path.entry_to_file(entry_str, self.opts.cwd) + local entry = path.entry_to_file(entry_str, self.opts) return entry end diff --git a/lua/fzf-lua/previewer/fzf.lua b/lua/fzf-lua/previewer/fzf.lua index ba5fbe8..e77a449 100644 --- a/lua/fzf-lua/previewer/fzf.lua +++ b/lua/fzf-lua/previewer/fzf.lua @@ -76,7 +76,7 @@ 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], self.opts.cwd) + local entry = path.entry_to_file(items[1], self.opts) return entry.bufname or entry.path end, self.opts.field_index_expr or "{}") return act @@ -166,7 +166,7 @@ local grep_tag = function(file, tag) end function Previewer.cmd_async:parse_entry_and_verify(entrystr) - local entry = path.entry_to_file(entrystr, self.opts.cwd) + local entry = path.entry_to_file(entrystr, self.opts) local filepath = entry.bufname or entry.path or '' if self.opts._ctag and entry.line<=1 then -- tags without line numbers @@ -274,7 +274,7 @@ function Previewer.git_diff:cmdline(o) self.git_icons['?'] .. self.git_icons['C'] .. "]"..utils.nbsp) ~= nil - local file = path.entry_to_file(items[1], self.opts.cwd) + local file = path.entry_to_file(items[1], self.opts) local cmd = nil if is_modified then cmd = self.cmd_modified elseif is_deleted then cmd = self.cmd_deleted diff --git a/lua/fzf-lua/providers/dap.lua b/lua/fzf-lua/providers/dap.lua index 9738657..852dc77 100644 --- a/lua/fzf-lua/providers/dap.lua +++ b/lua/fzf-lua/providers/dap.lua @@ -123,7 +123,7 @@ M.breakpoints = function(opts) { function(selected, o) for _, e in ipairs(selected) do - local entry = path.entry_to_file(e, o.cwd) + local entry = path.entry_to_file(e, o) if entry.bufnr>0 and entry.line then dap_bps.remove(entry.bufnr, entry.line) end