diff --git a/lua/oil/adapters/files.lua b/lua/oil/adapters/files.lua index 7b92cb94..1df9fe58 100644 --- a/lua/oil/adapters/files.lua +++ b/lua/oil/adapters/files.lua @@ -34,6 +34,8 @@ local function read_link_data(path, cb) ) end +M.supports_subdir_rename = true + ---@param path string ---@param entry_type nil|oil.EntryType ---@return string diff --git a/lua/oil/adapters/ssh.lua b/lua/oil/adapters/ssh.lua index c52f5a99..dacbc083 100644 --- a/lua/oil/adapters/ssh.lua +++ b/lua/oil/adapters/ssh.lua @@ -27,6 +27,8 @@ local function scp(args, ...) shell.run(cmd, ...) end +M.supports_subdir_rename = false + ---@param oil_url string ---@return oil.sshUrl M.parse_url = function(oil_url) diff --git a/lua/oil/adapters/test.lua b/lua/oil/adapters/test.lua index c4176ef4..b5a410ed 100644 --- a/lua/oil/adapters/test.lua +++ b/lua/oil/adapters/test.lua @@ -2,6 +2,8 @@ local cache = require("oil.cache") local util = require("oil.util") local M = {} +M.supports_subdir_rename = true + ---@param url string ---@param callback fun(url: string) M.normalize_url = function(url, callback) @@ -88,6 +90,12 @@ M.read_file = function(bufnr) -- pass end +---@param path string +---@return boolean +M.file_exists = function(path) + return false +end + ---@param bufnr integer M.write_file = function(bufnr) -- pass diff --git a/lua/oil/adapters/trash/freedesktop.lua b/lua/oil/adapters/trash/freedesktop.lua index 24a6e683..04c4c96a 100644 --- a/lua/oil/adapters/trash/freedesktop.lua +++ b/lua/oil/adapters/trash/freedesktop.lua @@ -12,6 +12,8 @@ local FIELD_META = constants.FIELD_META local M = {} +M.supports_subdir_rename = false + local function ensure_trash_dir(path) local mode = 448 -- 0700 fs.mkdirp(fs.join(path, "info"), mode) diff --git a/lua/oil/adapters/trash/mac.lua b/lua/oil/adapters/trash/mac.lua index 8b2d33a3..bff866f0 100644 --- a/lua/oil/adapters/trash/mac.lua +++ b/lua/oil/adapters/trash/mac.lua @@ -8,6 +8,8 @@ local uv = vim.uv or vim.loop local M = {} +M.supports_subdir_rename = false + local function touch_dir(path) uv.fs_mkdir(path, 448) -- 0700 end diff --git a/lua/oil/adapters/trash/windows.lua b/lua/oil/adapters/trash/windows.lua index ecfca61c..6db73152 100644 --- a/lua/oil/adapters/trash/windows.lua +++ b/lua/oil/adapters/trash/windows.lua @@ -12,6 +12,8 @@ local FIELD_TYPE = constants.FIELD_TYPE local M = {} +M.supports_subdir_rename = false + ---@return string local function get_trash_dir() local cwd = assert(vim.fn.getcwd()) diff --git a/lua/oil/init.lua b/lua/oil/init.lua index be76c2df..d22e4995 100644 --- a/lua/oil/init.lua +++ b/lua/oil/init.lua @@ -17,6 +17,7 @@ local M = {} ---@class (exact) oil.Adapter ---@field name string The unique name of the adapter (this will be set automatically) ---@field list fun(path: string, column_defs: string[], cb: fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun())) Async function to list a directory. +---@field supports_subdir_rename boolean Whether the adapter allows renaming of files into a subdirectory ---@field file_exists fun(path: string) Returns true if the file at path exists ---@field is_modifiable fun(bufnr: integer): boolean Return true if this directory is modifiable (allows for directories with read-only permissions). ---@field get_column fun(name: string): nil|oil.ColumnDefinition If the adapter has any adapter-specific columns, return them when fetched by name. diff --git a/lua/oil/mutator/init.lua b/lua/oil/mutator/init.lua index 6755b600..ebbbfb77 100644 --- a/lua/oil/mutator/init.lua +++ b/lua/oil/mutator/init.lua @@ -92,60 +92,47 @@ M.create_actions_from_diffs = function(all_diffs) local parent_url = vim.api.nvim_buf_get_name(bufnr) for _, diff in ipairs(diffs) do if diff.type == "new" then - if diff.id then - -- Parse nested files like foo/bar/baz - -- Create the parent directories if they don't exist - local path_sep = fs.is_windows and "[/\\]" or "/" - local pieces = vim.split(diff.name, path_sep) - local url = parent_url:gsub("/$", "") - for i, v in ipairs(pieces) do - if i == #pieces then - break - end - - url = url .. "/" .. v - add_action({ - type = "create", - url = url, - entry_type = "directory", - link = diff.link, - }) - end + local file_name = diff.name + local url = parent_url:gsub("/$", "") + --- Parse nested files like foo/bar/baz + local dirs = vim.split(diff.name, fs.sep) + file_name = table.remove(dirs) + for _, v in ipairs(dirs) do + url = url .. "/" .. v + add_action({ + type = "create", + url = url, + entry_type = "directory", + link = diff.link, + }) + end + if diff.id then local by_id = diff_by_id[diff.id] ---HACK: set the destination on this diff for use later ---@diagnostic disable-next-line: inject-field diff.dest = parent_url .. diff.name table.insert(by_id, diff) else - -- Parse nested files like foo/bar/baz - local path_sep = fs.is_windows and "[/\\]" or "/" - local pieces = vim.split(diff.name, path_sep) - local url = parent_url:gsub("/$", "") - for i, v in ipairs(pieces) do - local is_last = i == #pieces - local entry_type = is_last and diff.entry_type or "directory" - local alternation = v:match("{([^}]+)}") - if is_last and alternation then - -- Parse alternations like foo.{js,test.js} - for _, alt in ipairs(vim.split(alternation, ",")) do - local alt_url = url .. "/" .. v:gsub("{[^}]+}", alt) - add_action({ - type = "create", - url = alt_url, - entry_type = entry_type, - link = diff.link, - }) - end - else - url = url .. "/" .. v + local alternation = file_name:match("{([^}]+)}") + if alternation then + -- Parse alternations like foo.{js,test.js} + for _, alt in ipairs(vim.split(alternation, ",")) do + local alt_url = url .. "/" .. file_name:gsub("{[^}]+}", alt) add_action({ type = "create", - url = url, - entry_type = entry_type, + url = alt_url, + entry_type = diff.entry_type, link = diff.link, }) end + else + add_action({ + type = "create", + url = url .. "/" .. file_name, + entry_type = diff.entry_type, + link = diff.link, + }) end end elseif diff.type == "change" then diff --git a/lua/oil/mutator/parser.lua b/lua/oil/mutator/parser.lua index d060d867..2d4b4011 100644 --- a/lua/oil/mutator/parser.lua +++ b/lua/oil/mutator/parser.lua @@ -240,7 +240,7 @@ M.parse = function(bufnr) elseif not entry then err_message = "Could not find existing entry (was the ID changed?)" elseif - adapter.name ~= "files" + not adapter.supports_subdir_rename and (parsed_entry.name:match("/") or parsed_entry.name:match(fs.sep)) then err_message = "Filename cannot contain path separator"