Trash File from Emacs with Put-Back Enabled on macOS

I’ve enabled using the macOS system trash in Emacs to feel safer experimenting with dired and other file manipulation functions in Emacs.

This enables using the trash by default:

(setq delete-by-moving-to-trash t)

When this is enabled, move-file-to-trash is used to delete files. The manual reveals what’s affected, but only the function API docs from within Emacs tell the whole story (and are super hard to search online for whatever reason):

If the function system-move-file-to-trash is defined, call it with FILENAME as an argument.

Otherwise, if trash-directory is non-nil, move FILENAME to that directory.

Otherwise, trash FILENAME using the freedesktop.org conventions, like the GNOME, KDE and XFCE desktop environments. Emacs moves files only to “home trash”, ignoring per-volume trashcans.

So by default, the delete-by-moving-to-trash variable enablement does nothing.

Set the user-default trash path to make deletion move a file to trash:

(setq trash-directory "~/.Trash")  ;; fallback for `move-file-to-trash'

With this, all files are moved into the trash, but you cannot use the macOS ‘Put Back’ functionality. I expected an extended file attribute to control this, but it’s something else, apparently. Reading the attributes of files trashed by Finder doesn’t reveal anything.

But there’s a command-line utility called trash that can be told to use Finder’s functionality to move a file to the trash and enable put-back.

Successful trashing of a file, see the message in the minibuffer

So if we revisit the function docs, it says trash-directory is just a fall-back. The first attempt is made using the function system-move-file-to-trash if it exists. If we declare that function, we can use it to use the trash CLI app; and for good measure, we’ll limit it to macOS:

(when (memq window-system '(mac ns))
  (defun system-move-file-to-trash (path)
    "Moves file at PATH to the macOS Trash according to `move-file-to-trash' convention.

Relies on the command-line utility 'trash' to be installed.
Get it from:  <http://hasseg.org/trash/>"
    (shell-command (concat "trash -vF \"" path "\""
                           "| sed -e 's/^/Trashed: /'")
                   nil ;; Name of output buffer
                   "*Trash Error Buffer*")))

This just forwards the file path to the trash CLI utility and then prepends a string to format the output; trash -F uses the Finder trash functionality; trash -v returns the path name of the trashed file on success; and with the sed replacement, we get "Trashed: /path/to/file.txt". This output is printed in the minibuffer after deletion as you see in the screenshot.

References: