Skip to content

feat(filesystem): add BEFORE_FILE_{ADD/DELETE} events #1657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions lua/neo-tree/events/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ local utils = require("neo-tree.utils")

local M = {
-- Well known event names, you can make up your own
STATE_CREATED = "state_created",
BEFORE_RENDER = "before_render",
AFTER_RENDER = "after_render",
BEFORE_FILE_ADD = "before_file_add",
BEFORE_FILE_DELETE = "before_file_delete",
BEFORE_FILE_MOVE = "before_file_move",
BEFORE_FILE_RENAME = "before_file_rename",
BEFORE_RENDER = "before_render",
FILE_ADDED = "file_added",
FILE_DELETED = "file_deleted",
BEFORE_FILE_MOVE = "before_file_move",
FILE_MOVED = "file_moved",
FILE_OPEN_REQUESTED = "file_open_requested",
FILE_OPENED = "file_opened",
BEFORE_FILE_RENAME = "before_file_rename",
FILE_OPEN_REQUESTED = "file_open_requested",
FILE_RENAMED = "file_renamed",
FS_EVENT = "fs_event",
GIT_EVENT = "git_event",
GIT_STATUS_CHANGED = "git_status_changed",
STATE_CREATED = "state_created",
NEO_TREE_BUFFER_ENTER = "neo_tree_buffer_enter",
NEO_TREE_BUFFER_LEAVE = "neo_tree_buffer_leave",
NEO_TREE_LSP_UPDATE = "neo_tree_lsp_update",
Expand Down
137 changes: 84 additions & 53 deletions lua/neo-tree/sources/filesystem/lib/fs_actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
-- Permalink: https://github.com/mhartington/dotfiles/blob/7560986378753e0c047d940452cb03a3b6439b11/config/nvim/lua/mh/filetree/init.lua
local vim = vim
local api = vim.api
local loop = vim.loop
local loop = vim.uv or vim.loop
local scan = require("plenary.scandir")
local utils = require("neo-tree.utils")
local inputs = require("neo-tree.ui.inputs")
Expand Down Expand Up @@ -253,6 +253,12 @@ M.copy_node = function(source, _destination, callback, using_root_directory)
log.warn("Cannot copy a file/folder to itself")
return
end

local event_result = events.fire_event(events.BEFORE_FILE_ADD, destination) or {}
if event_result.handled then
return
end

local source_path = Path:new(source)
if source_path:is_file() then
-- When the source is a file, then Path.copy() currently doesn't create
Expand Down Expand Up @@ -321,6 +327,11 @@ M.create_directory = function(in_directory, callback, using_root_directory)
destination = vim.fn.fnamemodify(destination, ":p")
end

local event_result = events.fire_event(events.BEFORE_FILE_ADD, destination) or {}
if event_result.handled then
return
end

if loop.fs_stat(destination) then
log.warn("Directory already exists")
return
Expand Down Expand Up @@ -378,14 +389,24 @@ M.create_node = function(in_directory, callback, using_root_directory)
destination = vim.fn.fnamemodify(destination, ":p")
end

if utils.is_windows then
destination = utils.windowize_path(destination)
end
destination = utils.normalize_path(destination)
if loop.fs_stat(destination) then
log.warn("File already exists")
return
end

local complete = vim.schedule_wrap(function()
events.fire_event(events.FILE_ADDED, destination)
if callback then
callback(destination)
end
end)
local event_result = events.fire_event(events.BEFORE_FILE_ADD, destination) or {}
if event_result.handled then
complete()
return
end

create_all_parents(destination)
if is_dir then
loop.fs_mkdir(destination, 493)
Expand All @@ -403,17 +424,50 @@ M.create_node = function(in_directory, callback, using_root_directory)
loop.fs_close(fd)
end
end

vim.schedule(function()
events.fire_event(events.FILE_ADDED, destination)
if callback then
callback(destination)
end
end)
complete()
end
end)
end

---Recursively delete a directory and its children.
---@param dir_path string Directory to delete.
---@return boolean success Whether the directory was deleted.
local function delete_dir(dir_path)
local handle = loop.fs_scandir(dir_path)
if type(handle) == "string" then
api.nvim_err_writeln(handle)
return false
end

if not handle then
log.error("could not scan dir " .. dir_path)
return false
end

while true do
local child_name, t = loop.fs_scandir_next(handle)
if not child_name then
break
end

local child_path = dir_path .. "/" .. child_name
if t == "directory" then
local success = delete_dir(child_path)
if not success then
log.error("failed to delete ", child_path)
return false
end
else
local success = loop.fs_unlink(child_path)
if not success then
return false
end
clear_buffer(child_path)
end
end
return loop.fs_rmdir(dir_path) or false
end

-- Delete Node
M.delete_node = function(path, callback, noconfirm)
local _, name = utils.split_path(path)
Expand Down Expand Up @@ -454,39 +508,18 @@ M.delete_node = function(path, callback, noconfirm)
return
end

local do_delete = function(confirmed)
if not confirmed then
return
end

local function delete_dir(dir_path)
local handle = loop.fs_scandir(dir_path)
if type(handle) == "string" then
return api.nvim_err_writeln(handle)
local do_delete = function()
local complete = vim.schedule_wrap(function()
events.fire_event(events.FILE_DELETED, path)
if callback then
callback(path)
end
end)

while true do
local child_name, t = loop.fs_scandir_next(handle)
if not child_name then
break
end

local child_path = dir_path .. "/" .. child_name
if t == "directory" then
local success = delete_dir(child_path)
if not success then
log.error("failed to delete ", child_path)
return false
end
else
local success = loop.fs_unlink(child_path)
if not success then
return false
end
clear_buffer(child_path)
end
end
return loop.fs_rmdir(dir_path)
local event_result = events.fire_event(events.BEFORE_FILE_DELETE, path) or {}
if event_result.handled then
complete()
return
end

if _type == "directory" then
Expand Down Expand Up @@ -526,19 +559,17 @@ M.delete_node = function(path, callback, noconfirm)
end
clear_buffer(path)
end

vim.schedule(function()
events.fire_event(events.FILE_DELETED, path)
if callback then
callback(path)
end
end)
complete()
end

if noconfirm then
do_delete(true)
do_delete()
else
inputs.confirm(msg, do_delete)
inputs.confirm(msg, function(confirmed)
if confirmed then
do_delete()
end
end)
end
end

Expand Down Expand Up @@ -593,9 +624,8 @@ local rename_node = function(msg, name, get_destination, path, callback)
if err then
log.warn("Could not rename the files")
return
else
complete()
end
complete()
end)
end

Expand All @@ -605,6 +635,7 @@ local rename_node = function(msg, name, get_destination, path, callback)
callback = fs_rename,
}) or {}
if event_result.handled then
complete()
return
end
fs_rename()
Expand Down
Loading