@@ -3,10 +3,16 @@ local uv = vim.loop
33local log = require " nvim-tree.log"
44local utils = require " nvim-tree.utils"
55
6- local M = {
6+ local M = {}
7+
8+ local Event = {
9+ _events = {},
10+ }
11+ Event .__index = Event
12+
13+ local Watcher = {
714 _watchers = {},
815}
9- local Watcher = {}
1016Watcher .__index = Watcher
1117
1218local FS_EVENT_FLAGS = {
@@ -16,87 +22,129 @@ local FS_EVENT_FLAGS = {
1622 recursive = false ,
1723}
1824
19- function Watcher .new (opts )
20- for _ , existing in ipairs (M ._watchers ) do
21- if existing ._opts .absolute_path == opts .absolute_path then
22- log .line (" watcher" , " Watcher:new using existing '%s'" , opts .absolute_path )
23- return existing
24- end
25- end
26-
27- log .line (" watcher" , " Watcher:new '%s'" , opts .absolute_path )
25+ function Event :new (path )
26+ log .line (" watcher" , " Event:new '%s'" , path )
2827
29- local watcher = setmetatable ({
30- _opts = opts ,
31- }, Watcher )
28+ local e = setmetatable ({
29+ _path = path ,
30+ _fs_event = nil ,
31+ _listeners = {},
32+ }, Event )
3233
33- watcher = watcher :start ()
34-
35- table.insert (M ._watchers , watcher )
36-
37- return watcher
34+ if e :start () then
35+ Event ._events [path ] = e
36+ return e
37+ else
38+ return nil
39+ end
3840end
3941
40- function Watcher :start ()
41- log .line (" watcher" , " Watcher :start '%s'" , self ._opts . absolute_path )
42+ function Event :start ()
43+ log .line (" watcher" , " Event :start '%s'" , self ._path )
4244
4345 local rc , _ , name
4446
45- self ._e , _ , name = uv .new_fs_event ()
46- if not self ._e then
47- self ._e = nil
48- utils .notify .warn (
49- string.format (" Could not initialize an fs_event watcher for path %s : %s" , self ._opts .absolute_path , name )
50- )
51- return nil
47+ self ._fs_event , _ , name = uv .new_fs_event ()
48+ if not self ._fs_event then
49+ self ._fs_event = nil
50+ utils .notify .warn (string.format (" Could not initialize an fs_event watcher for path %s : %s" , self ._path , name ))
51+ return false
5252 end
5353
54- local event_cb = vim .schedule_wrap (function (err , filename , events )
54+ local event_cb = vim .schedule_wrap (function (err , filename )
5555 if err then
56- log .line (" watcher" , " event_cb for %s fail : %s" , self ._opts . absolute_path , err )
56+ log .line (" watcher" , " event_cb for %s fail : %s" , self ._path , err )
5757 else
58- log .line (" watcher" , " event_cb '%s' '%s' %s" , self ._opts .absolute_path , filename , vim .inspect (events ))
59- self ._opts .on_event (self ._opts )
58+ log .line (" watcher" , " event_cb '%s' '%s'" , self ._path , filename )
59+ for _ , listener in ipairs (self ._listeners ) do
60+ listener ()
61+ end
6062 end
6163 end )
6264
63- rc , _ , name = self ._e :start (self ._opts . absolute_path , FS_EVENT_FLAGS , event_cb )
65+ rc , _ , name = self ._fs_event :start (self ._path , FS_EVENT_FLAGS , event_cb )
6466 if rc ~= 0 then
65- utils .notify .warn (
66- string.format (" Could not start the fs_event watcher for path %s : %s" , self ._opts .absolute_path , name )
67- )
68- return nil
67+ utils .notify .warn (string.format (" Could not start the fs_event watcher for path %s : %s" , self ._path , name ))
68+ return false
6969 end
7070
71- return self
71+ return true
7272end
7373
74- function Watcher :destroy ()
75- log .line (" watcher" , " Watcher:destroy '%s'" , self ._opts .absolute_path )
76- if self ._e then
77- local rc , _ , name = self ._e :stop ()
74+ function Event :add (listener )
75+ table.insert (self ._listeners , listener )
76+ end
77+
78+ function Event :remove (listener )
79+ utils .array_remove (self ._listeners , listener )
80+ if # self ._listeners == 0 then
81+ self :destroy ()
82+ end
83+ end
84+
85+ function Event :destroy ()
86+ log .line (" watcher" , " Event:destroy '%s'" , self ._path )
87+
88+ if self ._fs_event then
89+ local rc , _ , name = self ._fs_event :stop ()
7890 if rc ~= 0 then
79- utils .notify .warn (
80- string.format (" Could not stop the fs_event watcher for path %s : %s" , self ._opts .absolute_path , name )
81- )
91+ utils .notify .warn (string.format (" Could not stop the fs_event watcher for path %s : %s" , self ._path , name ))
8292 end
83- self ._e = nil
93+ self ._fs_event = nil
8494 end
85- for i , w in ipairs (M ._watchers ) do
86- if w == self then
87- table.remove (M ._watchers , i )
88- break
89- end
95+
96+ Event ._events [self ._path ] = nil
97+ end
98+
99+ function Watcher :new (path , callback , data )
100+ log .line (" watcher" , " Watcher:new '%s'" , path )
101+
102+ local w = setmetatable (data , Watcher )
103+
104+ w ._event = Event ._events [path ] or Event :new (path )
105+ w ._listener = nil
106+ w ._path = path
107+ w ._callback = callback
108+
109+ if not w ._event then
110+ return nil
111+ end
112+
113+ w :start ()
114+
115+ table.insert (Watcher ._watchers , w )
116+
117+ return w
118+ end
119+
120+ function Watcher :start ()
121+ self ._listener = function ()
122+ self ._callback (self )
90123 end
124+
125+ self ._event :add (self ._listener )
126+ end
127+
128+ function Watcher :destroy ()
129+ log .line (" watcher" , " Watcher:destroy '%s'" , self ._path )
130+
131+ self ._event :remove (self ._listener )
132+
133+ utils .array_remove (Watcher ._watchers , self )
91134end
92135
93136M .Watcher = Watcher
94137
95138function M .purge_watchers ()
96- for _ , watcher in pairs (M ._watchers ) do
97- watcher :destroy ()
139+ log .line (" watcher" , " purge_watchers" )
140+
141+ for _ , w in ipairs (utils .array_shallow_clone (Watcher ._watchers )) do
142+ w :destroy ()
143+ end
144+
145+ for _ , e in pairs (Event ._events ) do
146+ e :destroy ()
98147 end
99- M ._watchers = {}
100148end
101149
102150return M
0 commit comments