@@ -7,20 +7,39 @@ local Watcher = require("nvim-tree.watcher").Watcher
77local Iterator = require (" nvim-tree.iterators.node-iterator" )
88local DirectoryNode = require (" nvim-tree.node.directory" )
99
10- --- @class (exact ) GitStatus -- xy short-format statuses
10+ --- Git xy short-format statuses for a single node
11+ --- @class (exact ) GitStatus
1112--- @field file string ?
1213--- @field dir table< " direct" | " indirect" , string[]> ?
1314
15+ -- Git xy short-format status
16+ --- @alias GitPathXY table<string , string>
17+
18+ -- Git xy short-format statuses
19+ --- @alias GitPathXYs table<string , string[]>
20+
21+ --- @alias GitProjectFiles GitPathXY
22+ --- @alias GitProjectDirs table< " direct" | " indirect" , GitPathXYs>
23+
24+ --- Git state for an entire repo
25+ --- @class (exact ) GitProject
26+ --- @field files GitProjectFiles ?
27+ --- @field dirs GitProjectDirs ?
28+ --- @field watcher Watcher ?
29+
1430local M = {
1531 config = {},
1632
17- -- all projects keyed by toplevel
33+ --- all projects keyed by toplevel
34+ --- @type table<string , GitProject>
1835 _projects_by_toplevel = {},
1936
20- -- index of paths inside toplevels, false when not inside a project
37+ --- index of paths inside toplevels, false when not inside a project
38+ --- @type table<string , string | false>
2139 _toplevels_by_path = {},
2240
2341 -- git dirs by toplevel
42+ --- @type table<string , string>
2443 _git_dirs_by_toplevel = {},
2544}
2645
@@ -36,33 +55,33 @@ local WATCHED_FILES = {
3655
3756--- @param toplevel string | nil
3857--- @param path string | nil
39- --- @param project table
40- --- @param statuses GitXYByPath ?
41- local function reload_git_statuses (toplevel , path , project , statuses )
58+ --- @param project GitProject
59+ --- @param project_files GitProjectFiles ?
60+ local function reload_git_project (toplevel , path , project , project_files )
4261 if path then
4362 for p in pairs (project .files ) do
4463 if p :find (path , 1 , true ) == 1 then
4564 project .files [p ] = nil
4665 end
4766 end
48- project .files = vim .tbl_deep_extend (" force" , project .files , statuses )
67+ project .files = vim .tbl_deep_extend (" force" , project .files , project_files )
4968 else
50- project .files = statuses
69+ project .files = project_files or {}
5170 end
5271
53- project .dirs = git_utils .file_status_to_dir_status (project .files , toplevel )
72+ project .dirs = git_utils .project_files_to_project_dirs (project .files , toplevel )
5473end
5574
5675--- Is this path in a known ignored directory?
5776--- @param path string
58- --- @param project table git status
77+ --- @param project GitProject
5978--- @return boolean
6079local function path_ignored_in_project (path , project )
6180 if not path or not project then
6281 return false
6382 end
6483
65- if project and project .files then
84+ if project .files then
6685 for file , status in pairs (project .files ) do
6786 if status == " !!" and vim .startswith (path , file ) then
6887 return true
@@ -72,9 +91,8 @@ local function path_ignored_in_project(path, project)
7291 return false
7392end
7493
75- --- Reload all projects
76- --- @return table projects maybe empty
77- function M .reload ()
94+ --- @return GitProject[] maybe empty
95+ function M .reload_all_projects ()
7896 if not M .config .git .enable then
7997 return {}
8098 end
@@ -87,11 +105,12 @@ function M.reload()
87105end
88106
89107--- Reload one project. Does nothing when no project or path is ignored
90- --- @param toplevel string | nil
91- --- @param path string | nil optional path to update only
92- --- @param callback function | nil
108+ --- @param toplevel string ?
109+ --- @param path string ? optional path to update only
110+ --- @param callback function ?
93111function M .reload_project (toplevel , path , callback )
94- local project = M ._projects_by_toplevel [toplevel ]
112+ local project = M ._projects_by_toplevel [toplevel ] --[[ @as GitProject]]
113+
95114 if not toplevel or not project or not M .config .git .enable then
96115 if callback then
97116 callback ()
@@ -116,21 +135,21 @@ function M.reload_project(toplevel, path, callback)
116135 }
117136
118137 if callback then
119- --- @param statuses GitXYByPath
138+ --- @param statuses GitPathXY
120139 runner_opts .callback = function (statuses )
121- reload_git_statuses (toplevel , path , project , statuses )
140+ reload_git_project (toplevel , path , project , statuses )
122141 callback ()
123142 end
124143 GitRunner :run (runner_opts )
125144 else
126145 -- TODO #1974 use callback once async/await is available
127- reload_git_statuses (toplevel , path , project , GitRunner :run (runner_opts ))
146+ reload_git_project (toplevel , path , project , GitRunner :run (runner_opts ))
128147 end
129148end
130149
131150--- Retrieve a known project
132- --- @param toplevel string | nil
133- --- @return table | nil project
151+ --- @param toplevel string ?
152+ --- @return GitProject ? project
134153function M .get_project (toplevel )
135154 return M ._projects_by_toplevel [toplevel ]
136155end
@@ -151,11 +170,10 @@ function M.get_toplevel(path)
151170 return nil
152171 end
153172
154- if M ._toplevels_by_path [path ] then
155- return M ._toplevels_by_path [path ]
156- end
157-
158- if M ._toplevels_by_path [path ] == false then
173+ local tl = M ._toplevels_by_path [path ]
174+ if tl then
175+ return tl
176+ elseif tl == false then
159177 return nil
160178 end
161179
@@ -194,8 +212,15 @@ function M.get_toplevel(path)
194212 end
195213
196214 M ._toplevels_by_path [path ] = toplevel
215+
197216 M ._git_dirs_by_toplevel [toplevel ] = git_dir
198- return M ._toplevels_by_path [path ]
217+
218+ toplevel = M ._toplevels_by_path [path ]
219+ if toplevel == false then
220+ return nil
221+ else
222+ return toplevel
223+ end
199224end
200225
201226local function reload_tree_at (toplevel )
230255--- Load the project status for a path. Does nothing when no toplevel for path.
231256--- Only fetches project status when unknown, otherwise returns existing.
232257--- @param path string absolute
233- --- @return table project maybe empty
234- function M .load_project_status (path )
258+ --- @return GitProject maybe empty
259+ function M .load_project (path )
235260 if not M .config .git .enable then
236261 return {}
237262 end
@@ -242,12 +267,12 @@ function M.load_project_status(path)
242267 return {}
243268 end
244269
245- local status = M ._projects_by_toplevel [toplevel ]
246- if status then
247- return status
270+ local project = M ._projects_by_toplevel [toplevel ]
271+ if project then
272+ return project
248273 end
249274
250- local statuses = GitRunner :run ({
275+ local path_xys = GitRunner :run ({
251276 toplevel = toplevel ,
252277 list_untracked = git_utils .should_show_untracked (toplevel ),
253278 list_ignored = true ,
@@ -275,10 +300,10 @@ function M.load_project_status(path)
275300 })
276301 end
277302
278- if statuses then
303+ if path_xys then
279304 M ._projects_by_toplevel [toplevel ] = {
280- files = statuses ,
281- dirs = git_utils .file_status_to_dir_status ( statuses , toplevel ),
305+ files = path_xys ,
306+ dirs = git_utils .project_files_to_project_dirs ( path_xys , toplevel ),
282307 watcher = watcher ,
283308 }
284309 return M ._projects_by_toplevel [toplevel ]
@@ -289,9 +314,9 @@ function M.load_project_status(path)
289314end
290315
291316--- @param dir DirectoryNode
292- --- @param project table ?
317+ --- @param project GitProject ?
293318--- @param root string ?
294- function M .update_parent_statuses (dir , project , root )
319+ function M .update_parent_projects (dir , project , root )
295320 while project and dir do
296321 -- step up to the containing project
297322 if dir .absolute_path == root then
@@ -331,14 +356,14 @@ function M.refresh_dir(dir)
331356
332357 dir .explorer :reload (node , project )
333358
334- M .update_parent_statuses (dir , project , toplevel )
359+ M .update_parent_projects (dir , project , toplevel )
335360
336361 dir .explorer .renderer :draw ()
337362 end )
338363end
339364
340365--- @param dir DirectoryNode ?
341- --- @param projects table
366+ --- @param projects GitProject[]
342367function M .reload_node_status (dir , projects )
343368 dir = dir and dir :as (DirectoryNode )
344369 if not dir or # dir .nodes == 0 then
0 commit comments