refactor: revert module namespace from canola back to oil
Problem: the canola rename creates unnecessary friction for users
migrating from stevearc/oil.nvim — every `require('oil')` call and
config reference must change.
Solution: revert all module paths, URL schemes, autocmd groups,
highlight groups, and filetype names back to `oil`. The repo stays
`canola.nvim` for identity; the code is a drop-in replacement.
This commit is contained in:
parent
9298b48c5d
commit
8dd67f91e8
68 changed files with 1622 additions and 1625 deletions
678
lua/oil/adapters/files.lua
Normal file
678
lua/oil/adapters/files.lua
Normal file
|
|
@ -0,0 +1,678 @@
|
|||
local cache = require('oil.cache')
|
||||
local columns = require('oil.columns')
|
||||
local config = require('oil.config')
|
||||
local constants = require('oil.constants')
|
||||
local fs = require('oil.fs')
|
||||
local git = require('oil.git')
|
||||
local log = require('oil.log')
|
||||
local permissions = require('oil.adapters.files.permissions')
|
||||
local util = require('oil.util')
|
||||
local uv = vim.uv or vim.loop
|
||||
|
||||
local M = {}
|
||||
|
||||
local FIELD_NAME = constants.FIELD_NAME
|
||||
local FIELD_TYPE = constants.FIELD_TYPE
|
||||
local FIELD_META = constants.FIELD_META
|
||||
|
||||
local function read_link_data(path, cb)
|
||||
uv.fs_readlink(
|
||||
path,
|
||||
vim.schedule_wrap(function(link_err, link)
|
||||
if link_err then
|
||||
cb(link_err)
|
||||
else
|
||||
assert(link)
|
||||
local stat_path = link
|
||||
if not fs.is_absolute(link) then
|
||||
stat_path = fs.join(vim.fn.fnamemodify(path, ':h'), link)
|
||||
end
|
||||
uv.fs_stat(stat_path, function(stat_err, stat)
|
||||
cb(nil, link, stat)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
)
|
||||
end
|
||||
|
||||
---@class (exact) oil.FilesAdapter: oil.Adapter
|
||||
---@field to_short_os_path fun(path: string, entry_type: nil|oil.EntryType): string
|
||||
|
||||
---@param path string
|
||||
---@param entry_type nil|oil.EntryType
|
||||
---@return string
|
||||
M.to_short_os_path = function(path, entry_type)
|
||||
local shortpath = fs.shorten_path(fs.posix_to_os_path(path))
|
||||
if entry_type == 'directory' then
|
||||
shortpath = util.addslash(shortpath, true)
|
||||
end
|
||||
return shortpath
|
||||
end
|
||||
|
||||
local file_columns = {}
|
||||
|
||||
file_columns.size = {
|
||||
require_stat = true,
|
||||
|
||||
render = function(entry, conf)
|
||||
local meta = entry[FIELD_META]
|
||||
local stat = meta and meta.stat
|
||||
if not stat then
|
||||
return columns.EMPTY
|
||||
end
|
||||
if entry[FIELD_TYPE] == 'directory' then
|
||||
return columns.EMPTY
|
||||
end
|
||||
if stat.size >= 1e9 then
|
||||
return string.format('%.1fG', stat.size / 1e9)
|
||||
elseif stat.size >= 1e6 then
|
||||
return string.format('%.1fM', stat.size / 1e6)
|
||||
elseif stat.size >= 1e3 then
|
||||
return string.format('%.1fk', stat.size / 1e3)
|
||||
else
|
||||
return string.format('%d', stat.size)
|
||||
end
|
||||
end,
|
||||
|
||||
get_sort_value = function(entry)
|
||||
local meta = entry[FIELD_META]
|
||||
local stat = meta and meta.stat
|
||||
if stat then
|
||||
return stat.size
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
|
||||
parse = function(line, conf)
|
||||
return line:match('^(%d+%S*)%s+(.*)$')
|
||||
end,
|
||||
}
|
||||
|
||||
-- TODO support file permissions on windows
|
||||
if not fs.is_windows then
|
||||
file_columns.permissions = {
|
||||
require_stat = true,
|
||||
|
||||
render = function(entry, conf)
|
||||
local meta = entry[FIELD_META]
|
||||
local stat = meta and meta.stat
|
||||
if not stat then
|
||||
return columns.EMPTY
|
||||
end
|
||||
return permissions.mode_to_str(stat.mode)
|
||||
end,
|
||||
|
||||
parse = function(line, conf)
|
||||
return permissions.parse(line)
|
||||
end,
|
||||
|
||||
compare = function(entry, parsed_value)
|
||||
local meta = entry[FIELD_META]
|
||||
if parsed_value and meta and meta.stat and meta.stat.mode then
|
||||
local mask = bit.lshift(1, 12) - 1
|
||||
local old_mode = bit.band(meta.stat.mode, mask)
|
||||
if parsed_value ~= old_mode then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
render_action = function(action)
|
||||
local _, path = util.parse_url(action.url)
|
||||
assert(path)
|
||||
return string.format(
|
||||
'CHMOD %s %s',
|
||||
permissions.mode_to_octal_str(action.value),
|
||||
M.to_short_os_path(path, action.entry_type)
|
||||
)
|
||||
end,
|
||||
|
||||
perform_action = function(action, callback)
|
||||
local _, path = util.parse_url(action.url)
|
||||
assert(path)
|
||||
path = fs.posix_to_os_path(path)
|
||||
uv.fs_stat(path, function(err, stat)
|
||||
if err then
|
||||
return callback(err)
|
||||
end
|
||||
assert(stat)
|
||||
-- We are only changing the lower 12 bits of the mode
|
||||
local mask = bit.bnot(bit.lshift(1, 12) - 1)
|
||||
local old_mode = bit.band(stat.mode, mask)
|
||||
uv.fs_chmod(path, bit.bor(old_mode, action.value), callback)
|
||||
end)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
local current_year
|
||||
-- Make sure we run this import-time effect in the main loop (mostly for tests)
|
||||
vim.schedule(function()
|
||||
current_year = vim.fn.strftime('%Y')
|
||||
end)
|
||||
|
||||
for _, time_key in ipairs({ 'ctime', 'mtime', 'atime', 'birthtime' }) do
|
||||
file_columns[time_key] = {
|
||||
require_stat = true,
|
||||
|
||||
render = function(entry, conf)
|
||||
local meta = entry[FIELD_META]
|
||||
local stat = meta and meta.stat
|
||||
if not stat then
|
||||
return columns.EMPTY
|
||||
end
|
||||
local fmt = conf and conf.format
|
||||
local ret
|
||||
if fmt then
|
||||
ret = vim.fn.strftime(fmt, stat[time_key].sec)
|
||||
else
|
||||
local year = vim.fn.strftime('%Y', stat[time_key].sec)
|
||||
if year ~= current_year then
|
||||
ret = vim.fn.strftime('%b %d %Y', stat[time_key].sec)
|
||||
else
|
||||
ret = vim.fn.strftime('%b %d %H:%M', stat[time_key].sec)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
|
||||
parse = function(line, conf)
|
||||
local fmt = conf and conf.format
|
||||
local pattern
|
||||
if fmt then
|
||||
-- Replace placeholders with a pattern that matches non-space characters (e.g. %H -> %S+)
|
||||
-- and whitespace with a pattern that matches any amount of whitespace
|
||||
-- e.g. "%b %d %Y" -> "%S+%s+%S+%s+%S+"
|
||||
pattern = fmt
|
||||
:gsub('%%.', '%%S+')
|
||||
:gsub('%s+', '%%s+')
|
||||
-- escape `()[]` because those are special characters in Lua patterns
|
||||
:gsub(
|
||||
'%(',
|
||||
'%%('
|
||||
)
|
||||
:gsub('%)', '%%)')
|
||||
:gsub('%[', '%%[')
|
||||
:gsub('%]', '%%]')
|
||||
else
|
||||
pattern = '%S+%s+%d+%s+%d%d:?%d%d'
|
||||
end
|
||||
return line:match('^(' .. pattern .. ')%s+(.+)$')
|
||||
end,
|
||||
|
||||
get_sort_value = function(entry)
|
||||
local meta = entry[FIELD_META]
|
||||
local stat = meta and meta.stat
|
||||
if stat then
|
||||
return stat[time_key].sec
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
---@param column_defs table[]
|
||||
---@return boolean
|
||||
local function columns_require_stat(column_defs)
|
||||
for _, def in ipairs(column_defs) do
|
||||
local name = util.split_config(def)
|
||||
local column = M.get_column(name)
|
||||
---@diagnostic disable-next-line: undefined-field We only put this on the files adapter columns
|
||||
if column and column.require_stat then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@return nil|oil.ColumnDefinition
|
||||
M.get_column = function(name)
|
||||
return file_columns[name]
|
||||
end
|
||||
|
||||
---@param url string
|
||||
---@param callback fun(url: string)
|
||||
M.normalize_url = function(url, callback)
|
||||
local scheme, path = util.parse_url(url)
|
||||
assert(path)
|
||||
|
||||
if fs.is_windows then
|
||||
if path == '/' then
|
||||
return callback(url)
|
||||
else
|
||||
local is_root_drive = path:match('^/%u$')
|
||||
if is_root_drive then
|
||||
return callback(url .. '/')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ':p')
|
||||
uv.fs_realpath(os_path, function(err, new_os_path)
|
||||
local realpath
|
||||
if fs.is_windows then
|
||||
-- Ignore the fs_realpath on windows because it will resolve mapped network drives to the IP
|
||||
-- address instead of using the drive letter
|
||||
realpath = os_path
|
||||
else
|
||||
realpath = new_os_path or os_path
|
||||
end
|
||||
|
||||
uv.fs_stat(
|
||||
realpath,
|
||||
vim.schedule_wrap(function(stat_err, stat)
|
||||
local is_directory
|
||||
if stat then
|
||||
is_directory = stat.type == 'directory'
|
||||
elseif vim.endswith(realpath, '/') or (fs.is_windows and vim.endswith(realpath, '\\')) then
|
||||
is_directory = true
|
||||
else
|
||||
local filetype = vim.filetype.match({ filename = vim.fs.basename(realpath) })
|
||||
is_directory = filetype == nil
|
||||
end
|
||||
|
||||
if is_directory then
|
||||
local norm_path = util.addslash(fs.os_to_posix_path(realpath))
|
||||
callback(scheme .. norm_path)
|
||||
else
|
||||
callback(vim.fn.fnamemodify(realpath, ':.'))
|
||||
end
|
||||
end)
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
---@param url string
|
||||
---@param entry oil.Entry
|
||||
---@param cb fun(path: nil|string)
|
||||
M.get_entry_path = function(url, entry, cb)
|
||||
if entry.id then
|
||||
local parent_url = cache.get_parent_url(entry.id)
|
||||
local scheme, path = util.parse_url(parent_url)
|
||||
M.normalize_url(scheme .. path .. entry.name, cb)
|
||||
else
|
||||
if entry.type == 'directory' then
|
||||
cb(url)
|
||||
else
|
||||
local _, path = util.parse_url(url)
|
||||
local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(assert(path)), ':p')
|
||||
cb(os_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param parent_dir string
|
||||
---@param entry oil.InternalEntry
|
||||
---@param require_stat boolean
|
||||
---@param cb fun(err?: string)
|
||||
local function fetch_entry_metadata(parent_dir, entry, require_stat, cb)
|
||||
local entry_path = fs.posix_to_os_path(parent_dir .. entry[FIELD_NAME])
|
||||
local meta = entry[FIELD_META]
|
||||
if not meta then
|
||||
meta = {}
|
||||
entry[FIELD_META] = meta
|
||||
end
|
||||
|
||||
-- Sometimes fs_readdir entries don't have a type, so we need to stat them.
|
||||
-- See https://github.com/stevearc/oil.nvim/issues/543
|
||||
if not require_stat and not entry[FIELD_TYPE] then
|
||||
require_stat = true
|
||||
end
|
||||
|
||||
-- Make sure we always get fs_stat info for links
|
||||
if entry[FIELD_TYPE] == 'link' then
|
||||
read_link_data(entry_path, function(link_err, link, link_stat)
|
||||
if link_err then
|
||||
log.warn('Error reading link data %s: %s', entry_path, link_err)
|
||||
return cb()
|
||||
end
|
||||
meta.link = link
|
||||
if link_stat then
|
||||
-- Use the fstat of the linked file as the stat for the link
|
||||
meta.link_stat = link_stat
|
||||
meta.stat = link_stat
|
||||
elseif require_stat then
|
||||
-- The link is broken, so let's use the stat of the link itself
|
||||
uv.fs_lstat(entry_path, function(stat_err, stat)
|
||||
if stat_err then
|
||||
log.warn('Error lstat link file %s: %s', entry_path, stat_err)
|
||||
return cb()
|
||||
end
|
||||
meta.stat = stat
|
||||
cb()
|
||||
end)
|
||||
return
|
||||
end
|
||||
|
||||
cb()
|
||||
end)
|
||||
elseif require_stat then
|
||||
uv.fs_stat(entry_path, function(stat_err, stat)
|
||||
if stat_err then
|
||||
log.warn('Error stat file %s: %s', entry_path, stat_err)
|
||||
return cb()
|
||||
end
|
||||
assert(stat)
|
||||
entry[FIELD_TYPE] = stat.type
|
||||
meta.stat = stat
|
||||
cb()
|
||||
end)
|
||||
else
|
||||
cb()
|
||||
end
|
||||
end
|
||||
|
||||
-- On windows, sometimes the entry type from fs_readdir is "link" but the actual type is not.
|
||||
-- See https://github.com/stevearc/oil.nvim/issues/535
|
||||
if fs.is_windows then
|
||||
local old_fetch_metadata = fetch_entry_metadata
|
||||
fetch_entry_metadata = function(parent_dir, entry, require_stat, cb)
|
||||
if entry[FIELD_TYPE] == 'link' then
|
||||
local entry_path = fs.posix_to_os_path(parent_dir .. entry[FIELD_NAME])
|
||||
uv.fs_lstat(entry_path, function(stat_err, stat)
|
||||
if stat_err then
|
||||
log.warn('Error lstat link file %s: %s', entry_path, stat_err)
|
||||
return old_fetch_metadata(parent_dir, entry, require_stat, cb)
|
||||
end
|
||||
assert(stat)
|
||||
entry[FIELD_TYPE] = stat.type
|
||||
local meta = entry[FIELD_META]
|
||||
if not meta then
|
||||
meta = {}
|
||||
entry[FIELD_META] = meta
|
||||
end
|
||||
meta.stat = stat
|
||||
old_fetch_metadata(parent_dir, entry, require_stat, cb)
|
||||
end)
|
||||
else
|
||||
return old_fetch_metadata(parent_dir, entry, require_stat, cb)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param url string
|
||||
---@param column_defs string[]
|
||||
---@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun())
|
||||
local function list_windows_drives(url, column_defs, cb)
|
||||
local _, path = util.parse_url(url)
|
||||
assert(path)
|
||||
local require_stat = columns_require_stat(column_defs)
|
||||
local stdout = ''
|
||||
local jid = vim.fn.jobstart({ 'wmic', 'logicaldisk', 'get', 'name' }, {
|
||||
stdout_buffered = true,
|
||||
on_stdout = function(_, data)
|
||||
stdout = table.concat(data, '\n')
|
||||
end,
|
||||
on_exit = function(_, code)
|
||||
if code ~= 0 then
|
||||
return cb('Error listing windows devices')
|
||||
end
|
||||
local lines = vim.split(stdout, '\n', { plain = true, trimempty = true })
|
||||
-- Remove the "Name" header
|
||||
table.remove(lines, 1)
|
||||
local internal_entries = {}
|
||||
local complete_disk_cb = util.cb_collect(#lines, function(err)
|
||||
if err then
|
||||
cb(err)
|
||||
else
|
||||
cb(nil, internal_entries)
|
||||
end
|
||||
end)
|
||||
|
||||
for _, disk in ipairs(lines) do
|
||||
if disk:match('^%s*$') then
|
||||
-- Skip empty line
|
||||
complete_disk_cb()
|
||||
else
|
||||
disk = disk:gsub(':%s*$', '')
|
||||
local cache_entry = cache.create_entry(url, disk, 'directory')
|
||||
table.insert(internal_entries, cache_entry)
|
||||
fetch_entry_metadata(path, cache_entry, require_stat, complete_disk_cb)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
if jid <= 0 then
|
||||
cb('Could not list windows devices')
|
||||
end
|
||||
end
|
||||
|
||||
---@param url string
|
||||
---@param column_defs string[]
|
||||
---@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun())
|
||||
M.list = function(url, column_defs, cb)
|
||||
local _, path = util.parse_url(url)
|
||||
assert(path)
|
||||
if fs.is_windows and path == '/' then
|
||||
return list_windows_drives(url, column_defs, cb)
|
||||
end
|
||||
local dir = fs.posix_to_os_path(path)
|
||||
local require_stat = columns_require_stat(column_defs)
|
||||
|
||||
---@diagnostic disable-next-line: param-type-mismatch, discard-returns
|
||||
uv.fs_opendir(dir, function(open_err, fd)
|
||||
if open_err then
|
||||
if open_err:match('^ENOENT: no such file or directory') then
|
||||
-- If the directory doesn't exist, treat the list as a success. We will be able to traverse
|
||||
-- and edit a not-yet-existing directory.
|
||||
return cb()
|
||||
else
|
||||
return cb(open_err)
|
||||
end
|
||||
end
|
||||
local read_next
|
||||
read_next = function()
|
||||
uv.fs_readdir(fd, function(err, entries)
|
||||
local internal_entries = {}
|
||||
if err then
|
||||
uv.fs_closedir(fd, function()
|
||||
cb(err)
|
||||
end)
|
||||
return
|
||||
elseif entries then
|
||||
local poll = util.cb_collect(#entries, function(inner_err)
|
||||
if inner_err then
|
||||
cb(inner_err)
|
||||
else
|
||||
cb(nil, internal_entries, read_next)
|
||||
end
|
||||
end)
|
||||
for _, entry in ipairs(entries) do
|
||||
local cache_entry = cache.create_entry(url, entry.name, entry.type)
|
||||
table.insert(internal_entries, cache_entry)
|
||||
fetch_entry_metadata(path, cache_entry, require_stat, poll)
|
||||
end
|
||||
else
|
||||
uv.fs_closedir(fd, function(close_err)
|
||||
if close_err then
|
||||
cb(close_err)
|
||||
else
|
||||
cb()
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
read_next()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
end, 10000)
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@return boolean
|
||||
M.is_modifiable = function(bufnr)
|
||||
local bufname = vim.api.nvim_buf_get_name(bufnr)
|
||||
local _, path = util.parse_url(bufname)
|
||||
assert(path)
|
||||
if fs.is_windows and path == '/' then
|
||||
return false
|
||||
end
|
||||
local dir = fs.posix_to_os_path(path)
|
||||
local stat = uv.fs_stat(dir)
|
||||
if not stat then
|
||||
return true
|
||||
end
|
||||
|
||||
-- fs_access can return nil, force boolean return
|
||||
return uv.fs_access(dir, 'W') == true
|
||||
end
|
||||
|
||||
---@param action oil.Action
|
||||
---@return string
|
||||
M.render_action = function(action)
|
||||
if action.type == 'create' then
|
||||
local _, path = util.parse_url(action.url)
|
||||
assert(path)
|
||||
local ret = string.format('CREATE %s', M.to_short_os_path(path, action.entry_type))
|
||||
if action.link then
|
||||
ret = ret .. ' -> ' .. fs.posix_to_os_path(action.link)
|
||||
end
|
||||
return ret
|
||||
elseif action.type == 'delete' then
|
||||
local _, path = util.parse_url(action.url)
|
||||
assert(path)
|
||||
local short_path = M.to_short_os_path(path, action.entry_type)
|
||||
if config.delete_to_trash then
|
||||
return string.format(' TRASH %s', short_path)
|
||||
else
|
||||
return string.format('DELETE %s', short_path)
|
||||
end
|
||||
elseif action.type == 'move' or action.type == 'copy' then
|
||||
local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url))
|
||||
if dest_adapter == M then
|
||||
local _, src_path = util.parse_url(action.src_url)
|
||||
assert(src_path)
|
||||
local _, dest_path = util.parse_url(action.dest_url)
|
||||
assert(dest_path)
|
||||
return string.format(
|
||||
' %s %s -> %s',
|
||||
action.type:upper(),
|
||||
M.to_short_os_path(src_path, action.entry_type),
|
||||
M.to_short_os_path(dest_path, action.entry_type)
|
||||
)
|
||||
else
|
||||
-- We should never hit this because we don't implement supported_cross_adapter_actions
|
||||
error("files adapter doesn't support cross-adapter move/copy")
|
||||
end
|
||||
else
|
||||
error(string.format("Bad action type: '%s'", action.type))
|
||||
end
|
||||
end
|
||||
|
||||
---@param action oil.Action
|
||||
---@param cb fun(err: nil|string)
|
||||
M.perform_action = function(action, cb)
|
||||
if action.type == 'create' then
|
||||
local _, path = util.parse_url(action.url)
|
||||
assert(path)
|
||||
path = fs.posix_to_os_path(path)
|
||||
|
||||
if config.git.add(path) then
|
||||
local old_cb = cb
|
||||
cb = vim.schedule_wrap(function(err)
|
||||
if not err then
|
||||
git.add(path, old_cb)
|
||||
else
|
||||
old_cb(err)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if action.entry_type == 'directory' then
|
||||
uv.fs_mkdir(path, config.new_dir_mode, function(err)
|
||||
-- Ignore if the directory already exists
|
||||
if not err or err:match('^EEXIST:') then
|
||||
cb()
|
||||
else
|
||||
cb(err)
|
||||
end
|
||||
end)
|
||||
elseif action.entry_type == 'link' and action.link then
|
||||
local flags = nil
|
||||
local target = fs.posix_to_os_path(action.link)
|
||||
if fs.is_windows then
|
||||
flags = {
|
||||
dir = vim.fn.isdirectory(target) == 1,
|
||||
junction = false,
|
||||
}
|
||||
end
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
uv.fs_symlink(target, path, flags, cb)
|
||||
else
|
||||
fs.touch(
|
||||
path,
|
||||
config.new_file_mode,
|
||||
vim.schedule_wrap(function(err)
|
||||
if not err then
|
||||
vim.api.nvim_exec_autocmds(
|
||||
'User',
|
||||
{ pattern = 'OilFileCreated', modeline = false, data = { path = path } }
|
||||
)
|
||||
end
|
||||
cb(err)
|
||||
end)
|
||||
)
|
||||
end
|
||||
elseif action.type == 'delete' then
|
||||
local _, path = util.parse_url(action.url)
|
||||
assert(path)
|
||||
path = fs.posix_to_os_path(path)
|
||||
|
||||
if config.git.rm(path) then
|
||||
local old_cb = cb
|
||||
cb = vim.schedule_wrap(function(err)
|
||||
if not err then
|
||||
git.rm(path, old_cb)
|
||||
else
|
||||
old_cb(err)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if config.delete_to_trash then
|
||||
require('oil.adapters.trash').delete_to_trash(path, cb)
|
||||
else
|
||||
fs.recursive_delete(action.entry_type, path, cb)
|
||||
end
|
||||
elseif action.type == 'move' then
|
||||
local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url))
|
||||
if dest_adapter == M then
|
||||
local _, src_path = util.parse_url(action.src_url)
|
||||
assert(src_path)
|
||||
local _, dest_path = util.parse_url(action.dest_url)
|
||||
assert(dest_path)
|
||||
src_path = fs.posix_to_os_path(src_path)
|
||||
dest_path = fs.posix_to_os_path(dest_path)
|
||||
if config.git.mv(src_path, dest_path) then
|
||||
git.mv(action.entry_type, src_path, dest_path, cb)
|
||||
else
|
||||
fs.recursive_move(action.entry_type, src_path, dest_path, cb)
|
||||
end
|
||||
else
|
||||
-- We should never hit this because we don't implement supported_cross_adapter_actions
|
||||
cb("files adapter doesn't support cross-adapter move")
|
||||
end
|
||||
elseif action.type == 'copy' then
|
||||
local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url))
|
||||
if dest_adapter == M then
|
||||
local _, src_path = util.parse_url(action.src_url)
|
||||
assert(src_path)
|
||||
local _, dest_path = util.parse_url(action.dest_url)
|
||||
assert(dest_path)
|
||||
src_path = fs.posix_to_os_path(src_path)
|
||||
dest_path = fs.posix_to_os_path(dest_path)
|
||||
fs.recursive_copy(action.entry_type, src_path, dest_path, cb)
|
||||
else
|
||||
-- We should never hit this because we don't implement supported_cross_adapter_actions
|
||||
cb("files adapter doesn't support cross-adapter copy")
|
||||
end
|
||||
else
|
||||
cb(string.format('Bad action type: %s', action.type))
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue