Skip to content
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
58 changes: 36 additions & 22 deletions lua/neo-tree/log.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ local default_config = {
-- {{{ NO NEED TO CHANGE
local log = {}

local unpack = unpack

local notify = function(message, level_config)
if type(vim.notify) == "table" then
-- probably using nvim-notify
Expand All @@ -60,7 +58,7 @@ log.new = function(config, standalone)
string.format("%s/%s.log", vim.api.nvim_call_function("stdpath", { "data" }), config.plugin)

local obj
if standalone then
if not standalone then
obj = log
else
obj = {}
Expand All @@ -70,7 +68,7 @@ log.new = function(config, standalone)
obj.use_file = function(file, quiet)
if file == false then
if not quiet then
obj.info("[neo-tree] Logging to file disabled")
obj.info("Logging to file disabled")
end
config.use_file = false
else
Expand All @@ -81,7 +79,7 @@ log.new = function(config, standalone)
end
config.use_file = true
if not quiet then
obj.info("[neo-tree] Logging to file: " .. obj.outfile)
obj.info("Logging to file: " .. obj.outfile)
end
end
end
Expand Down Expand Up @@ -128,6 +126,21 @@ log.new = function(config, standalone)
return table.concat(t, " ")
end

---@param name string
---@param msg string
local log_to_file = function(name, msg)
local info = debug.getinfo(2, "Sl")
local lineinfo = info.short_src .. ":" .. info.currentline
local str = string.format("[%-6s%s] %s: %s\n", name, os.date(), lineinfo, msg)
local fp = io.open(obj.outfile, "a")
if fp then
fp:write(str)
fp:close()
else
print("[neo-tree] Could not open log file: " .. obj.outfile)
end
end

local log_at_level = function(level, level_config, message_maker, ...)
-- Return early if we're below the config.level
if level < levels[config.level] then
Expand All @@ -137,22 +150,13 @@ log.new = function(config, standalone)
if vim.v.dying > 0 or vim.v.exiting ~= vim.NIL then
return
end
local nameupper = level_config.name:upper()

local msg = message_maker(...)
local info = debug.getinfo(2, "Sl")
local lineinfo = info.short_src .. ":" .. info.currentline

-- Output to log file
if config.use_file then
local str = string.format("[%-6s%s] %s: %s\n", nameupper, os.date(), lineinfo, msg)
local fp = io.open(obj.outfile, "a")
if fp then
fp:write(str)
fp:close()
else
print("[neo-tree] Could not open log file: " .. obj.outfile)
end
local nameupper = level_config.name:upper()
log_to_file(nameupper, msg)
end

-- Output to console
Expand All @@ -163,13 +167,13 @@ log.new = function(config, standalone)
end
end

for i, x in ipairs(config.modes) do
obj[x.name] = function(...)
return log_at_level(i, x, make_string, ...)
for i, mode in ipairs(config.modes) do
obj[mode.name] = function(...)
return log_at_level(i, mode, make_string, ...)
end

obj[("fmt_%s"):format(x.name)] = function()
return log_at_level(i, x, function(...)
obj[("fmt_%s"):format(mode.name)] = function()
return log_at_level(i, mode, function(...)
local passed = { ... }
local fmt = table.remove(passed, 1)
local inspected = {}
Expand All @@ -180,9 +184,19 @@ log.new = function(config, standalone)
end)
end
end

obj.assert = function(v, ...)
if v then
return v, ...
end
if config.use_file then
log_to_file("ERROR", table.concat({ ... }, " "))
end
error(...)
end
end

log.new(default_config, true)
log.new(default_config, false)
-- }}}

return log
110 changes: 73 additions & 37 deletions lua/neo-tree/sources/filesystem/lib/fs_actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ local utils = require("neo-tree.utils")
local inputs = require("neo-tree.ui.inputs")
local events = require("neo-tree.events")
local log = require("neo-tree.log")
local Path = require("plenary").path
local Path = require("plenary.path")

local M = {}

Expand Down Expand Up @@ -152,14 +152,15 @@ local function rename_buffer(old_path, new_path)
end
end

local folder_perm = tonumber("755", 8)
local function create_all_parents(path)
local function create_all_as_folders(in_path)
if not uv.fs_stat(in_path) then
local parent, _ = utils.split_path(in_path)
if parent then
create_all_as_folders(parent)
end
uv.fs_mkdir(in_path, 493)
uv.fs_mkdir(in_path, folder_perm)
end
end

Expand All @@ -170,7 +171,7 @@ end
-- Gets a non-existing filename from the user and executes the callback with it.
---@param source string
---@param destination string
---@param using_root_directory boolean
---@param using_root_directory string?
---@param name_chosen_callback fun(string)
---@param first_message string?
local function get_unused_name(
Expand Down Expand Up @@ -204,7 +205,13 @@ local function get_unused_name(
end
end

-- Move Node
---Copy Node
---@generic S : string
---@generic D : string?
---@param source S
---@param destination D
---@param callback fun(source: S, destination: D|S)
---@param using_root_directory string?
M.move_node = function(source, destination, callback, using_root_directory)
log.trace(
"Moving node: ",
Expand All @@ -216,6 +223,17 @@ M.move_node = function(source, destination, callback, using_root_directory)
)
local _, name = utils.split_path(source)
get_unused_name(source, destination or source, using_root_directory, function(dest)
local parent_of_dest, _ = utils.split_path(dest)
if source == parent_of_dest then
log.warn("Cannot move " .. source .. " to itself")
return
end

if uv.fs_stat(source).type == "directory" and utils.is_descendant(source, destination) then
log.warn("Cannot move " .. source .. " to its own descendant " .. parent_of_dest)
return
end

-- Resolve user-inputted relative paths out of the absolute paths
dest = vim.fs.normalize(dest)
if utils.is_windows then
Expand Down Expand Up @@ -284,52 +302,70 @@ local function check_path_copy_result(flat_result)
return true
end

-- Copy Node
M.copy_node = function(source, _destination, callback, using_root_directory)
---Copy Node
---@generic S : string
---@generic D : string?
---@param source S
---@param destination D
---@param callback fun(source: S, destination: D|S)
---@param using_root_directory string?
M.copy_node = function(source, destination, callback, using_root_directory)
local _, name = utils.split_path(source)
get_unused_name(source, _destination or source, using_root_directory, function(destination)
local parent_path, _ = utils.split_path(destination)
if source == parent_path then
log.warn("Cannot copy a file/folder to itself")
get_unused_name(source, destination or source, using_root_directory, function(dest)
local parent_of_dest, _ = utils.split_path(dest)
if source == parent_of_dest then
log.warn("Cannot copy " .. source .. " to itself")
return
end

local event_result = events.fire_event(events.BEFORE_FILE_ADD, destination) or {}
if event_result.handled then
if uv.fs_stat(source).type == "directory" and utils.is_descendant(source, destination) then
log.warn("Cannot copy " .. source .. " to its own descendant " .. parent_of_dest)
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
-- the potential non-existing parent directories of the destination.
create_all_parents(destination)
end
local success, result = pcall(source_path.copy, source_path, {
destination = destination,
recursive = true,
parents = true,
})
if not success then
log.error("Could not copy the file(s) from", source, "to", destination, ":", result)
local event_result = events.fire_event(events.BEFORE_FILE_ADD, dest) or {}
if event_result.handled then
return
end

-- It can happen that the Path.copy() function returns successfully but
-- the copy action still failed. In this case the copy() result contains
-- a nested table of Path instances for each file copied, and the success
-- result.
local flat_result = {}
flatten_path_copy_result(flat_result, result)
if not check_path_copy_result(flat_result) then
log.error("Could not copy the file(s) from", source, "to", destination, ":", flat_result)
return
local source_stat = log.assert(uv.fs_lstat(source))
if source_stat.type == "link" then
local target = log.assert(uv.fs_readlink(source))
local symlink_ok, err = uv.fs_symlink(target, destination)
log.assert(symlink_ok, "Could not copy symlink ", source, "to", destination, ":", err)
else
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
-- the potential non-existing parent directories of the destination.
create_all_parents(dest)
end
local success, result = pcall(source_path.copy, source_path, {
destination = dest,
recursive = true,
parents = true,
})
if not success then
log.error("Could not copy the file(s) from", source, "to", dest, ":", result)
return
end

-- It can happen that the Path.copy() function returns successfully but
-- the copy action still failed. In this case the copy() result contains
-- a nested table of Path instances for each file copied, and the success
-- result.
local flat_result = {}
flatten_path_copy_result(flat_result, result)
if not check_path_copy_result(flat_result) then
log.error("Could not copy the file(s) from", source, "to", dest, ":", flat_result)
return
end
end

vim.schedule(function()
events.fire_event(events.FILE_ADDED, destination)
events.fire_event(events.FILE_ADDED, dest)
if callback then
callback(source, destination)
callback(source, dest)
end
end)
end, 'Copy "' .. name .. '" to:')
Expand Down Expand Up @@ -378,7 +414,7 @@ M.create_directory = function(in_directory, callback, using_root_directory)
end

create_all_parents(destination)
uv.fs_mkdir(destination, 493)
uv.fs_mkdir(destination, folder_perm)

vim.schedule(function()
events.fire_event(events.FILE_ADDED, destination)
Expand Down
30 changes: 16 additions & 14 deletions lua/neo-tree/types/fixes/uv.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---@meta
---A series of edited backports from neovim's 0.12 type files since lua-ls has incorrect types.

---@class uv
---@field constants {O_RDONLY: integer, O_WRONLY: integer, O_RDWR: integer, O_APPEND: integer, O_CREAT: integer, O_DSYNC: integer, O_EXCL: integer, O_NOCTTY: integer, O_NONBLOCK: integer, O_RSYNC: integer, O_SYNC: integer, O_TRUNC: integer, SOCK_STREAM: integer, SOCK_DGRAM: integer, SOCK_SEQPACKET: integer, SOCK_RAW: integer, SOCK_RDM: integer, AF_UNIX: integer, AF_INET: integer, AF_INET6: integer, AF_IPX: integer, AF_NETLINK: integer, AF_X25: integer, AF_AX25: integer, AF_ATMPVC: integer, AF_APPLETALK: integer, AF_PACKET: integer, AI_ADDRCONFIG: integer, AI_V4MAPPED: integer, AI_ALL: integer, AI_NUMERICHOST: integer, AI_PASSIVE: integer, AI_NUMERICSERV: integer, SIGHUP: integer, SIGINT: integer, SIGQUIT: integer, SIGILL: integer, SIGTRAP: integer, SIGABRT: integer, SIGIOT: integer, SIGBUS: integer, SIGFPE: integer, SIGKILL: integer, SIGUSR1: integer, SIGSEGV: integer, SIGUSR2: integer, SIGPIPE: integer, SIGALRM: integer, SIGTERM: integer, SIGCHLD: integer, SIGSTKFLT: integer, SIGCONT: integer, SIGSTOP: integer, SIGTSTP: integer, SIGTTIN: integer, SIGWINCH: integer, SIGIO: integer, SIGPOLL: integer, SIGXFSZ: integer, SIGVTALRM: integer, SIGPROF: integer, UDP_RECVMMSG: integer, UDP_MMSG_CHUNK: integer, UDP_REUSEADDR: integer, UDP_PARTIAL: integer, UDP_IPV6ONLY: integer, TCP_IPV6ONLY: integer, UDP_MMSG_FREE: integer, SIGSYS: integer, SIGPWR: integer, SIGTTOU: integer, SIGURG: integer, SIGXCPU: integer}
Expand All @@ -7,17 +8,18 @@ local uv = {}
--- Opens path as a directory stream. Returns a handle that the user can pass to
--- `uv.fs_readdir()`. The `entries` parameter defines the maximum number of entries
--- that should be returned by each call to `uv.fs_readdir()`.
---
--- **Returns (sync version):** `luv_dir_t userdata` or `fail`
---
--- **Returns (async version):** `uv_fs_t userdata`
---
---@param path string
---@param callback nil
---@param entries integer?
---@return uv.luv_dir_t|nil dir
---@return uv.error.message|nil err
---@return uv.error.name|nil err_name
---
---@overload fun(path: string, callback: uv.fs_opendir.callback, entries?: integer):uv.uv_fs_t
function uv.fs_opendir(path, callback, entries) end
--- @param path string
--- @param entries integer?
--- @return uv.luv_dir_t? dir
--- @return string? err
--- @return string? err_name
--- @overload fun(path: string, callback: fun(err: string?, dir: uv.luv_dir_t?), entries: integer?): uv.uv_fs_t
function uv.fs_opendir(path, entries) end

--- Equivalent to `lstat(2)`.
--- @param path string
--- @return uv.fs_stat.result? stat
--- @return string? err
--- @return string? err_name
--- @overload fun(path: string, callback: fun(err: string?, stat: uv.fs_stat.result?)): uv.uv_fs_t
function uv.fs_lstat(path) end
Loading
Loading