首页 > 解决方案 > 如何控制 Emacs 将备份文件动态生成到哪个目录?

问题描述

我看过这篇文章如何控制 Emacs 如何制作备份文件? 还有一些类似的帖子显示了非常相似的解决方案。我很清楚这种方法。但它并没有完全按照我的意愿去做。我希望我要备份的每个文件都有自己的个性化备份目录。

例如,假设我在当前目录中有以下文件,/Users/me/project_a/

apple.txt
banana.txt
coconut.txt

当我编辑这些文件时,我希望他们将备份存储在目录中,如下所示:

/Users/me/project_a/.backups/apple.txt/
/Users/me/project_a/.backups/banana.txt/
/Users/me/project_a/.backups/coconut.txt/

如果我在另一个项目目录中,比如/Users/me/project_b/文件

needle.doc
thread.doc
thimble.doc

然后,它们各自的备份应位于

/Users/me/project_b/.backups/needle.doc/
/Users/me/project_b/.backups/thread.doc/
/Users/me/project_b/.backups/thimble.doc/

是的,我使用正在备份的文件的名称作为保存它的目录的路径名的一部分。因此,如果我有三个以前的版本thimble.doc,备份的完整路径名将是:

/Users/me/project_b/.backups/thimble.doc/thimble.doc.~1~
/Users/me/project_b/.backups/thimble.doc/thimble.doc.~2~
/Users/me/project_b/.backups/thimble.doc/thimble.doc.~3~

我有一个解决方法来实现这一点(见下文)。理想情况下,我会将备份命名为:

/Users/me/project_b/.backups/thimble.doc/bak.~1~
/Users/me/project_b/.backups/thimble.doc/bak.~2~
/Users/me/project_b/.backups/thimble.doc/bak.~3~

我还没想好怎么去那里。(有什么建议么?)

以下是我如何使用.dir-locals.el具有以下用于保存.txt.tex文件的代码的文件来完成不太理想的版本。

  (let (a b)
    (dolist (ae-fh (directory-files-recursively "." "\\.\\(txt\\|tex\\)$"))
      (setq a (file-name-nondirectory ae-fh))
      (setq a (replace-regexp-in-string "\\." "\\\\." a))
      (setq b (concat "./.backups/" (file-name-nondirectory ae-fh)))
      (add-to-list 'backup-directory-alist (cons a b))             
      ))

我已经创建了backup-directory-alist一个缓冲区局部变量。

这完成了我想要的,但我不太喜欢这种方法。我想完全避免使用.dir-locals.el它来解决这个问题。而且,我想避免将backup-directory-alist. 如果有一个钩子我可以应用到备份过程中会很好地通知 emacs 它应该如何命名备份文件。

有谁知道如何做到这一点或知道在哪里指向我?我考虑过尝试重新定义make-backup-file-name-function,但我并不完全理解我在用 elisp 做什么,现在我有需要处理的项目。

人家能告诉我什么?

标签: backup

解决方案


我有一个部分解决方案。

  • 它避免了.dir-locals.el我想要的使用。
  • 它在某种程度上也像我想要的那样动态地创建了路径。
  • 它仍然使用backup-directory-alist

我将以下内容添加到我的 emacs 初始化文件中:

 (add-hook 'after-change-major-mode-hook 
           '(lambda ()
              (let (a b)
                (if (stringp (buffer-file-name))
                (progn
                  (setq a (file-name-nondirectory (buffer-file-name)))
                  (setq a (replace-regexp-in-string "\\." "\\\\." a))
                  (setq b (concat "./.backups/" (file-name-nondirectory (buffer-file-name))))
                  (add-to-list 'backup-directory-alist (cons a b))             
                      )
                  )
                )))

我对这个钩子不太了解。所以,我不确定这是否会一直有效。而且,我可能应该考虑是否可能存在这种约定确实不受欢迎的文件。

在没有基础文件的缓冲区的情况下,这(stringp (buffer-file-name))是最低限度的必要条件:例如*scratch*甚至迷你缓冲区。

我仍然对其他人可能提出的解决方案感兴趣。理想情况下,解决方案更像

/Users/me/project_b/.backups/thimble.doc/bak.~1~
/Users/me/project_b/.backups/thimble.doc/bak.~2~
/Users/me/project_b/.backups/thimble.doc/bak.~3~

/Users/me/project_b/.backups/thimble.doc/thimble.doc.~1~
/Users/me/project_b/.backups/thimble.doc/thimble.doc.~2~
/Users/me/project_b/.backups/thimble.doc/thimble.doc.~3~

更新:坚持会让你有地方!!!!

我终于在谷歌上搜索了:“emacs我如何重新定义make-backup-file-name”。我发现了这种方法的描述,我适应了我的情况。也就是说,我做了以下事情:

(defun z:backup:truncate.backup.name (file)
  (concat (file-name-directory file) "bak"))
(advice-add 'make-backup-file-name-1 :filter-return #'z:backup:truncate.backup.name)

我不完全确定一切是关于什么的。

  • 我不知道#'语法是做什么的。
  • 我不确定是什么:filter-return,虽然我可以猜到。

我应该指出,我仍然需要 mae add-hookfor 'after-change-major-mode-hook。没有它,我会得到错误。显然,我只是不能将建议功能写为

(defun z:backup:truncate.backup.name (file)
  (concat (file-name-directory file) (file-name-nondirectory) "/bak"))

我试了一下,得到一个关于无法备份的错误。而且我认为这样做的原因backup-directory-alist是用于确定目录路径。我对这里的一些调整有一些想法。但这就是目前的情况。

更新:不再需要我add-hookafter-change-major-mode-hook

我已经解决了备份目录 alist 不一定设置为正确目录的问题。这是我的最终形式z:backup:truncate.backup.name

(defun z:backup:truncate.backup.name ()
  (let* (
         (dir  (file-name-directory (buffer-file-name)))
         (fh   (file-name-nondirectory (buffer-file-name)))
         (qdir (concat dir ".backups/" fh))
          )
    (if (not (file-directory-p qdir))
        (progn
          (if (file-directory-p dir)
              (progn
                (make-directory qdir)
                ))))
  (concat qdir "/bak")))

所以现在更多的不得不调整backup-directory-alist。我已经完成了我想要的一切。是的。


推荐阅读