Emacsでファイルを削除すると、デフォルトでは完全削除になります。
一方、私はCLIでgtrashを使ってTrashに入れる運用をしています。そのため、Emacsから削除した場合の挙動も揃えたくなりました。
ここでは、Emacs 30.1以降の仕様を前提に、Emacsからの削除でもgtrashを使うための設定をまとめます。
Emacsの削除とTrashの関係 #
Emacsでは、ファイル削除時の挙動は設定によって変わります。
delete-by-moving-to-trash変数がnon-nilの場合、Emacsはファイルを完全削除せず、Trashに移動しようとします。
このときEmacsは内部でmove-file-to-trashを呼び出し、実際にどの方法でTrashに移動するかを決定します。
system-move-file-to-trashを定義してgtrashを使う
#
Emacsでは、Trashへの移動方法を環境ごとに差し替えるための関数が用意されています。
それがsystem-move-file-to-trashです。
delete-by-moving-to-trashが有効な場合、Emacsは削除処理の中でmove-file-to-trashを呼び出します。
この関数は、Trashの実装として次の方針で動作します。
system-move-file-to-trashが定義されていれば、それを使用する- 定義されていなければ、Emacs標準のTrash処理を行う
つまりsystem-move-file-to-trashを定義することで、Emacsの削除フローは変更せずTrashの実装だけを差し替えることが可能です。
gtrashを使う場合、この関数をgtrash putを呼び出す処理で実装することで、Emacsの削除操作をgtrashに揃えられます。
TRAMPでのgtrashの使用 #
Emacsでは本来、リモート(TRAMP)ファイルはTrashを使わず削除されます。
TRAMP経由のファイル削除でgtrashを使うと意図しない場所(リモートではなくローカル等)にTrashされる可能性があるため、リモートではgtrashを使わない方針にします。
remote-file-name-inhibit-delete-by-moving-to-trashについて
#
Emacs 30.1以降では、リモート(TRAMP)ファイルの削除挙動を制御するためにremote-file-name-inhibit-delete-by-moving-to-trashという変数が追加されています。
この変数をnon-nilにすると、リモートファイルに対しては、delete-by-moving-to-trashの設定に関わらずEmacsのデフォルト挙動どおり完全削除されます。
そのため、この変数をnon-nilに設定することで、ローカルとリモートでの分岐処理をsystem-move-file-to-trashに書く必要がありません。
設定 #
Trashのポリシー設定 #
;; Move deleted files to trash (local only)
(setopt delete-by-moving-to-trash t
remote-file-name-inhibit-delete-by-moving-to-trash t)上記の設定で以下を実現します。
- ローカルファイルはTrashに移動
- リモート(TRAMP)ファイルは完全削除
system-move-file-to-trashの定義
#
TRAMP判定などは行わず、ローカル専用の関数として使います。
(when (executable-find "gtrash")
(defun system-move-file-to-trash (filename)
"Move FILENAME to trash using `gtrash put`."
(let ((exit-code
(call-process "gtrash" nil nil nil "put" filename)))
(unless (zerop exit-code)
(error "gtrash put failed for %s" filename))
t)))実際の動作 #
これで、以下のような動作になります。
| 操作対象 | 挙動 |
|---|---|
| ローカルのfile | gtrashにて処理 |
| ローカルのdirectory | gtrashにて処理 |
| TRAMPのfile | 完全削除(Emacsのデフォルト) |
| TRAMPのdirectory | 完全削除(Emacsのデフォルト) |
| Dired | 対象がローカルかTRAMPかに応じて上記と同じ挙動 |