package 分享 · 使用项目相对路径作为 buffer-name

日常使用 emacs 时,我习惯开大量的 buffer,并用 C-x b 进行切换。这些文件来自多个项目/目录,并且有很多文件会重名。例如我进行 rust 项目开发时,就可能会打开多个 crates 的 lib.rs

虽然 Emacs 自带的 buffer-name 有一套针对同名文件的注释机制,但是这个机制只会利用上层文件夹的不同名字加标记,很多时候我依然找不到想要的文件。我觉得更好的机制是直接使用相对项目根目录的路径作为项目名,例如 ~/github/rust-project/crates/xxx/lib.rs 使用 rust-project/crates/xxx/lib.rs

电报群的群友推荐了这个 package,我试了一下非常好用,所以来分享一下:

配置:

(use-package buffer-name-relative
  :straight (:host codeberg :repo "ideasman42/emacs-buffer-name-relative")
  :hook (after-init . buffer-name-relative-mode)
  :config
  (setq buffer-name-relative-prefix '("" . "/")))
3 个赞

不知道这个能不能满足你? 它是 built-in 的:

;; 多个同名 buffer 时的设置
(use-package uniquify
  :custom
  (uniquify-buffer-name-style 'reverse)
  (uniquify-separator " • ")
  (uniquify-after-kill-buffer-p t)
  (uniquify-ignore-buffers-re "^\\*"))

我希望没有同名的情况下也进行重命名🤣 这样方便和 consult 配合。因为 consult 中默认会在 C-x b 里面展示 recentf 的列表,所以就算我没有打开同名的文件,但是已经打开的 buffer 也有可能会历史记录里面的某个文件同名

consult+marginlia 完全能看出来吧?

我想盲选,还要仔细分辨的话有点麻烦

可以像其它编辑器(vsc,notepad+)一样把文件的根目录显示在buffer最上方,我显示在header-line,切换buffer用counsel-switch-buffer`

如果只是想用 consult 过滤的时候可以输入路径的话,可以试试这个 advice:

(defun my-project-root ()
  (when-let ((project (project-current nil)))
    (if (fboundp #'project-root)
        (project-root project)
      (car (project-roots project)))))

(define-advice consult--buffer-pair (:around (_ buffer) show-path)
  "Also show path for file buffers so the user can filter them by path."
  (let ((dir (or (my-project-root) default-directory)))
    (if-let ((path (buffer-file-name buffer)))
        (progn (when (file-in-directory-p path dir)
                 (setq path (file-relative-name path dir)))
               (cons path buffer))
      (cons (buffer-name buffer) buffer))))

我没有修改 buffer name 的原因是我的 tab-bar 里面要用它们作为 tab 的名字。

3 个赞

不错的包,代码写得也比较整洁,除了每个函数头上的 (declare (important-return-value nil)) 不知道是什么作用。目前的个人配置:

(use-package buffer-name-relative
  :diminish
  :commands buffer-name-relative-mode
  :config
  (setq buffer-name-relative-prefix '("<" . "> ")
        buffer-name-relative-fallback 'default)

  (defun buffer-name-relative-root-path-from-project (filepath)
    "Return the PROJECT directory from FILEPATH or nil."
    (let ((result nil))
      (when (fboundp 'project-root)
        (let ((dir (if (file-directory-p filepath)
                       (directory-file-name filepath)
                     (file-name-directory filepath))))
          (when dir
            (condition-case-unless-debug err
                (setq result (project-root (project-current nil dir)))
              (error (message "Error finding PROJECT root name: %s" err))))))
      result))
  (setq buffer-name-relative-root-functions '(buffer-name-relative-root-path-from-project)))
1 个赞

用了一段时间,感觉 buffer-name-relative 很容易导致我的 buffer-name 过长,在 modeline 中的显示效果很不好 :joy:, 所以目前弃用了。现在用的是楼上推荐的 consult 过滤 advice。

我也遇到了这个问题😂