Skip to content

Commit e3fec64

Browse files
committed
feat(filesystem): auto watch git folder for index changes, closes #337
1 parent 7ee0f38 commit e3fec64

File tree

3 files changed

+58
-6
lines changed

3 files changed

+58
-6
lines changed

lua/neo-tree/sources/filesystem/init.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ end
255255
--wants to change from the defaults. May be empty to accept default values.
256256
M.setup = function(config, global_config)
257257
config.filtered_items = config.filtered_items or {}
258+
config.enable_git_status = global_config.enable_git_status
258259

259260
local hide_by_name = config.filtered_items.hide_by_name
260261
if hide_by_name then

lua/neo-tree/sources/filesystem/lib/fs_scan.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,15 @@ M.get_items = function(state, parent_id, path_to_reveal, callback, async, recurs
202202
end
203203
--end
204204

205+
if not parent_id and state.use_libuv_file_watcher and state.enable_git_status then
206+
log.trace("Starting .git folder watcher")
207+
local path = root.path
208+
if root.is_link then
209+
path = root.link_to
210+
end
211+
fs_watch.watch_git_index(path)
212+
end
213+
205214
file_items.deep_sort(root.children)
206215
if parent_id then
207216
-- lazy loading a child folder
@@ -281,6 +290,7 @@ M.stop_watchers = function(state)
281290
local loaded_folders = renderer.select_nodes(state.tree, function(node)
282291
return node.type == "directory" and node.loaded
283292
end)
293+
fs_watch.unwatch_git_index(state.path)
284294
for _, folder in ipairs(loaded_folders) do
285295
log.trace("Unwatching folder ", folder.path)
286296
if folder.is_link then

lua/neo-tree/sources/filesystem/lib/fs_watch.lua

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
local vim = vim
22
local events = require("neo-tree.events")
33
local log = require("neo-tree.log")
4+
local git = require("neo-tree.git")
5+
local utils = require("neo-tree.utils")
46

57
local M = {}
68

@@ -20,6 +22,18 @@ local flags = {
2022

2123
local watched = {}
2224

25+
local get_dot_git_folder = function(path)
26+
local git_root = git.get_repository_root(path)
27+
if git_root then
28+
local git_folder = utils.path_join(git_root, ".git")
29+
local stat = vim.loop.fs_stat(git_folder)
30+
if stat and stat.type == "directory" then
31+
return git_folder, git_root
32+
end
33+
end
34+
return nil, nil
35+
end
36+
2337
M.show_watched = function()
2438
local items = {}
2539
for _, handle in pairs(watched) do
@@ -30,11 +44,13 @@ end
3044

3145
---Watch a directory for changes to it's children. Not recursive.
3246
---@param path string The directory to watch.
33-
M.watch_folder = function(path)
34-
if path:find("/%.git$") or path:find("/%.git/") then
35-
-- git folders seem to throw off fs events constantly.
36-
log.debug("watch_folder(path): Skipping git folder: ", path)
37-
return
47+
M.watch_folder = function(path, git_watch_callback)
48+
if not git_watch_callback then
49+
if path:find("/%.git$") or path:find("/%.git/") then
50+
-- git folders seem to throw off fs events constantly.
51+
log.debug("watch_folder(path): Skipping git folder: ", path)
52+
return
53+
end
3854
end
3955
local h = watched[path]
4056
if h == nil then
@@ -45,13 +61,31 @@ M.watch_folder = function(path)
4561
path = path,
4662
references = 1,
4763
}
48-
w:start(path, flags, fs_event_callback)
64+
w:start(path, flags, git_watch_callback or fs_event_callback)
4965
else
5066
log.trace("Incrementing references for fs watch on: ", path)
5167
h.references = h.references + 1
5268
end
5369
end
5470

71+
M.watch_git_index = function(path)
72+
local git_folder, git_root = get_dot_git_folder(path)
73+
if git_folder then
74+
local git_event_callback = vim.schedule_wrap(function(err, fname)
75+
if fname and fname:match("^.+%.lock$") then
76+
return
77+
end
78+
if err then
79+
log.error("git_event_callback: ", err)
80+
return
81+
end
82+
events.fire_event(events.GIT_EVENT, { path = fname, repository = git_root })
83+
end)
84+
85+
M.watch_folder(git_folder, git_event_callback)
86+
end
87+
end
88+
5589
---Stop watching a directory. If there are no more references to the handle,
5690
---it will be destroyed. Otherwise, the reference count will be decremented.
5791
---@param path string The directory to stop watching.
@@ -72,6 +106,13 @@ M.unwatch_folder = function(path)
72106
end
73107
end
74108

109+
M.unwatch_git_index = function(path)
110+
local git_folder = get_dot_git_folder(path)
111+
if git_folder then
112+
M.unwatch_folder(git_folder)
113+
end
114+
end
115+
75116
---Stop watching all directories. This is the nuclear option and it affects all
76117
---sources.
77118
M.unwatch_all = function()

0 commit comments

Comments
 (0)