如何在emacs中获取最近关闭的文件列表?

13
有时我手痒误删一些我本想隐藏起来的缓冲区。问题是,我使用tramp从多台机器上编辑文件,这些文件名又长又复杂,总之我不太擅长找到我需要的文件。因此,我希望emacs能跟踪我刚刚关闭的文件,以便我可以轻松地重新打开它们(最好通过ido提示方式)。
以下是我目前的尝试,但并未成功:
(defvar closed-files '())

(defun track-closed-file ()
  (message buffer-file-name)
  (and buffer-file-name
       (cons  buffer-file-name closed-files)))

(defun last-closed-files ()
  (interactive)
  (find-file (ido-completing-read "Last closed: " closed-files)))

(add-hook 'kill-buffer-hook 'track-closed-file)

我不太擅长elisp,在定义变量和添加单元格时可能会出错...

[我知道recentf,但它只是跟踪已打开的文件,而不是已关闭的文件。]

5个回答

16

我刚刚测试了一下,使用列表和add-to-list可以实现,并且还可以消除重复项。这是否符合您的需求?

(defvar closed-files (list))

(defun track-closed-file ()
  (message buffer-file-name)
  (and buffer-file-name
       (add-to-list 'closed-files buffer-file-name)))

(defun last-closed-files ()
  (interactive)
  (find-file (ido-completing-read "Last closed: " closed-files)))

(add-hook 'kill-buffer-hook 'track-closed-file)

更新

我很喜欢这个功能,并已将其放置在我的emacs配置中。您也可以从我所做的更改中受益。

此添加功能将会将最近关闭的文件推送到列表的开头,即使它们以前已经被关闭(并已存在于closed-files列表中)。

(defun track-closed-file ()
  (and buffer-file-name
       (message buffer-file-name)
       (or (delete buffer-file-name closed-files) t)
       (add-to-list 'closed-files buffer-file-name)))

您最初的问题是cons返回新列表,而不是操作输入列表:
(setq mylist '(2 3))
 => (2 3)
(cons 1 mylist)
 => (1 2 3)
mylist
 => (2 3)

在这种情况下,您需要执行以下操作:
(setq mylist (cons 1 mylist))
  => (1 2 3)
mylist
  => (1 2 3)

它有效。学习Lisp的基础知识是新年决心,这是肯定的! - polyglot
这真的很方便。我也把它添加到了我的.emacs中。谢谢。 - seth
非常好!有一个评论 - 你正在同时使用 andor,但是你只需要 when。如果你将 and 替换为 when,你可以省略 or。例如:(when buffer-file-name (message ...) (delete buffer-file-name ...) ...) - Tyler
buffer-file-name 包含 % 时,(message buffer-file-name) 会导致一个 bug。例如,尝试打开一个名为 tmp%.txt 的文件,然后将其关闭。这个消息实际上并不是必要的,因此删除它应该没问题。 - Tyler

5

你尝试使用recentf了吗?Emacs应该已经提供了它。

我最初是通过XSteve的Emacs高级用户技巧看到它的,他建议将其绑定到F12,并提供了一个交互界面:

;;recentf
(require 'recentf)
(recentf-mode 1)
(setq recentf-max-saved-items 500)
(setq recentf-max-menu-items 60)
(global-set-key [(meta f12)] 'recentf-open-files)

(defun xsteve-ido-choose-from-recentf ()
  "Use ido to select a recently opened file from the `recentf-list'"
  (interactive)
  (let ((home (expand-file-name (getenv "HOME"))))
    (find-file
     (ido-completing-read "Recentf open: "
                          (mapcar (lambda (path)
                                    (replace-regexp-in-string home "~" path))
                                  recentf-list)
                          nil t))))

[更新]: 哎呀,刚看到你有关recentf的说明。确实,它是针对所有打开的文件的,因此也包括当前打开的缓冲区中的文件。由于我只在尝试查找最近关闭的文件时才访问它,所以从未考虑过这一点。不过,也许从输出中筛选打开的文件比重新发明整个轮子更容易?

对于那些感兴趣的人,你可以使用钩子: (add-hook 'kill-buffer-hook 'recentf-track-opened-file) ;; 添加文件 (add-hook 'kill-buffer-hook 'recentf-track-closed-file) ;; 然后根据文件类型可能会删除 这将包括所有最近打开、保存和关闭的文件在同一个列表中,而不仅仅是关闭的。 - Nicholas Harrison


0
你有没有考虑将“C-x k”重新绑定到bury-buffer而不是kill-buffer?(如果需要,你可以使用类似于'midnight.el'的工具来定期清理缓冲区列表。)

哦,天啊。通常情况下,我会打开大约50个缓冲区……但总有另一种方法。 - Michael Paulukonis
我将bury-buffer重新绑定到shift-F4,将kill-buffer重新绑定到ctrl-F4,有时候会感到困惑 :) 但是对于我打开的缓冲区,我非常注重清洁,因此不杀死我暂时打开进行检查的无数日志文件会让我感到恐惧。 - polyglot
我个人只是让缓冲区关闭,然后使用OtherMichael提到的ido/recentf集成来重新打开它们(如果需要的话)。如果你正在快速打开和关闭文件,就像你所建议的那样,那么最近打开的文件和最近关闭的文件之间没有太大的区别。 - sanityinc

0

这个美好的功能也可作为“anything”包的一部分使用。强烈建议尝试。

但是,“anything”有一个名为“helm”的新版本,似乎没有这个功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接