@@ -11,6 +11,7 @@ M.FileChangeType = vim.tbl_add_reverse_lookup({
1111--- Joins filepath elements by static '/' separator
1212---
1313--- @param ... (string ) The path elements.
14+ --- @return string
1415local function filepath_join (...)
1516 return table.concat ({ ... }, ' /' )
1617end
3637--- - uvflags (table|nil)
3738--- Same flags as accepted by |uv.fs_event_start()|
3839--- @param callback (function ) The function called when new events
39- --- @return s (function ) A function to stop the watch
40+ --- @return (function ) A function to stop the watch
4041function M .watch (path , opts , callback )
4142 vim .validate ({
4243 path = { path , ' string' , false },
7576
7677local default_poll_interval_ms = 2000
7778
79+ --- @class watch.Watches
80+ --- @field is_dir boolean
81+ --- @field children ? table<string,watch.Watches>
82+ --- @field cancel ? fun ()
83+ --- @field started ? boolean
84+ --- @field handle ? uv_fs_poll_t
85+
86+ --- @class watch.PollOpts
87+ --- @field interval ? integer
88+ --- @field include_pattern ? userdata
89+ --- @field exclude_pattern ? userdata
90+
7891--- @private
7992--- Implementation for poll, hiding internally-used parameters.
8093---
81- --- @param watches (table | nil ) A tree structure to maintain state for recursive watches.
94+ --- @param path string
95+ --- @param opts watch.PollOpts
96+ --- @param callback fun ( patch : string , filechangetype : integer )
97+ --- @param watches (watch.Watches | nil ) A tree structure to maintain state for recursive watches.
8298--- - handle (uv_fs_poll_t)
8399--- The libuv handle
84100--- - cancel (function)
@@ -88,15 +104,36 @@ local default_poll_interval_ms = 2000
88104--- be invoked recursively)
89105--- - children (table|nil)
90106--- A mapping of directory entry name to its recursive watches
91- -- - started (boolean|nil)
92- -- Whether or not the watcher has first been initialized. Used
93- -- to prevent a flood of Created events on startup.
107+ --- - started (boolean|nil)
108+ --- Whether or not the watcher has first been initialized. Used
109+ --- to prevent a flood of Created events on startup.
110+ --- @return fun () Cancel function
94111local function poll_internal (path , opts , callback , watches )
95112 path = vim .fs .normalize (path )
96113 local interval = opts and opts .interval or default_poll_interval_ms
97114 watches = watches or {
98115 is_dir = true ,
99116 }
117+ watches .cancel = function ()
118+ if watches .children then
119+ for _ , w in pairs (watches .children ) do
120+ w .cancel ()
121+ end
122+ end
123+ if watches .handle then
124+ stop (watches .handle )
125+ end
126+ end
127+
128+ local function incl_match ()
129+ return not opts .include_pattern or opts .include_pattern :match (path ) ~= nil
130+ end
131+ local function excl_match ()
132+ return opts .exclude_pattern and opts .exclude_pattern :match (path ) ~= nil
133+ end
134+ if not watches .is_dir and not incl_match () or excl_match () then
135+ return watches .cancel
136+ end
100137
101138 if not watches .handle then
102139 local poll , new_err = vim .uv .new_fs_poll ()
@@ -120,18 +157,9 @@ local function poll_internal(path, opts, callback, watches)
120157 end
121158 end
122159
123- watches .cancel = function ()
124- if watches .children then
125- for _ , w in pairs (watches .children ) do
126- w .cancel ()
127- end
128- end
129- stop (watches .handle )
130- end
131-
132160 if watches .is_dir then
133161 watches .children = watches .children or {}
134- local exists = {}
162+ local exists = {} --- @type table<string,true>
135163 for name , ftype in vim .fs .dir (path ) do
136164 exists [name ] = true
137165 if not watches .children [name ] then
@@ -143,14 +171,16 @@ local function poll_internal(path, opts, callback, watches)
143171 end
144172 end
145173
146- local newchildren = {}
174+ local newchildren = {} --- @type table<string,watch.Watches>
147175 for name , watch in pairs (watches .children ) do
148176 if exists [name ] then
149177 newchildren [name ] = watch
150178 else
151179 watch .cancel ()
152180 watches .children [name ] = nil
153- callback (path .. ' /' .. name , M .FileChangeType .Deleted )
181+ if watch .handle then
182+ callback (path .. ' /' .. name , M .FileChangeType .Deleted )
183+ end
154184 end
155185 end
156186 watches .children = newchildren
168198--- @param opts (table | nil ) Additional options
169199--- - interval (number|nil)
170200--- Polling interval in ms as passed to |uv.fs_poll_start()|. Defaults to 2000.
201+ --- - include_pattern (LPeg pattern|nil)
202+ --- An |lpeg| pattern. Only changes to files whose full paths match the pattern
203+ --- will be reported. Only matches against non-directoriess, all directories will
204+ --- be watched for new potentially-matching files. exclude_pattern can be used to
205+ --- filter out directories. When nil, matches any file name.
206+ --- - exclude_pattern (LPeg pattern|nil)
207+ --- An |lpeg| pattern. Only changes to files and directories whose full path does
208+ --- not match the pattern will be reported. Matches against both files and
209+ --- directories. When nil, matches nothing.
171210--- @param callback (function ) The function called when new events
172211--- @return s (function ) A function to stop the watch.
173212function M .poll (path , opts , callback )
0 commit comments