mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-12 02:23:39 +08:00
178 lines
4.9 KiB
Lua
178 lines
4.9 KiB
Lua
|
local vim = vim
|
||
|
local events = require("neo-tree.events")
|
||
|
local log = require("neo-tree.log")
|
||
|
local git = require("neo-tree.git")
|
||
|
local utils = require("neo-tree.utils")
|
||
|
|
||
|
local M = {}
|
||
|
|
||
|
local flags = {
|
||
|
watch_entry = false,
|
||
|
stat = false,
|
||
|
recursive = false,
|
||
|
}
|
||
|
|
||
|
local watched = {}
|
||
|
|
||
|
local get_dot_git_folder = function(path, callback)
|
||
|
if type(callback) == "function" then
|
||
|
git.get_repository_root(path, function(git_root)
|
||
|
if git_root then
|
||
|
local git_folder = utils.path_join(git_root, ".git")
|
||
|
local stat = vim.loop.fs_stat(git_folder)
|
||
|
if stat and stat.type == "directory" then
|
||
|
callback(git_folder, git_root)
|
||
|
end
|
||
|
else
|
||
|
callback(nil, nil)
|
||
|
end
|
||
|
end)
|
||
|
else
|
||
|
local git_root = git.get_repository_root(path)
|
||
|
if git_root then
|
||
|
local git_folder = utils.path_join(git_root, ".git")
|
||
|
local stat = vim.loop.fs_stat(git_folder)
|
||
|
if stat and stat.type == "directory" then
|
||
|
return git_folder, git_root
|
||
|
end
|
||
|
end
|
||
|
return nil, nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
M.show_watched = function()
|
||
|
local items = {}
|
||
|
for _, handle in pairs(watched) do
|
||
|
items[handle.path] = handle.references
|
||
|
end
|
||
|
log.info("Watched Folders: ", vim.inspect(items))
|
||
|
end
|
||
|
|
||
|
---Watch a directory for changes to it's children. Not recursive.
|
||
|
---@param path string The directory to watch.
|
||
|
---@param custom_callback? function The callback to call when a change is detected.
|
||
|
---@param allow_git_watch? boolean Allow watching of git folders.
|
||
|
M.watch_folder = function(path, custom_callback, allow_git_watch)
|
||
|
if not allow_git_watch then
|
||
|
if path:find("/%.git$") or path:find("/%.git/") then
|
||
|
-- git folders seem to throw off fs events constantly.
|
||
|
log.debug("watch_folder(path): Skipping git folder: ", path)
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
local h = watched[path]
|
||
|
if h == nil then
|
||
|
log.trace("Starting new fs watch on: ", path)
|
||
|
local callback = custom_callback
|
||
|
or vim.schedule_wrap(function(err, fname)
|
||
|
if fname and fname:match("^%.null[-]ls_.+") then
|
||
|
-- null-ls temp file: https://github.com/jose-elias-alvarez/null-ls.nvim/pull/1075
|
||
|
return
|
||
|
end
|
||
|
if err then
|
||
|
log.error("file_event_callback: ", err)
|
||
|
return
|
||
|
end
|
||
|
events.fire_event(events.FS_EVENT, { afile = path })
|
||
|
end)
|
||
|
h = {
|
||
|
handle = vim.loop.new_fs_event(),
|
||
|
path = path,
|
||
|
references = 0,
|
||
|
active = false,
|
||
|
callback = callback,
|
||
|
}
|
||
|
watched[path] = h
|
||
|
--w:start(path, flags, callback)
|
||
|
else
|
||
|
log.trace("Incrementing references for fs watch on: ", path)
|
||
|
end
|
||
|
h.references = h.references + 1
|
||
|
end
|
||
|
|
||
|
M.watch_git_index = function(path, async)
|
||
|
local function watch_git_folder(git_folder, git_root)
|
||
|
if git_folder then
|
||
|
local git_event_callback = vim.schedule_wrap(function(err, fname)
|
||
|
if fname and fname:match("^.+%.lock$") then
|
||
|
return
|
||
|
end
|
||
|
if fname and fname:match("^%._null-ls_.+") then
|
||
|
-- null-ls temp file: https://github.com/jose-elias-alvarez/null-ls.nvim/pull/1075
|
||
|
return
|
||
|
end
|
||
|
if err then
|
||
|
log.error("git_event_callback: ", err)
|
||
|
return
|
||
|
end
|
||
|
events.fire_event(events.GIT_EVENT, { path = fname, repository = git_root })
|
||
|
end)
|
||
|
|
||
|
M.watch_folder(git_folder, git_event_callback, true)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if async then
|
||
|
get_dot_git_folder(path, watch_git_folder)
|
||
|
else
|
||
|
watch_git_folder(get_dot_git_folder(path))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
M.updated_watched = function()
|
||
|
for path, w in pairs(watched) do
|
||
|
if w.references > 0 then
|
||
|
if not w.active then
|
||
|
log.trace("References added for fs watch on: ", path, ", starting.")
|
||
|
w.handle:start(path, flags, w.callback)
|
||
|
w.active = true
|
||
|
end
|
||
|
else
|
||
|
if w.active then
|
||
|
log.trace("No more references for fs watch on: ", path, ", stopping.")
|
||
|
w.handle:stop()
|
||
|
w.active = false
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---Stop watching a directory. If there are no more references to the handle,
|
||
|
---it will be destroyed. Otherwise, the reference count will be decremented.
|
||
|
---@param path string The directory to stop watching.
|
||
|
M.unwatch_folder = function(path, callback_id)
|
||
|
local h = watched[path]
|
||
|
if h then
|
||
|
log.trace("Decrementing references for fs watch on: ", path, callback_id)
|
||
|
h.references = h.references - 1
|
||
|
else
|
||
|
log.trace("(unwatch_folder) No fs watch found for: ", path)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
M.unwatch_git_index = function(path, async)
|
||
|
local function unwatch_git_folder(git_folder, _)
|
||
|
if git_folder then
|
||
|
M.unwatch_folder(git_folder)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if async then
|
||
|
get_dot_git_folder(path, unwatch_git_folder)
|
||
|
else
|
||
|
unwatch_git_folder(get_dot_git_folder(path))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---Stop watching all directories. This is the nuclear option and it affects all
|
||
|
---sources.
|
||
|
M.unwatch_all = function()
|
||
|
for _, h in pairs(watched) do
|
||
|
h.handle:stop()
|
||
|
h.handle = nil
|
||
|
end
|
||
|
watched = {}
|
||
|
end
|
||
|
|
||
|
return M
|