Skip to content

Commit

Permalink
Merge branch 'master' into feat/tree
Browse files Browse the repository at this point in the history
  • Loading branch information
fdschmidt93 committed Mar 25, 2023
2 parents cfc393b + ff558dd commit 74f7ecd
Show file tree
Hide file tree
Showing 11 changed files with 578 additions and 140 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
doc/tags
7 changes: 7 additions & 0 deletions .luarc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"diagnostics.globals": [
"vim",
"describe",
"it"
]
}
274 changes: 192 additions & 82 deletions README.md

Large diffs are not rendered by default.

20 changes: 16 additions & 4 deletions lua/telescope/_extensions/file_browser/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,10 @@ fb_actions.goto_parent_dir = function(prompt_bufnr, bypass)

finder.path = parent_dir
fb_utils.redraw_border_title(current_picker)
current_picker:refresh(finder, { reset_prompt = true, multi = current_picker._multi })
current_picker:refresh(
finder,
{ new_prefix = fb_utils.relative_path_prefix(finder), reset_prompt = true, multi = current_picker._multi }
)
end

--- Goto working directory of nvim in |telescope-file-browser.picker.file_browser|.
Expand All @@ -577,7 +580,10 @@ fb_actions.goto_cwd = function(prompt_bufnr)
finder.path = vim.loop.cwd()

fb_utils.redraw_border_title(current_picker)
current_picker:refresh(finder, { reset_prompt = true, multi = current_picker._multi })
current_picker:refresh(
finder,
{ new_prefix = fb_utils.relative_path_prefix(finder), reset_prompt = true, multi = current_picker._multi }
)
end

--- Change working directory of nvim to the selected file/folder in |telescope-file-browser.picker.file_browser|.
Expand All @@ -591,7 +597,10 @@ fb_actions.change_cwd = function(prompt_bufnr)
vim.cmd("cd " .. finder.path)

fb_utils.redraw_border_title(current_picker)
current_picker:refresh(finder, { reset_prompt = true, multi = current_picker._multi })
current_picker:refresh(
finder,
{ new_prefix = fb_utils.relative_path_prefix(finder), reset_prompt = true, multi = current_picker._multi }
)
fb_utils.notify(
"action.change_cwd",
{ msg = "Set the current working directory!", level = "INFO", quiet = finder.quiet }
Expand All @@ -606,7 +615,10 @@ fb_actions.goto_home_dir = function(prompt_bufnr)
finder.path = vim.loop.os_homedir()

fb_utils.redraw_border_title(current_picker)
current_picker:refresh(finder, { reset_prompt = true, multi = current_picker._multi })
current_picker:refresh(
finder,
{ new_prefix = fb_utils.relative_path_prefix(finder), reset_prompt = true, multi = current_picker._multi }
)
end

--- Toggle between file and folder browser for |telescope-file-browser.picker.file_browser|.
Expand Down
5 changes: 4 additions & 1 deletion lua/telescope/_extensions/file_browser/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ _TelescopeFileBrowserConfig = {

finder.path = path
fb_utils.redraw_border_title(current_picker)
current_picker:refresh(finder, { reset_prompt = true, multi = current_picker._multi })
current_picker:refresh(
finder,
{ new_prefix = fb_utils.relative_path_prefix(finder), reset_prompt = true, multi = current_picker._multi }
)
end)
return true
end,
Expand Down
45 changes: 36 additions & 9 deletions lua/telescope/_extensions/file_browser/finders.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
local fb_utils = require "telescope._extensions.file_browser.utils"
local fb_tree = require "telescope._extensions.file_browser.tree"
local fb_make_entry = require "telescope._extensions.file_browser.make_entry"
local fb_git = require "telescope._extensions.file_browser.git"

local async_oneshot_finder = require "telescope.finders.async_oneshot_finder"
local finders = require "telescope.finders"
Expand All @@ -19,6 +20,7 @@ local Job = require "plenary.job"
local os_sep = Path.path.sep

local fb_finders = {}

local has_fd = vim.fn.executable "fd" == 1

--- Harmonize fd opts for lua config with plenary.scandir in mind.
Expand Down Expand Up @@ -126,15 +128,17 @@ fb_finders.browser = function(opts)
opts = opts or {}

-- returns copy with properly set cwd for entry maker
local entry_maker = opts.entry_maker {
cwd = opts.path,
path_display = opts.path_display,
}
local parent_path = Path:new(opts.path):parent():absolute()
local needs_sync = opts.auto_depth ~= true and (opts.grouped or opts.select_buffer)
local needs_sync = opts.auto_depth ~= true and (opts.grouped or opts.select_buffer or opts.git_status)
local data
if has_fd then

if has_fd and opts.use_fd then
if not needs_sync then
local entry_maker = opts.entry_maker {
cwd = opts.path,
path_display = opts.path_display,
git_file_status = {},
}
return async_oneshot_finder {
fn_command = function()
return { command = "fd", args = fb_finders.fd_args(opts) }
Expand All @@ -155,13 +159,30 @@ fb_finders.browser = function(opts)
respect_gitignore = opts.respect_gitignore,
})
end

local git_file_status = {}
if opts.git_status then
-- use dot args to also catch renames which also require the old filename
-- to properly show it as a rename.
local git_status, _ = Job:new({ cwd = opts.path, command = "git", args = { "status", "--porcelain", "--", "." } })
:sync()
git_file_status = fb_git.parse_status_output(git_status, opts.path)
end
if opts.path ~= os_sep and not opts.hide_parent_dir then
table.insert(data, 1, parent_path)
end
if opts.grouped then
fb_utils.group_by_type(data)
end
return finders.new_table { results = data, entry_maker = entry_maker }
local entry_maker = opts.entry_maker {
cwd = opts.path,
path_display = opts.path_display,
git_file_status = git_file_status,
}
return finders.new_table {
results = data,
entry_maker = entry_maker,
}
end

local deprecation_notices = function(opts)
Expand Down Expand Up @@ -194,21 +215,24 @@ local deprecation_notices = function(opts)
end
end

local MERGE_KEYS = { "depth", "respect_gitignore", "hidden", "grouped", "select_buffer" }
-- opts agnostic between [files, folders, tree]
local MERGE_KEYS = { "depth", "respect_gitignore", "hidden", "grouped", "select_buffer", "use_fd", "git_status" }

--- Returns a finder that combines |fb_finders.browse_files| and |fb_finders.browse_folders| into a unified finder.
---@param opts table: options to pass to the picker
---@field path string: root dir to file_browse from (default: vim.loop.cwd())
---@field cwd string: root dir (default: vim.loop.cwd())
---@field follow boolean: folder browser follows `path` of file browser
---@field files boolean: start in file (true) or folder (false) browser (default: true)
---@field grouped boolean: group initial sorting by directories and then files; uses plenary.scandir (default: false)
---@field grouped boolean: group initial sorting by directories and then files (default: false)
---@field depth number: file tree depth to display (default: 1)
---@field hidden boolean: determines whether to show hidden files or not (default: false)
---@field respect_gitignore boolean: induces slow-down w/ plenary finder (default: false, true if `fd` available)
---@field hide_parent_dir boolean: hide `../` in the file browser (default: false)
---@field dir_icon string: change the icon for a directory (default: )
---@field dir_icon_hl string: change the highlight group of dir icon (default: "Default")
---@field use_fd boolean: use `fd` if available over `plenary.scandir` (default: true)
---@field git_status boolean: show the git status of files (default: true)
fb_finders.finder = function(opts)
opts = opts or {}

Expand Down Expand Up @@ -263,6 +287,7 @@ fb_finders.finder = function(opts)
collapse_dirs = vim.F.if_nil(opts.collapse_dirs, false),
_in_auto_depth = false,
_is_tree = false,
git_status = vim.F.if_nil(opts.git_status, true),
-- ensure we forward make_entry opts adequately
entry_maker = vim.F.if_nil(opts.entry_maker, function(local_opts)
return fb_make_entry(vim.tbl_extend("force", opts, local_opts))
Expand All @@ -272,6 +297,8 @@ fb_finders.finder = function(opts)
end,
prompt_title = opts.custom_prompt_title,
results_title = opts.custom_results_title,
prompt_path = opts.prompt_path,
use_fd = vim.F.if_nil(opts.use_fd, true),
}, {
-- call dynamically sanitizes the opts between browsers to invoke the correct browser with the appropriate opts
__call = function(self, ...)
Expand Down
106 changes: 106 additions & 0 deletions lua/telescope/_extensions/file_browser/git.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
local Job = require "plenary.job"
local fb_utils = require "telescope._extensions.file_browser.utils"

local M = {}

-- icon defaults are taken from Telescope git_status icons
local icon_defaults = {
added = "+",
changed = "~",
copied = ">",
deleted = "-",
renamed = "",
unmerged = "",
untracked = "?",
}

local empty_status = " "

--- Returns a display item for use in a display array based on a git status
---@param opts table: configuration options to override defaults
---@param status string: the string to convert to a display item
---@return table: a display item
M.make_display = function(opts, status)
if status == " " or status == nil then
return { empty_status }
end
local icons = vim.tbl_extend("keep", opts.git_icons or {}, icon_defaults)

-- X Y Meaning
-- -------------------------------------------------
-- [AMD] not updated
-- M [ MTD] updated in index
-- T [ MTD] type changed in index
-- A [ MTD] added to index
-- D deleted from index
-- R [ MTD] renamed in index
-- C [ MTD] copied in index
-- [MTARC] index and work tree matches
-- [ MTARC] M work tree changed since index
-- [ MTARC] T type changed in work tree since index
-- [ MTARC] D deleted in work tree
-- R renamed in work tree
-- C copied in work tree
-- -------------------------------------------------
-- D D unmerged, both deleted
-- A U unmerged, added by us
-- U D unmerged, deleted by them
-- U A unmerged, added by them
-- D U unmerged, deleted by us
-- A A unmerged, both added
-- U U unmerged, both modified
-- -------------------------------------------------
-- ? ? untracked
-- ! ! ignored
-- -------------------------------------------------
local git_abbrev = {
["M"] = { icon = icons.changed, hl = "TelescopeResultsDiffChange" },
["T"] = { icon = icons.changed, hl = "TelescopeResultsDiffChange" },
["D"] = { icon = icons.deleted, hl = "TelescopeResultsDiffDelete" },
["A"] = { icon = icons.added, hl = "TelescopeResultsDiffAdd" },
["R"] = { icon = icons.renamed, hl = "TelescopeResultsDiffChange" },
["C"] = { icon = icons.copied, hl = "TelescopeResultsDiffChange" },
}
local git_unmerged_or_unknown = {
-- unmerged
["DD"] = { icon = icons.unmerged, hl = "TelescopeResultsDiffChange" },
["AU"] = { icon = icons.unmerged, hl = "TelescopeResultsDiffChange" },
["UD"] = { icon = icons.unmerged, hl = "TelescopeResultsDiffChange" },
["UA"] = { icon = icons.unmerged, hl = "TelescopeResultsDiffChange" },
["DU"] = { icon = icons.unmerged, hl = "TelescopeResultsDiffChange" },
["AA"] = { icon = icons.unmerged, hl = "TelescopeResultsDiffChange" },
["UU"] = { icon = icons.unmerged, hl = "TelescopeResultsDiffChange" },
-- unknown
["??"] = { icon = icons.untracked, hl = "TelescopeResultsDiffUntracked" },
["!!"] = { icon = icons.untracked, hl = "TelescopeResultsDiffUntracked" },
}
local status_config = git_unmerged_or_unknown[status]
if status_config ~= nil then
return { status_config.icon or empty_status, status_config.hl }
end

-- in case the status is not a merge conflict or an unknwon file, we will
-- parse both staged (X) and unstaged (Y) individually to display partially
-- staged files correctly. In case there are staged changes it displays
-- the staged hl group.
local staged = git_abbrev[status:sub(1, 1)] or { icon = " " }
local unstaged = git_abbrev[status:sub(2, 2)] or { icon = " " }
return { staged.icon .. unstaged.icon, unstaged.hl or "TelescopeResultsDiffAdd" }
end

--- Returns a map of absolute file path to file status
---@param output table: lines of the git status output
---@param cwd string: cwd of the picker
---@return table: map from absolute file paths to files status
M.parse_status_output = function(output, cwd)
local git_root, _ = Job:new({ cwd = cwd, command = "git", args = { "rev-parse", "--show-toplevel" } }):sync()
git_root = fb_utils.sanitize_dir(git_root[1], true)
local parsed = {}
for _, value in ipairs(output) do
local mod, file = value:match "^(..) (.+)$"
parsed[git_root .. file] = mod
end
return parsed
end

return M

0 comments on commit 74f7ecd

Please sign in to comment.