Skip to content
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

Support for trashing files #165

Merged
merged 32 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
03c600a
wip: skeleton code for trash adapter
stevearc Aug 21, 2023
906c656
refactor: split trash implementation for mac and linux
stevearc Aug 23, 2023
4edcaf6
fix: ensure we create the .Trash/$uid dir
stevearc Aug 23, 2023
b29e11b
feat: code complete linux trash implementation
stevearc Aug 26, 2023
9aeb0dd
doc: write up trash features
stevearc Aug 26, 2023
cdbc791
feat: code complete mac trash implementation
stevearc Aug 27, 2023
e13a31f
cleanup: remove previous, terrible, undocumented trash feature
stevearc Aug 27, 2023
43aa851
fix: always disabled trash
stevearc Aug 27, 2023
2b97e82
feat: show original path of trashed files
stevearc Aug 27, 2023
7ae2437
doc: add a note about calling actions directly
stevearc Aug 27, 2023
24958a8
fix: bugs in trash implementation
stevearc Aug 27, 2023
9f415bc
fix: schedule_wrap in mac trash
stevearc Aug 28, 2023
ab0b1f5
doc: fix typo and line wrapping
stevearc Sep 6, 2023
a22f448
fix: parsing of arguments to :Oil command
stevearc Sep 11, 2023
f7a0a90
doc: small documentation tweaks
stevearc Sep 12, 2023
44727a1
doc: fix awkward wording in the toggle_trash action
stevearc Sep 17, 2023
60a3f56
fix: warning on Windows when delete_to_trash = true
stevearc Sep 17, 2023
35cea94
feat: :Oil --trash can open specific trash directories
stevearc Sep 19, 2023
f08e26b
fix: show all trash files in device root
stevearc Oct 12, 2023
ea88400
fix: trash mtime should be sortable
stevearc Oct 12, 2023
0002f90
fix: shorten_path handles optional trailing slash
stevearc Oct 17, 2023
6beec59
refactor: overhaul the UI
stevearc Oct 17, 2023
cdf2d71
fix: keep trash original path vtext from stacking
stevearc Oct 18, 2023
4db7b78
refactor: replace disable_changes with an error filter
stevearc Oct 21, 2023
5267e9e
fix: shorten path names in home directory relative to root
stevearc Oct 21, 2023
f6d9c02
doc: small README format changes
stevearc Oct 22, 2023
f0f86d8
cleanup: remove unnecessary preserve_undo logic
stevearc Oct 22, 2023
13ecc84
test: add a functional test for the freedesktop trash adapter
stevearc Oct 23, 2023
0ebcbf6
test: more functional tests for trash
stevearc Oct 24, 2023
2e70af6
fix: schedule a callback to avoid main loop error
stevearc Oct 24, 2023
97cd378
refactor: clean up mutator logic
stevearc Nov 5, 2023
fc731fe
doc: some comments and type annotations
stevearc Nov 5, 2023
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
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ oil.nvim supports all the usual plugin managers
<summary>Packer</summary>

```lua
require('packer').startup(function()
use {
'stevearc/oil.nvim',
config = function() require('oil').setup() end
}
require("packer").startup(function()
use({
"stevearc/oil.nvim",
config = function()
require("oil").setup()
end,
})
end)
```

Expand All @@ -57,9 +59,9 @@ end)
<summary>Paq</summary>

```lua
require "paq" {
{'stevearc/oil.nvim'};
}
require("paq")({
{ "stevearc/oil.nvim" },
})
```

</details>
Expand Down Expand Up @@ -154,8 +156,6 @@ require("oil").setup({
delete_to_trash = false,
-- Skip the confirmation popup for simple operations
skip_confirm_for_simple_edits = false,
-- Change this to customize the command used when deleting to trash
trash_command = "trash-put",
-- Selecting a new/moved/renamed file or directory will prompt you to save changes first
prompt_save_on_select_new_entry = true,
-- Oil will automatically delete hidden buffers after this delay
Expand Down Expand Up @@ -184,6 +184,7 @@ require("oil").setup({
["gs"] = "actions.change_sort",
["gx"] = "actions.open_external",
["g."] = "actions.toggle_hidden",
["g\\"] = "actions.toggle_trash",
},
-- Set to false to disable all of the above keymaps
use_default_keymaps = true,
Expand Down Expand Up @@ -277,7 +278,7 @@ nvim oil-ssh://[username@]hostname[:port]/[path]

This may look familiar. In fact, this is the same url format that netrw uses.

Note that at the moment the ssh adapter does not support Windows machines, and it requires the server to have a `/bin/sh` binary as well as standard unix commands (`rm`, `mv`, `mkdir`, `chmod`, `cp`, `touch`, `ln`, `echo`).
Note that at the moment the ssh adapter does not support Windows machines, and it requires the server to have a `/bin/sh` binary as well as standard unix commands (`ls`, `rm`, `mv`, `mkdir`, `chmod`, `cp`, `touch`, `ln`, `echo`).

## API

Expand Down
54 changes: 51 additions & 3 deletions doc/oil.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CONTENTS *oil-content
3. Columns |oil-columns|
4. Actions |oil-actions|
5. Highlights |oil-highlights|
6. Trash |oil-trash|

--------------------------------------------------------------------------------
OPTIONS *oil-options*
Expand Down Expand Up @@ -45,8 +46,6 @@ OPTIONS *oil-option
delete_to_trash = false,
-- Skip the confirmation popup for simple operations
skip_confirm_for_simple_edits = false,
-- Change this to customize the command used when deleting to trash
trash_command = "trash-put",
-- Selecting a new/moved/renamed file or directory will prompt you to save changes first
prompt_save_on_select_new_entry = true,
-- Oil will automatically delete hidden buffers after this delay
Expand Down Expand Up @@ -75,6 +74,7 @@ OPTIONS *oil-option
["gs"] = "actions.change_sort",
["gx"] = "actions.open_external",
["g."] = "actions.toggle_hidden",
["g\\"] = "actions.toggle_trash",
},
-- Set to false to disable all of the above keymaps
use_default_keymaps = true,
Expand Down Expand Up @@ -343,6 +343,8 @@ birthtime *column-birthtim
ACTIONS *oil-actions*

These are actions that can be used in the `keymaps` section of config options.
You can also call them directly with
`require("oil.actions").action_name.callback()`

cd *actions.cd*
:cd to the current oil directory
Expand Down Expand Up @@ -408,11 +410,14 @@ tcd *actions.tc
toggle_hidden *actions.toggle_hidden*
Toggle hidden files and directories

toggle_trash *actions.toggle_trash*
Jump to and from the trash for the current directory

--------------------------------------------------------------------------------
HIGHLIGHTS *oil-highlights*

OilDir *hl-OilDir*
Directories in an oil buffer
Directory names in an oil buffer

OilDirIcon *hl-OilDirIcon*
Icon for directories
Expand All @@ -423,6 +428,9 @@ OilSocket *hl-OilSocke
OilLink *hl-OilLink*
Soft links in an oil buffer

OilLinkTarget *hl-OilLinkTarget*
The target of a soft link

OilFile *hl-OilFile*
Normal files in an oil buffer

Expand All @@ -441,5 +449,45 @@ OilCopy *hl-OilCop
OilChange *hl-OilChange*
Change action in the oil preview window

OilRestore *hl-OilRestore*
Restore (from the trash) action in the oil preview window

OilPurge *hl-OilPurge*
Purge (Permanently delete a file from trash) action in the oil preview
window

OilTrash *hl-OilTrash*
Trash (delete a file to trash) action in the oil preview window

OilTrashSourcePath *hl-OilTrashSourcePath*
Virtual text that shows the original path of file in the trash

--------------------------------------------------------------------------------
TRASH *oil-trash*


Oil has built-in support for using the system trash. When
`delete_to_trash = true`, any deleted files will be sent to the trash instead
of being permanently deleted. You can browse the trash for a directory using
the `toggle_trash` action (bound to `g\` by default). You can view all files
in the trash with `:Oil --trash /`.

To restore files, simply delete them from the trash and put them in the desired
destination, the same as any other file operation. If you delete files from the
trash they will be permanently deleted (purged).

Linux:
Oil supports the FreeDesktop trash specification.
https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
All features should work.

Mac:
Oil has limited support for MacOS due to the proprietary nature of the
implementation. The trash bin can only be viewed as a single dir
(instead of being able to see files that were trashed from a directory).

Windows:
Oil does not yet support the Windows trash. PRs are welcome!

================================================================================
vim:tw=80:ts=2:ft=help:norl:syntax=help:
32 changes: 32 additions & 0 deletions lua/oil/actions.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
local oil = require("oil")
local util = require("oil.util")

-- TODO remove after https://github.com/folke/neodev.nvim/pull/163 lands
---@diagnostic disable: inject-field

local M = {}

M.show_help = {
Expand Down Expand Up @@ -302,6 +305,35 @@ M.change_sort = {
end,
}

M.toggle_trash = {
desc = "Jump to and from the trash for the current directory",
callback = function()
local fs = require("oil.fs")
local bufname = vim.api.nvim_buf_get_name(0)
local scheme, path = util.parse_url(bufname)
local bufnr = vim.api.nvim_get_current_buf()
local url
if scheme == "oil://" then
url = "oil-trash://" .. path
elseif scheme == "oil-trash://" then
url = "oil://" .. path
-- The non-linux trash implementations don't support per-directory trash,
-- so jump back to the stored source buffer.
if not fs.is_linux then
local src_bufnr = vim.b.oil_trash_toggle_src
if src_bufnr and vim.api.nvim_buf_is_valid(src_bufnr) then
url = vim.api.nvim_buf_get_name(src_bufnr)
end
end
else
vim.notify("No trash found for buffer", vim.log.levels.WARN)
return
end
vim.cmd.edit({ args = { url } })
vim.b.oil_trash_toggle_src = bufnr
end,
}

---List actions for documentation generation
---@private
M._get_actions = function()
Expand Down
32 changes: 25 additions & 7 deletions lua/oil/adapters/files.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ local permissions = require("oil.adapters.files.permissions")
local trash = require("oil.adapters.files.trash")
local util = require("oil.util")
local uv = vim.uv or vim.loop

local M = {}

local FIELD_NAME = constants.FIELD_NAME
Expand Down Expand Up @@ -147,7 +148,11 @@ if not fs.is_windows then
}
end

local current_year = vim.fn.strftime("%Y")
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] = {
Expand Down Expand Up @@ -436,7 +441,12 @@ M.render_action = function(action)
elseif action.type == "delete" then
local _, path = util.parse_url(action.url)
assert(path)
return string.format("DELETE %s", M.to_short_os_path(path, action.entry_type))
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)
stevearc marked this conversation as resolved.
Show resolved Hide resolved
else
return string.format("DELETE %s", short_path)
end
elseif action.type == "move" or action.type == "copy" then
local dest_adapter = config.get_adapter_by_scheme(action.dest_url)
if dest_adapter == M then
Expand All @@ -451,7 +461,7 @@ M.render_action = function(action)
M.to_short_os_path(dest_path, action.entry_type)
)
else
-- We should never hit this because we don't implement supported_adapters_for_copy
-- 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
Expand Down Expand Up @@ -494,7 +504,15 @@ M.perform_action = function(action, cb)
assert(path)
path = fs.posix_to_os_path(path)
if config.delete_to_trash then
trash.recursive_delete(path, cb)
if config.trash_command then
vim.notify_once(
"Oil now has native support for trash. Remove the `trash_command` from your config to try it out!",
vim.log.levels.WARN
)
trash.recursive_delete(path, cb)
else
require("oil.adapters.trash").delete_to_trash(path, cb)
end
else
fs.recursive_delete(action.entry_type, path, cb)
end
Expand All @@ -507,9 +525,9 @@ M.perform_action = function(action, cb)
assert(dest_path)
src_path = fs.posix_to_os_path(src_path)
dest_path = fs.posix_to_os_path(dest_path)
fs.recursive_move(action.entry_type, src_path, dest_path, vim.schedule_wrap(cb))
fs.recursive_move(action.entry_type, src_path, dest_path, cb)
else
-- We should never hit this because we don't implement supported_adapters_for_copy
-- 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
Expand All @@ -523,7 +541,7 @@ M.perform_action = function(action, cb)
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_adapters_for_copy
-- 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
Expand Down
2 changes: 1 addition & 1 deletion lua/oil/adapters/ssh.lua
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ M.perform_action = function(action, cb)
end
end

M.supported_adapters_for_copy = { files = true }
M.supported_cross_adapter_actions = { files = "copy" }

---@param bufnr integer
M.read_file = function(bufnr)
Expand Down
9 changes: 9 additions & 0 deletions lua/oil/adapters/trash.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
local fs = require("oil.fs")

if fs.is_mac then
return require("oil.adapters.trash.mac")
elseif fs.is_windows then
error("Trash is not implemented yet on Windows")
else
return require("oil.adapters.trash.freedesktop")
end
Loading