Skip to content

Commit

Permalink
feat(files): add set_branch()
Browse files Browse the repository at this point in the history
It modifies which paths are attempted to be displayed in explorer.
Can be used to power all kinds of workflows:
- Reveal ancestor/descendant directory.
- Restore some previously visited branch.
- Show path from a set of bookmarks.
- And more.

Resolve #928
  • Loading branch information
echasnovski committed Sep 1, 2024
1 parent 07837f7 commit c632364
Show file tree
Hide file tree
Showing 10 changed files with 443 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- FEATURE: make data for `MiniFilesActionDelete` contain `to` field in case of not permanent delete.
- FEATURE: make file manipulation work better for special complex/overlapping cases (like delete 'file-a' and copy 'file-b' as 'file-a'). It is **still** a better idea to split overlapping manipulations into smaller and not related steps, as there *are* cases which won't work.
- FEATURE: add `get_explorer_state()` to allow more reliable user customizations.
- FEATURE: add `set_branch()` to allow to set what paths should be displayed and focused.
- BREAKING: soft deprecate `get_target_window()` in favor of `get_explorer_state().target_window`. Will be completely removed after the next release.
- BREAKING: update how confirmation lines are computed:
- Show create actions in the group directory where text manipulation took place. This matters during creating nested entries and is usually a more intuitive representation.
Expand Down
23 changes: 22 additions & 1 deletion doc/mini-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,8 @@ Return ~
shown in the window) fields.

See also ~
|MiniFiles.set_target_window()|
- |MiniFiles.set_target_window()|
- |MiniFiles.set_branch()|

------------------------------------------------------------------------------
*MiniFiles.get_target_window()*
Expand All @@ -837,6 +838,26 @@ Set target window
Parameters ~
{win_id} `(number)` Window identifier inside which file will be opened.

------------------------------------------------------------------------------
*MiniFiles.set_branch()*
`MiniFiles.set_branch`({branch}, {opts})
Set branch

Set which paths to display. Preview (if enabled) is applied afterwards.

Parameters ~
{branch} `(table)` Array of strings representing actually present on disk paths.
Each consecutive pair should represent direct parent-child paths.
Should contain at least one directory path.
May end with file path (will be previwed).
Relative paths are resolved using |current-directory|.
{opts} `(table|nil)` Options. Possible fields:
- <depth_focus> `(number)` - an index in `branch` for path to focus. Will
be normalized to fit inside `branch`. Default: index of deepest directory.

See also ~
|MiniFiles.get_explorer_state()|

------------------------------------------------------------------------------
*MiniFiles.get_latest_path()*
`MiniFiles.get_latest_path`()
Expand Down
68 changes: 67 additions & 1 deletion lua/mini/files.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,8 @@ end
--- Each element is a table with <win_id> (window identifier) and <path> (path
--- shown in the window) fields.
---
---@seealso |MiniFiles.set_target_window()|
---@seealso - |MiniFiles.set_target_window()|
--- - |MiniFiles.set_branch()|
MiniFiles.get_explorer_state = function()
local explorer = H.explorer_get()
if explorer == nil then return end
Expand Down Expand Up @@ -1053,6 +1054,49 @@ MiniFiles.set_target_window = function(win_id)
explorer.target_window = win_id
end

--- Set branch
---
--- Set which paths to display. Preview (if enabled) is applied afterwards.
---
---@param branch table Array of strings representing actually present on disk paths.
--- Each consecutive pair should represent direct parent-child paths.
--- Should contain at least one directory path.
--- May end with file path (will be previwed).
--- Relative paths are resolved using |current-directory|.
---@param opts table|nil Options. Possible fields:
--- - <depth_focus> `(number)` - an index in `branch` for path to focus. Will
--- be normalized to fit inside `branch`. Default: index of deepest directory.
---
---@seealso |MiniFiles.get_explorer_state()|
MiniFiles.set_branch = function(branch, opts)
local explorer = H.explorer_get()
if explorer == nil then return end

-- Validate and normalize input
branch = H.validate_branch(branch)
opts = opts or {}
local depth_focus = opts.depth_focus or math.huge
if type(depth_focus) ~= 'number' then H.error('`depth_focus` should be a number') end
local max_depth = #branch - (H.fs_get_type(branch[#branch]) == 'file' and 1 or 0)
depth_focus = math.min(math.max(math.floor(depth_focus), 1), max_depth)

-- Set data and ensure cursors are on child entries
explorer.branch, explorer.depth_focus = branch, depth_focus
for i = 1, #branch - 1 do
local parent, child = branch[i], H.fs_get_basename(branch[i + 1])
local parent_view = explorer.views[parent] or {}
parent_view.cursor = child
explorer.views[parent] = parent_view
end

-- Skip update cursors, as they are already set
H.explorer_refresh(explorer, { skip_update_cursor = true })
-- Refresh second time to ensure that preview is shown. Doing that in other
-- way is not really feasible, as it requires knowing cursor at deepest path,
-- which might not yet be set before first refresh.
H.explorer_refresh(explorer)
end

--- Get latest used anchor path
---
--- Note: if latest used `path` argument for |MiniFiles.open()| was for file,
Expand Down Expand Up @@ -2703,6 +2747,25 @@ H.validate_line = function(buf_id, x)
return x
end

H.validate_branch = function(x)
if not (H.islist(x) and x[1] ~= nil) then H.error('`branch` should be array with at least one element') end
local res = {}
for i, p in ipairs(x) do
if type(p) ~= 'string' then H.error('`branch` contains not string: ' .. vim.inspect(p)) end
p = H.fs_full_path(p)
if not H.fs_is_present_path(p) then H.error('`branch` contains not present path: ' .. vim.inspect(p)) end
res[i] = p
end
for i = 2, #res do
local parent, child = res[i - 1], res[i]
if (parent .. '/' .. child:match('[^/]+$')) ~= res[i] then
H.error('`branch` contains not a parent-child pair: ' .. vim.inspect(parent) .. ' and ' .. vim.inspect(child))
end
end
if #res == 1 and H.fs_get_type(res[1]) == 'file' then H.error('`branch` should contain at least one directory') end
return res
end

-- Utilities ------------------------------------------------------------------
H.error = function(msg) error(string.format('(mini.files) %s', msg), 0) end

Expand Down Expand Up @@ -2743,4 +2806,7 @@ H.get_first_valid_normal_window = function()
end
end

-- TODO: Remove after compatibility with Neovim=0.9 is dropped
H.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist

return MiniFiles
27 changes: 27 additions & 0 deletions tests/screenshots/tests-test_files.lua---set_branch()---works
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--|---------|---------|---------|
01|┌…ts/dir-files/common┐
02|│ .a-dir │
03|│ a-dir │
04|│ b-dir │
05|│ .a-file │
06|│ a-file │
07|│ A-file-2 │
08|│ b-file │
09|└────────────────────┘
10|~
11|~
12| 1,10-8 All

--|---------|---------|---------|
01|011111111111111111111022222222
02|033333333444444444444055555555
03|066666667777777777777055555555
04|066666667777777777777055555555
05|077777777777777777777055555555
06|077777777777777777777055555555
07|077777777777777777777055555555
08|077777777777777777777055555555
09|000000000000000000000055555555
10|555555555555555555555555555555
11|555555555555555555555555555555
12|222222222222222222222222222222
27 changes: 27 additions & 0 deletions tests/screenshots/tests-test_files.lua---set_branch()---works-002
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--|---------|---------|---------|
01|┌…-files/common/a-dir┐
02|│ aa-dir │
03|│ aa-file │
04|│ ab-file │
05|└────────────────────┘
06|~
07|~
08|~
09|~
10|~
11|~
12| 1,10-8 All

--|---------|---------|---------|
01|011111111111111111111022222222
02|033333333444444444444055555555
03|066666666666666666666055555555
04|066666666666666666666055555555
05|000000000000000000000055555555
06|555555555555555555555555555555
07|555555555555555555555555555555
08|555555555555555555555555555555
09|555555555555555555555555555555
10|555555555555555555555555555555
11|555555555555555555555555555555
12|222222222222222222222222222222
27 changes: 27 additions & 0 deletions tests/screenshots/tests-test_files.lua---set_branch()---works-003
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--|---------|---------|---------|---------|
01|┌…es/common┐┌a-dir───────────────┐
02|│ .a-dir ││ aa-dir │
03|│ a-dir ││ aa-file │
04|│ b-dir ││ ab-file │
05|│ .a-file │└────────────────────┘
06|│ a-file │
07|│ A-file-2│
08|│ b-file │
09|└──────────┘
10|~
11|~
12| 1,10-8 All

--|---------|---------|---------|---------|
01|0111111111100222220000000000000000333333
02|0444444445500666666667777777777770888888
03|0666666677700555555555555555555550888888
04|0444444455500555555555555555555550888888
05|0555555555500000000000000000000000888888
06|0555555555508888888888888888888888888888
07|0555555555508888888888888888888888888888
08|0555555555508888888888888888888888888888
09|0000000000008888888888888888888888888888
10|8888888888888888888888888888888888888888
11|8888888888888888888888888888888888888888
12|3333333333333333333333333333333333333333
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--|---------|---------|---------|---------|
01|┌…ests/dir-files/real┐┌LICENSE───┐
02|│ a.lua ││ │
03|│ b.txt │└──────────┘
04|│ c.gif │
05|│ LICENSE │
06|│ Makefile │
07|│ top-secret │
08|└────────────────────┘
09|~
10|~
11|~
12| 4,10-8 All

--|---------|---------|---------|---------|
01|0111111111111111111110022222220000333333
02|0444444444444444444440055555555550666666
03|0444444444444444444440000000000000666666
04|0444444444444444444440666666666666666666
05|0555555555555555555550666666666666666666
06|0444444444444444444440666666666666666666
07|0444444444444444444440666666666666666666
08|0000000000000000000000666666666666666666
09|6666666666666666666666666666666666666666
10|6666666666666666666666666666666666666666
11|6666666666666666666666666666666666666666
12|3333333333333333333333333333333333333333
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--|---------|---------|---------|---------|
01|┌…ests/dir-files/real┐┌LICENSE────────┐
02|│ a.lua ││ │
03|│ b.txt │└───────────────┘
04|│ c.gif │
05|│ LICENSE │
06|│ Makefile │
07|│ top-secret │
08|└────────────────────┘
09|~
10|~
11|~
12| 4,10-8 All

--|---------|---------|---------|---------|
01|0111111111111111111110022222220000000003
02|0444444444444444444440055555555555555506
03|0444444444444444444440000000000000000006
04|0444444444444444444440666666666666666666
05|0555555555555555555550666666666666666666
06|0444444444444444444440666666666666666666
07|0444444444444444444440666666666666666666
08|0000000000000000000000666666666666666666
09|6666666666666666666666666666666666666666
10|6666666666666666666666666666666666666666
11|6666666666666666666666666666666666666666
12|3333333333333333333333333333333333333333
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--|---------|---------|---------|---------|
01|┌…ts/dir-files/common┐┌.a-dir─────────┐
02|│ .a-dir ││ aa-file │
03|│ a-dir ││ ab-file │
04|│ b-dir │└───────────────┘
05|│ .a-file │
06|│ a-file │
07|│ A-file-2 │
08|│ b-file │
09|└────────────────────┘
10|~
11|~
12| 1,10-8 All

--|---------|---------|---------|---------|
01|0111111111111111111110022222200000000003
02|0444444445555555555550055555555555555506
03|0777777788888888888880088888888888888806
04|0777777788888888888880000000000000000006
05|0888888888888888888880666666666666666666
06|0888888888888888888880666666666666666666
07|0888888888888888888880666666666666666666
08|0888888888888888888880666666666666666666
09|0000000000000000000000666666666666666666
10|6666666666666666666666666666666666666666
11|6666666666666666666666666666666666666666
12|3333333333333333333333333333333333333333
Loading

0 comments on commit c632364

Please sign in to comment.