Skip to content

Commit

Permalink
refactor: overhaul the UI
Browse files Browse the repository at this point in the history
  • Loading branch information
stevearc committed Oct 17, 2023
1 parent eeb8976 commit 98294e5
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 36 deletions.
90 changes: 64 additions & 26 deletions lua/oil/adapters/trash/freedesktop.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
-- Based on the FreeDesktop.org trash specification
-- https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
-- TODO make sure that the subdirs for trash use the same entry as the root
local cache = require("oil.cache")
local config = require("oil.config")
local constants = require("oil.constants")
Expand Down Expand Up @@ -103,21 +102,6 @@ local function get_write_trash_dir(path)
return top_trash
end

---@param path string
---@return boolean
local function is_dev_root(path)
if path == "/" then
return true
end
local stat = uv.fs_stat(path)
if not stat then
return false
end
local dev = stat.dev
local parent = vim.fs.dirname(path)
return uv.fs_stat(parent).dev ~= dev
end

---@param path string
---@return string[]
local function get_read_trash_dirs(path)
Expand All @@ -141,20 +125,24 @@ M.normalize_url = function(url, callback)
)
end

---@param _url string
---@param url string
---@param entry oil.Entry
---@param cb fun(path: string)
M.get_entry_path = function(_url, entry, cb)
M.get_entry_path = function(url, entry, cb)
local internal_entry = assert(cache.get_entry_by_id(entry.id))
local meta = internal_entry[FIELD_META]
---@type oil.TrashInfo
local trash_info = meta.trash_info
if not trash_info then
-- This is a subpath in the trash
M.normalize_url(url, cb)
return
end
local path = fs.os_to_posix_path(trash_info.trash_file)
if meta.stat.type == "directory" then
path = util.addslash(path)
end
local url = "oil://" .. path
cb(url)
cb("oil://" .. path)
end

---@class oil.TrashInfo
Expand Down Expand Up @@ -237,7 +225,6 @@ M.list = function(url, column_defs, cb)
cb = vim.schedule_wrap(cb)
local _, path = util.parse_url(url)
assert(path)
local is_in_dev_root = is_dev_root(path)
local trash_dirs = get_read_trash_dirs(path)
local trash_idx = 0

Expand All @@ -248,6 +235,16 @@ M.list = function(url, column_defs, cb)
if not trash_dir then
return cb()
end

-- Show all files from the trash directory if we are in the root of the device, which we can
-- tell if the trash dir is a subpath of our current path
local show_all_files = fs.is_subpath(path, trash_dir)
-- The first trash dir is a special case; it is in the home directory and we should only show
-- all entries if we are in the top root path "/"
if trash_idx == 1 then
show_all_files = path == "/"
end

local info_dir = fs.join(trash_dir, "info")
---@diagnostic disable-next-line: param-type-mismatch
uv.fs_opendir(info_dir, function(open_err, fd)
Expand Down Expand Up @@ -288,7 +285,7 @@ M.list = function(url, column_defs, cb)
poll()
else
local parent = util.addslash(vim.fn.fnamemodify(info.original_path, ":h"))
if path == parent or is_in_dev_root then
if path == parent or show_all_files then
local name = vim.fn.fnamemodify(info.trash_file, ":t")
---@diagnostic disable-next-line: undefined-field
local cache_entry = cache.create_entry(url, name, info.stat.type)
Expand All @@ -300,6 +297,21 @@ M.list = function(url, column_defs, cb)
}
table.insert(internal_entries, cache_entry)
end
if path ~= parent and (show_all_files or fs.is_subpath(path, parent)) then
local name = parent:sub(path:len() + 1)
local next_par = vim.fs.dirname(name)
while next_par ~= "." do
name = next_par
next_par = vim.fs.dirname(name)
end
---@diagnostic disable-next-line: undefined-field
local cache_entry = cache.create_entry(url, name, "directory")

cache_entry[FIELD_META] = {
stat = info.stat,
}
table.insert(internal_entries, cache_entry)
end
poll()
end
end)
Expand Down Expand Up @@ -338,16 +350,20 @@ file_columns.mtime = {
local meta = entry[FIELD_META]
---@type oil.TrashInfo
local trash_info = meta.trash_info
local time = trash_info and trash_info.deletion_date or meta.stat and meta.stat.mtime.sec
if not time then
return nil
end
local fmt = conf and conf.format
local ret
if fmt then
ret = vim.fn.strftime(fmt, trash_info.deletion_date)
ret = vim.fn.strftime(fmt, time)
else
local year = vim.fn.strftime("%Y", trash_info.deletion_date)
local year = vim.fn.strftime("%Y", time)
if year ~= current_year then
ret = vim.fn.strftime("%b %d %Y", trash_info.deletion_date)
ret = vim.fn.strftime("%b %d %Y", time)
else
ret = vim.fn.strftime("%b %d %H:%M", trash_info.deletion_date)
ret = vim.fn.strftime("%b %d %H:%M", time)
end
end
return ret
Expand Down Expand Up @@ -384,6 +400,28 @@ end

M.supported_cross_adapter_actions = { files = "move" }

---@param action oil.Action
---@return boolean
M.filter_action = function(action)
if action.type == "create" then
return false
elseif action.type == "delete" then
local entry = assert(cache.get_entry_by_url(action.url))
local meta = entry[FIELD_META]
return meta.trash_info ~= nil
elseif action.type == "move" then
local src_adapter = assert(config.get_adapter_by_scheme(action.src_url))
local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url))
return src_adapter.name == "files" or dest_adapter.name == "files"
elseif action.type == "copy" then
local src_adapter = assert(config.get_adapter_by_scheme(action.src_url))
local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url))
return src_adapter.name == "files" or dest_adapter.name == "files"
else
error(string.format("Bad action type '%s'", action.type))
end
end

---@param action oil.Action
---@return string
M.render_action = function(action)
Expand Down
1 change: 1 addition & 0 deletions lua/oil/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ local M = {}
---@field write_file? fun(bufnr: integer) Used for adapters that deal with remote/virtual files. Write the contents of a buffer to the destination.
---@field supported_cross_adapter_actions? table<string, oil.CrossAdapterAction> Mapping of adapter name to enum for all other adapters that can be used as a src or dest for move/copy actions.
---@field disable_changes? boolean When true, adapter will not support creating new entries or changing (e.g. renaming) existing entries
---@field filter_action? fun(action: oil.Action): boolean When present, filter out actions as they are created

-- TODO remove after https://github.com/folke/neodev.nvim/pull/163 lands
---@diagnostic disable: undefined-field
Expand Down
23 changes: 17 additions & 6 deletions lua/oil/mutator/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ M.create_actions_from_diffs = function(all_diffs)
if not adapter then
error("Missing adapter")
end
local function add_action(action)
if not adapter.filter_action or adapter.filter_action(action) then
table.insert(actions, action)
end
end
local parent_url = vim.api.nvim_buf_get_name(bufnr)
for _, diff in ipairs(diffs) do
if diff.type == "new" then
Expand All @@ -86,7 +91,7 @@ M.create_actions_from_diffs = function(all_diffs)
-- Parse alternations like foo.{js,test.js}
for _, alt in ipairs(vim.split(alternation, ",")) do
local alt_url = url .. "/" .. v:gsub("{[^}]+}", alt)
table.insert(actions, {
add_action({
type = "create",
url = alt_url,
entry_type = entry_type,
Expand All @@ -95,7 +100,7 @@ M.create_actions_from_diffs = function(all_diffs)
end
else
url = url .. "/" .. v
table.insert(actions, {
add_action({
type = "create",
url = url,
entry_type = entry_type,
Expand All @@ -105,7 +110,7 @@ M.create_actions_from_diffs = function(all_diffs)
end
end
elseif diff.type == "change" then
table.insert(actions, {
add_action({
type = "change",
url = parent_url .. diff.name,
entry_type = diff.entry_type,
Expand All @@ -121,6 +126,12 @@ M.create_actions_from_diffs = function(all_diffs)
end
end

local function add_action(action)
local adapter = assert(config.get_adapter_by_scheme(action.dest_url or action.url))
if not adapter.filter_action or adapter.filter_action(action) then
table.insert(actions, action)
end
end
for id, diffs in pairs(diff_by_id) do
local entry = cache.get_entry_by_id(id)
if not entry then
Expand All @@ -131,7 +142,7 @@ M.create_actions_from_diffs = function(all_diffs)
if has_create then
-- MOVE (+ optional copies) when has both creates and delete
for i, diff in ipairs(diffs) do
table.insert(actions, {
add_action({
type = i == #diffs and "move" or "copy",
entry_type = entry[FIELD_TYPE],
dest_url = diff.dest,
Expand All @@ -140,7 +151,7 @@ M.create_actions_from_diffs = function(all_diffs)
end
else
-- DELETE when no create
table.insert(actions, {
add_action({
type = "delete",
entry_type = entry[FIELD_TYPE],
url = cache.get_parent_url(id) .. entry[FIELD_NAME],
Expand All @@ -149,7 +160,7 @@ M.create_actions_from_diffs = function(all_diffs)
else
-- COPY when create but no delete
for _, diff in ipairs(diffs) do
table.insert(actions, {
add_action({
type = "copy",
entry_type = entry[FIELD_TYPE],
src_url = cache.get_parent_url(id) .. entry[FIELD_NAME],
Expand Down
10 changes: 6 additions & 4 deletions lua/oil/view.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ 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 keymap_util = require("oil.keymap_util")
local loading = require("oil.loading")
local util = require("oil.util")
Expand Down Expand Up @@ -427,7 +428,7 @@ local function render_buffer(bufnr, opts)
jump = false,
jump_first = false,
})
local scheme = util.parse_url(bufname)
local scheme, buf_path = util.parse_url(bufname)
local adapter = util.get_adapter(bufnr)
if not scheme or not adapter then
return false
Expand Down Expand Up @@ -474,17 +475,18 @@ local function render_buffer(bufnr, opts)
util.set_highlights(bufnr, highlights)

-- Show original location of trash file as virtual text
if adapter.name == "trash" and bufname == "oil-trash:///" then
if adapter.name == "trash" then
local ns = vim.api.nvim_create_namespace("OilVtext")
vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
local os_path = fs.posix_to_os_path(assert(buf_path))
for i, entry in ipairs(entry_list) do
local meta = entry[FIELD_META]
---@type nil|oil.TrashInfo
local trash_info = meta and meta.trash_info
if trash_info then
vim.api.nvim_buf_set_extmark(0, ns, i - 1, 0, {
vim.api.nvim_buf_set_extmark(bufnr, ns, i - 1, 0, {
virt_text = {
{ "" .. trash_info.original_path, "OilTrashSourcePath" },
{ "" .. fs.shorten_path(trash_info.original_path, os_path), "OilTrashSourcePath" },
},
})
end
Expand Down

0 comments on commit 98294e5

Please sign in to comment.