diff options
Diffstat (limited to 'runtime/lua/vim/_watch.lua')
-rw-r--r-- | runtime/lua/vim/_watch.lua | 73 |
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) |