aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/_watch.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/_watch.lua')
-rw-r--r--runtime/lua/vim/_watch.lua73
1 files changed, 56 insertions, 17 deletions
diff --git a/runtime/lua/vim/_watch.lua b/runtime/lua/vim/_watch.lua
index 3bd8a56f6e..d489cef9fc 100644
--- a/runtime/lua/vim/_watch.lua
+++ b/runtime/lua/vim/_watch.lua
@@ -11,6 +11,7 @@ M.FileChangeType = vim.tbl_add_reverse_lookup({
--- Joins filepath elements by static '/' separator
---
---@param ... (string) The path elements.
+---@return string
local function filepath_join(...)
return table.concat({ ... }, '/')
end
@@ -36,7 +37,7 @@ end
--- - uvflags (table|nil)
--- Same flags as accepted by |uv.fs_event_start()|
---@param callback (function) The function called when new events
----@returns (function) A function to stop the watch
+---@return (function) A function to stop the watch
function M.watch(path, opts, callback)
vim.validate({
path = { path, 'string', false },
@@ -75,10 +76,25 @@ end
local default_poll_interval_ms = 2000
+--- @class watch.Watches
+--- @field is_dir boolean
+--- @field children? table<string,watch.Watches>
+--- @field cancel? fun()
+--- @field started? boolean
+--- @field handle? uv_fs_poll_t
+
+--- @class watch.PollOpts
+--- @field interval? integer
+--- @field include_pattern? userdata
+--- @field exclude_pattern? userdata
+
---@private
--- Implementation for poll, hiding internally-used parameters.
---
----@param watches (table|nil) A tree structure to maintain state for recursive watches.
+---@param path string
+---@param opts watch.PollOpts
+---@param callback fun(patch: string, filechangetype: integer)
+---@param watches (watch.Watches|nil) A tree structure to maintain state for recursive watches.
--- - handle (uv_fs_poll_t)
--- The libuv handle
--- - cancel (function)
@@ -88,15 +104,36 @@ local default_poll_interval_ms = 2000
--- be invoked recursively)
--- - children (table|nil)
--- A mapping of directory entry name to its recursive watches
--- - started (boolean|nil)
--- Whether or not the watcher has first been initialized. Used
--- to prevent a flood of Created events on startup.
+--- - started (boolean|nil)
+--- Whether or not the watcher has first been initialized. Used
+--- to prevent a flood of Created events on startup.
+---@return fun() Cancel function
local function poll_internal(path, opts, callback, watches)
path = vim.fs.normalize(path)
local interval = opts and opts.interval or default_poll_interval_ms
watches = watches or {
is_dir = true,
}
+ watches.cancel = function()
+ if watches.children then
+ for _, w in pairs(watches.children) do
+ w.cancel()
+ end
+ end
+ if watches.handle then
+ stop(watches.handle)
+ end
+ end
+
+ local function incl_match()
+ return not opts.include_pattern or opts.include_pattern:match(path) ~= nil
+ end
+ local function excl_match()
+ return opts.exclude_pattern and opts.exclude_pattern:match(path) ~= nil
+ end
+ if not watches.is_dir and not incl_match() or excl_match() then
+ return watches.cancel
+ end
if not watches.handle then
local poll, new_err = vim.uv.new_fs_poll()
@@ -120,18 +157,9 @@ local function poll_internal(path, opts, callback, watches)
end
end
- watches.cancel = function()
- if watches.children then
- for _, w in pairs(watches.children) do
- w.cancel()
- end
- end
- stop(watches.handle)
- end
-
if watches.is_dir then
watches.children = watches.children or {}
- local exists = {}
+ local exists = {} --- @type table<string,true>
for name, ftype in vim.fs.dir(path) do
exists[name] = true
if not watches.children[name] then
@@ -143,14 +171,16 @@ local function poll_internal(path, opts, callback, watches)
end
end
- local newchildren = {}
+ local newchildren = {} ---@type table<string,watch.Watches>
for name, watch in pairs(watches.children) do
if exists[name] then
newchildren[name] = watch
else
watch.cancel()
watches.children[name] = nil
- callback(path .. '/' .. name, M.FileChangeType.Deleted)
+ if watch.handle then
+ callback(path .. '/' .. name, M.FileChangeType.Deleted)
+ end
end
end
watches.children = newchildren
@@ -168,6 +198,15 @@ end
---@param opts (table|nil) Additional options
--- - interval (number|nil)
--- Polling interval in ms as passed to |uv.fs_poll_start()|. Defaults to 2000.
+--- - include_pattern (LPeg pattern|nil)
+--- An |lpeg| pattern. Only changes to files whose full paths match the pattern
+--- will be reported. Only matches against non-directoriess, all directories will
+--- be watched for new potentially-matching files. exclude_pattern can be used to
+--- filter out directories. When nil, matches any file name.
+--- - exclude_pattern (LPeg pattern|nil)
+--- An |lpeg| pattern. Only changes to files and directories whose full path does
+--- not match the pattern will be reported. Matches against both files and
+--- directories. When nil, matches nothing.
---@param callback (function) The function called when new events
---@returns (function) A function to stop the watch.
function M.poll(path, opts, callback)