Skip to content

Commit

Permalink
refactor(#2886): multi instance: node class refactoring: extract link…
Browse files Browse the repository at this point in the history
…s, *_git_status (#2944)

* extract DirectoryLinkNode and FileLinkNode, move Node methods to children

* temporarily move DirectoryNode methods into BaseNode for easier reviewing

* move mostly unchanged DirectoryNode methods back to BaseNode

* tidy

* git.git_status_file takes an array

* update git status of links

* luacheck hack
  • Loading branch information
alex-courtis authored Oct 11, 2024
1 parent 0bc36f5 commit dbe76bd
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 184 deletions.
31 changes: 22 additions & 9 deletions lua/nvim-tree/git/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -283,33 +283,46 @@ function M.load_project_status(path)
end
end

---Git file and directory status for an absolute path with optional file fallback
---@param parent_ignored boolean
---@param status table|nil
---@param absolute_path string
---@param path string
---@param path_file string? alternative file path when no other file status
---@return GitStatus|nil
function M.git_status_dir(parent_ignored, status, absolute_path)
function M.git_status_dir(parent_ignored, status, path, path_file)
if parent_ignored then
return { file = "!!" }
end

if status then
return {
file = status.files and status.files[absolute_path],
file = status.files and status.files[path] or path_file and status.files[path_file],
dir = status.dirs and {
direct = status.dirs.direct[absolute_path],
indirect = status.dirs.indirect[absolute_path],
direct = status.dirs.direct[path],
indirect = status.dirs.indirect[path],
},
}
end
end

---Git file status for an absolute path with optional fallback
---@param parent_ignored boolean
---@param status table|nil
---@param absolute_path string
---@param path string
---@param path_fallback string?
---@return GitStatus
function M.git_status_file(parent_ignored, status, absolute_path)
local file_status = parent_ignored and "!!" or (status and status.files and status.files[absolute_path])
return { file = file_status }
function M.git_status_file(parent_ignored, status, path, path_fallback)
if parent_ignored then
return { file = "!!" }
end

if not status or not status.files then
return {}
end

return {
file = status.files[path] or status.files[path_fallback]
}
end

function M.purge_state()
Expand Down
19 changes: 19 additions & 0 deletions lua/nvim-tree/log.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ function M.raw(typ, fmt, ...)
end
end

--- Write to a new file
---@param typ string as per log.types config
---@param path string absolute path
---@param fmt string for string.format
---@param ... any arguments for string.format
function M.file(typ, path, fmt, ...)
if not M.enabled(typ) then
return
end

local line = string.format(fmt, ...)
local file = io.open(path, "w")
if file then
io.output(file)
io.write(line)
io.close(file)
end
end

---@class Profile
---@field start number nanos
---@field tag string
Expand Down
54 changes: 54 additions & 0 deletions lua/nvim-tree/node/directory-link.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
local git = require("nvim-tree.git")

local DirectoryNode = require("nvim-tree.node.directory")

---@class (exact) DirectoryLinkNode: DirectoryNode
---@field link_to string absolute path
---@field fs_stat_target uv.fs_stat.result
local DirectoryLinkNode = DirectoryNode:new()

---Static factory method
---@param explorer Explorer
---@param parent Node
---@param absolute_path string
---@param link_to string
---@param name string
---@param fs_stat uv.fs_stat.result?
---@param fs_stat_target uv.fs_stat.result
---@return DirectoryLinkNode? nil on vim.loop.fs_realpath failure
function DirectoryLinkNode:create(explorer, parent, absolute_path, link_to, name, fs_stat, fs_stat_target)
-- create DirectoryNode with the target path for the watcher
local o = DirectoryNode:create(explorer, parent, link_to, name, fs_stat)

o = self:new(o) --[[@as DirectoryLinkNode]]

-- reset absolute path to the link itself
o.absolute_path = absolute_path

o.type = "link"
o.link_to = link_to
o.fs_stat_target = fs_stat_target

return o
end

-----Update the directory GitStatus of link target and the file status of the link itself
-----@param parent_ignored boolean
-----@param status table|nil
function DirectoryLinkNode:update_git_status(parent_ignored, status)
self.git_status = git.git_status_dir(parent_ignored, status, self.link_to, self.absolute_path)
end

---Create a sanitized partial copy of a node, populating children recursively.
---@return DirectoryLinkNode cloned
function DirectoryLinkNode:clone()
local clone = DirectoryNode.clone(self) --[[@as DirectoryLinkNode]]

clone.type = self.type
clone.link_to = self.link_to
clone.fs_stat_target = self.fs_stat_target

return clone
end

return DirectoryLinkNode
58 changes: 58 additions & 0 deletions lua/nvim-tree/node/directory.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local git = require("nvim-tree.git")
local watch = require("nvim-tree.explorer.watch")

local BaseNode = require("nvim-tree.node")
Expand Down Expand Up @@ -58,6 +59,63 @@ function DirectoryNode:destroy()
end
end

---Update the GitStatus of the directory
---@param parent_ignored boolean
---@param status table|nil
function DirectoryNode:update_git_status(parent_ignored, status)
self.git_status = git.git_status_dir(parent_ignored, status, self.absolute_path, nil)
end

---@return GitStatus|nil
function DirectoryNode:get_git_status()
if not self.git_status or not self.explorer.opts.git.show_on_dirs then
return nil
end

local status = {}
if not self:last_group_node().open or self.explorer.opts.git.show_on_open_dirs then
-- dir is closed or we should show on open_dirs
if self.git_status.file ~= nil then
table.insert(status, self.git_status.file)
end
if self.git_status.dir ~= nil then
if self.git_status.dir.direct ~= nil then
for _, s in pairs(self.git_status.dir.direct) do
table.insert(status, s)
end
end
if self.git_status.dir.indirect ~= nil then
for _, s in pairs(self.git_status.dir.indirect) do
table.insert(status, s)
end
end
end
else
-- dir is open and we shouldn't show on open_dirs
if self.git_status.file ~= nil then
table.insert(status, self.git_status.file)
end
if self.git_status.dir ~= nil and self.git_status.dir.direct ~= nil then
local deleted = {
[" D"] = true,
["D "] = true,
["RD"] = true,
["DD"] = true,
}
for _, s in pairs(self.git_status.dir.direct) do
if deleted[s] then
table.insert(status, s)
end
end
end
end
if #status == 0 then
return nil
else
return status
end
end

---Create a sanitized partial copy of a node, populating children recursively.
---@return DirectoryNode cloned
function DirectoryNode:clone()
Expand Down
31 changes: 24 additions & 7 deletions lua/nvim-tree/node/factory.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local DirectoryLinkNode = require("nvim-tree.node.directory-link")
local DirectoryNode = require("nvim-tree.node.directory")
local LinkNode = require("nvim-tree.node.link")
local FileLinkNode = require("nvim-tree.node.file-link")
local FileNode = require("nvim-tree.node.file")
local Watcher = require("nvim-tree.watcher")

Expand All @@ -8,21 +9,37 @@ local M = {}
---Factory function to create the appropriate Node
---@param explorer Explorer
---@param parent Node
---@param abs string
---@param absolute_path string
---@param stat uv.fs_stat.result? -- on nil stat return nil Node
---@param name string
---@return Node?
function M.create_node(explorer, parent, abs, stat, name)
function M.create_node(explorer, parent, absolute_path, stat, name)
if not stat then
return nil
end

if stat.type == "directory" and vim.loop.fs_access(abs, "R") and Watcher.is_fs_event_capable(abs) then
return DirectoryNode:create(explorer, parent, abs, name, stat)
if stat.type == "directory" then
-- directory must be readable and enumerable
if vim.loop.fs_access(absolute_path, "R") and Watcher.is_fs_event_capable(absolute_path) then
return DirectoryNode:create(explorer, parent, absolute_path, name, stat)
end
elseif stat.type == "file" then
return FileNode:create(explorer, parent, abs, name, stat)
-- any file
return FileNode:create(explorer, parent, absolute_path, name, stat)
elseif stat.type == "link" then
return LinkNode:create(explorer, parent, abs, name, stat)
-- link target path and stat must resolve
local link_to = vim.loop.fs_realpath(absolute_path)
local link_to_stat = link_to and vim.loop.fs_stat(link_to)
if not link_to or not link_to_stat then
return
end

-- choose directory or file
if link_to_stat.type == "directory" then
return DirectoryLinkNode:create(explorer, parent, absolute_path, link_to, name, stat, link_to_stat)
else
return FileLinkNode:create(explorer, parent, absolute_path, link_to, name, stat, link_to_stat)
end
end

return nil
Expand Down
50 changes: 50 additions & 0 deletions lua/nvim-tree/node/file-link.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
local git = require("nvim-tree.git")

local FileNode = require("nvim-tree.node.file")

---@class (exact) FileLinkNode: FileNode
---@field link_to string absolute path
---@field fs_stat_target uv.fs_stat.result
local FileLinkNode = FileNode:new()

---Static factory method
---@param explorer Explorer
---@param parent Node
---@param absolute_path string
---@param link_to string
---@param name string
---@param fs_stat uv.fs_stat.result?
---@param fs_stat_target uv.fs_stat.result
---@return FileLinkNode? nil on vim.loop.fs_realpath failure
function FileLinkNode:create(explorer, parent, absolute_path, link_to, name, fs_stat, fs_stat_target)
local o = FileNode:create(explorer, parent, absolute_path, name, fs_stat)

o = self:new(o) --[[@as FileLinkNode]]

o.type = "link"
o.link_to = link_to
o.fs_stat_target = fs_stat_target

return o
end

-----Update the GitStatus of the target otherwise the link itself
-----@param parent_ignored boolean
-----@param status table|nil
function FileLinkNode:update_git_status(parent_ignored, status)
self.git_status = git.git_status_file(parent_ignored, status, self.link_to, self.absolute_path)
end

---Create a sanitized partial copy of a node
---@return FileLinkNode cloned
function FileLinkNode:clone()
local clone = FileNode.clone(self) --[[@as FileLinkNode]]

clone.type = self.type
clone.link_to = self.link_to
clone.fs_stat_target = self.fs_stat_target

return clone
end

return FileLinkNode
19 changes: 18 additions & 1 deletion lua/nvim-tree/node/file.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local git = require("nvim-tree.git")
local utils = require("nvim-tree.utils")

local BaseNode = require("nvim-tree.node")
Expand Down Expand Up @@ -36,7 +37,23 @@ function FileNode:create(explorer, parent, absolute_path, name, fs_stat)
return o
end

---Create a sanitized partial copy of a node, populating children recursively.
---Update the GitStatus of the file
---@param parent_ignored boolean
---@param status table|nil
function FileNode:update_git_status(parent_ignored, status)
self.git_status = git.git_status_file(parent_ignored, status, self.absolute_path, nil)
end

---@return GitStatus|nil
function FileNode:get_git_status()
if not self.git_status then
return nil
end

return self.git_status.file and { self.git_status.file }
end

---Create a sanitized partial copy of a node
---@return FileNode cloned
function FileNode:clone()
local clone = BaseNode.clone(self) --[[@as FileNode]]
Expand Down
Loading

0 comments on commit dbe76bd

Please sign in to comment.