Skip to content

Commit

Permalink
feat: vscode-like path display
Browse files Browse the repository at this point in the history
All file pickers can be added the option to display paths in vscode
formatting where the filename appears first followed by the directory.

To enable set `formatter="path.filename_first" (hardcoded in globals):
```lua
require("fzf-lua").setup({
  files = {
    formatter = "path.filename_first"
  }
})
```

Can also be sent directly in the call options, e.g:
```lua
:lua require("fzf-lua").live_grep({ formatter = "path.filename_first" })
:FzfLua lsp_finder formatter=path.filename_first
```

This commit also sets up the framework to write your own custom
formatter, if you wish to experiment with that please open an issue.

Ref: #1051
  • Loading branch information
ibhagwan committed Apr 28, 2024
1 parent 7a2d984 commit 0d09b75
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 7 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,9 @@ require'fzf-lua'.setup {
file_icons = true, -- show file icons?
color_icons = true, -- colorize file|git icons
-- path_shorten = 1, -- 'true' or number, shorten path?
-- Uncomment for custom vscode-like formatter where the filename is first:
-- e.g. "fzf-lua/previewer/fzf.lua" => "fzf.lua previewer/fzf-lua"
-- formatter = "path.filename_first",
-- executed command priority is 'cmd' (if exists)
-- otherwise auto-detect prioritizes `fd`:`rg`:`find`
-- default options are controlled by 'fd|rg|find|_opts'
Expand Down
16 changes: 16 additions & 0 deletions lua/fzf-lua/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,22 @@ function M.normalize_opts(opts, globals, __resume_key)
type(M.globals[k]) == "table" and utils.tbl_deep_clone(M.globals[k]) or {})
end

-- Setup formatter options
if opts.formatter then
local _fmt = M.globals["formatters." .. opts.formatter]
if _fmt then
opts._fmt = opts._fmt or {}
opts._fmt.to = opts._fmt.to or _fmt.to
opts._fmt.from = opts._fmt.to or _fmt.from
-- no support for `bat_native` with a formatter
if opts.previewer == "bat_native" then opts.previewer = "bat" end
-- no support of searching file begin (we can't guarantee no. of nbsp's)
opts._fzf_nth_devicons = false
else
utils.warn(("Invalid formatter '%s', ignoring."):format(opts.formatter))
end
end

-- backward compat: no-value flags should be set to `true`, in the past these
-- would be set to an empty string which would now translate into a shell escaped
-- string as we automatically shell escape all fzf_opts
Expand Down
7 changes: 5 additions & 2 deletions lua/fzf-lua/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ M.ACTION_DEFINITIONS = {
[actions.toggle_ignore] = {
function(o)
local flag = o.toggle_ignore_flag or "--no-ignore"
if o.cmd:match(utils.lua_regex_escape(flag)) then
if o.cmd and o.cmd:match(utils.lua_regex_escape(flag)) then
return "Respect .gitignore"
else
return "Disable .gitignore"
Expand Down Expand Up @@ -660,6 +660,7 @@ M.mt_cmd_wrapper = function(opts)
"stdout",
"stderr",
"stderr_to_stdout",
"formatter",
"git_dir",
"git_worktree",
"git_icons",
Expand Down Expand Up @@ -714,7 +715,9 @@ M.mt_cmd_wrapper = function(opts)
and not opts.git_icons
and not opts.file_icons
and not opts.file_ignore_patterns
and not opts.path_shorten then
and not opts.path_shorten
and not opts.formatter
then
-- command does not require any processing, we also reset `argv_expr`
-- to keep `setup_fzf_interactive_flags::no_query_condi` in the command
opts.argv_expr = nil
Expand Down
29 changes: 29 additions & 0 deletions lua/fzf-lua/defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,35 @@ M.defaults = {
pager = M._preview_pager_fn,
},
},
formatters = {
path = {
filename_first = {
-- NOT NEEDED: for perf reasons we format at the source in `make_entry.file`
-- to = function(s, _)
-- end,
from = function(s, o)
-- Which part should contain the parent folder?
-- files that are directly under cwd it will have no parent folder part
local parent_idx = (o._parent_idx or 2)
+ (o.file_icons and 1 or 0)
+ (o.git_icons and 1 or 0)
local parts = utils.strsplit(s, utils.nbsp)
if #parts == parent_idx then
local last = parts[parent_idx]
local filename = parts[parent_idx - 1]
local parent = last:match("^[^:]+")
local fullpath = path.join({ parent, filename })
-- remove the last part (parent + rest of line)
table.remove(parts, parent_idx)
-- overwrite last part with restored fullpath + rest of line
parts[#parts] = fullpath .. last:sub(#parent + 1)
s = table.concat(parts, utils.nbsp)
end
return s
end
}
}
},
}

M.defaults.files = {
Expand Down
27 changes: 22 additions & 5 deletions lua/fzf-lua/make_entry.lua
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ M.file = function(x, opts)
if opts.git_icons then
local diff_info = opts.diff_files
and opts.diff_files[utils._if_win(path.normalize(origpath), origpath)]
local indicators = diff_info and diff_info[1] or utils.nbsp
local indicators = diff_info and diff_info[1] or " "
for i = 1, #indicators do
icon = indicators:sub(i, i)
local git_icon = config.globals.git.icons[icon]
Expand All @@ -355,10 +355,27 @@ M.file = function(x, opts)
ret[#ret + 1] = icon
ret[#ret + 1] = utils.nbsp
end
ret[#ret + 1] = file_is_ansi > 0
-- filename is ansi escape colored, replace the inner string (#819)
and file_part:gsub(utils.lua_regex_escape(stripped_filepath), filepath)
or filepath
-- convert to number type for faster condition testing next entry
if opts.formatter == "path.filename_first" then
opts.formatter = 1
end
if tonumber(opts.formatter) == 1 then
-- skip ansi coloring restoration as we use our own hlgroup for the parent
local parent = path.parent(filepath)
if parent then
ret[#ret + 1] = path.tail(filepath)
ret[#ret + 1] = utils.nbsp
ret[#ret + 1] = utils.ansi_codes.grey(path.remove_trailing(parent))
-- ret[#ret + 1] = path.remove_trailing(parent)
else
ret[#ret + 1] = filepath
end
else
ret[#ret + 1] = file_is_ansi > 0
-- filename is ansi escape colored, replace the inner string (#819)
and file_part:gsub(utils.lua_regex_escape(stripped_filepath), filepath)
or filepath
end
ret[#ret + 1] = rest_of_line
return table.concat(ret)
end
Expand Down
3 changes: 3 additions & 0 deletions lua/fzf-lua/providers/git.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ M.status = function(opts)
-- as part of our `git status -s`
opts.git_icons = false

-- set parent_idx base for `formatter=path.filename_first`
opts._parent_idx = 5

-- we always require processing (can't send the raw command to fzf)
opts.requires_processing = true

Expand Down
2 changes: 2 additions & 0 deletions lua/fzf-lua/providers/lsp.lua
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,8 @@ M.finder = function(opts)
return
end
opts = core.set_fzf_field_index(opts)
-- set parent_idx base for `formatter=path.filename_first`
opts._parent_idx = 3
return core.fzf_exec(contents, opts)
end

Expand Down

0 comments on commit 0d09b75

Please sign in to comment.