如何让Emacs的「文件/打开最近文件」菜单忽略当前已打开的文件?
如何让Emacs的「文件/打开最近文件」菜单忽略当前已打开的文件?
我完全懂你的痛点——「打开最近文件」菜单里混着一堆已经在Emacs里打开的文件,点了只是切换缓冲区,根本达不到“打开新文件”的目的;更关键的是你不想改动recentf-list本身,毕竟关掉那些已打开的文件后,还希望它们能重新出现在最近列表里,也不想破坏持久化的记录,这个顾虑太合理了!
咱们的核心思路是:不修改原始的recentf-list,只在生成菜单的时候临时过滤掉当前已打开的文件,这样既满足了菜单的需求,又不会丢失任何历史记录。
下面是给你准备的Elisp代码,我尽量写清楚注释,方便你理解:
(defun my-recentf-open-menu () "自定义的「打开最近文件」菜单,自动排除当前已打开的文件" (interactive) ;; 第一步:收集当前所有已打开文件的绝对路径 ;; 遍历所有缓冲区,提取有对应文件的缓冲区路径,转成绝对路径去重 (let ((open-files (delete-dups (mapcar #'(lambda (buf) (when (buffer-file-name buf) (expand-file-name (buffer-file-name buf)))) (buffer-list)))) ;; 第二步:从recentf-list里过滤掉已打开的文件 filtered-recentf (seq-filter #'(lambda (file) ;; 用绝对路径对比,避免相对路径/绝对路径格式不一致导致过滤失败 (not (member (expand-file-name file) open-files))) recentf-list)) ;; 第三步:调用Emacs内置的菜单生成函数,用过滤后的列表创建菜单 (if filtered-recentf (recentf-open--menu filtered-recentf "Recent Files (Excluding Open)") (message "没有可用的最近文件(已排除当前打开的)")))) ;; 替换原来「文件」菜单里的「打开最近文件」绑定 (global-set-key [menu-bar file open-recent] '("Open Recent" . my-recentf-open-menu))
代码说明:
- 收集已打开文件:
buffer-list能拿到当前所有缓冲区,buffer-file-name提取缓冲区对应的文件路径,expand-file-name统一转成绝对路径,避免因为路径格式不同(比如相对路径和绝对路径)导致过滤失效,delete-dups则去掉重复的路径。 - 过滤最近文件列表:用
seq-filter遍历recentf-list,把已经在open-files里的项剔除掉。 - 生成菜单:调用
recentf-open--menu(这是Emacs内置的生成最近文件菜单的函数),传入过滤后的列表和菜单标题,这样展示的就是纯未打开的最近文件了。
可选调整:
如果你不想替换原来的菜单,而是想新增一个「打开最近文件(排除已打开)」的菜单项,可以把最后一段绑定代码改成这样:
;; 在原「打开最近文件」菜单后面新增一个自定义项 (define-key-after global-map [menu-bar file open-recent-excluding] '("Open Recent (Excluding Open)" . my-recentf-open-menu) 'open-recent)
这样做的好处是:
- 原始的
recentf-list和~/.emacs.d/recentf持久化文件完全不受影响,关掉已打开的文件后,它会自动回到下一次的菜单里 - 菜单里只会显示真正没打开的最近文件,完全符合你的需求
备注:内容来源于stack exchange,提问作者Bruno
相关产品推荐
相关产品推荐

