Support transforming the dirname used by uniquify

By transforming the buffer's directory name, we can add
additional information to use during uniquifying.  A basic
one: uniquifying buffer names based on the project name.
* lisp/progmodes/project.el (project-uniquify-dirname-transform): Add.
* lisp/uniquify.el (uniquify-dirname-transform-default)
(uniquify-dirname-transform): Add.  (Bug#62621)
(uniquify-rationalize-file-buffer-names, uniquify-buffer-file-name):
Use 'uniquify-dirname-transform'.
* test/lisp/uniquify-tests.el (uniquify-home)
(uniquify-project-transform): Add tests.
This commit is contained in:
Spencer Baugh 2023-07-09 22:21:03 -04:00 committed by Eli Zaretskii
parent 4ef9cc5a5d
commit 2aec67f4de
3 changed files with 82 additions and 5 deletions

View file

@ -1887,5 +1887,22 @@ to directory DIR."
(let ((project-current-directory-override dir))
(call-interactively command))))
;;;###autoload
(defun project-uniquify-dirname-transform (dirname)
"Include `project-name' in DIRNAME if in a project.
If you set `uniquify-dirname-transform' to this function,
slash-separated components from `project-name' will be added to
the buffer's name when buffers from two different projects would
otherwise have the same name."
(if-let (proj (project-current nil dirname))
(let ((root (project-root proj)))
(expand-file-name
(file-name-concat
(file-name-directory root)
(project-name proj)
(file-relative-name dirname root))))
dirname))
(provide 'project)
;;; project.el ends here

View file

@ -168,6 +168,31 @@ This can be handy when you have deep parallel hierarchies."
That means that when `buffer-file-name' is set to nil, `list-buffers-directory'
contains the name of the directory which the buffer is visiting.")
(defcustom uniquify-dirname-transform #'identity
"Function to transform buffer's directory for uniquifying its name.
If `uniquify-buffer-name-style' is non-nil and a buffer's name
would be the same as some other buffer, then components from the
buffer's directory name are added to the buffer's name until the
buffer's name is unique.
This function is used to transform the buffer's directory name
before the uniquifying process, allowing the unique buffer name
to include components from other sources. The default is
`identity', so only the buffer's directory name is used for
uniquifying. This function is called with the buffer's directory
name and should return a file name (which does not need to
actually exist in the filesystem) to use components from.
To include components from `project-name', set this variable to
`project-uniquify-dirname-transform'."
:type '(choice (function-item :tag "Don't change the dirname" identity)
(function-item :tag "Include project name in dirname"
#'project-uniquify-dirname-transform)
function)
:version "30.1"
:group 'uniquify)
;;; Utilities
;; uniquify-fix-list data structure
@ -209,7 +234,8 @@ this rationalization."
;; this buffer.
(with-current-buffer newbuf (setq uniquify-managed nil))
(when dirname
(setq dirname (expand-file-name (directory-file-name dirname)))
(setq dirname (funcall uniquify-dirname-transform
(expand-file-name (directory-file-name dirname))))
(let ((fix-list (list (uniquify-make-item base dirname newbuf
nil)))
items)
@ -268,10 +294,11 @@ in `uniquify-list-buffers-directory-modes', otherwise returns nil."
(if (memq major-mode uniquify-list-buffers-directory-modes)
list-buffers-directory))))
(when filename
(directory-file-name
(file-name-directory
(expand-file-name
(directory-file-name filename))))))))
(funcall uniquify-dirname-transform
(directory-file-name
(file-name-directory
(expand-file-name
(directory-file-name filename)))))))))
(defun uniquify-rerationalize-w/o-cb (fix-list)
"Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'."

View file

@ -88,6 +88,21 @@
'("a/dir/" "b/dir/")))
(mapc #'kill-buffer bufs)))))
(ert-deftest uniquify-home ()
"uniquify works, albeit confusingly, in the presence of directories named \"~\""
(let (bufs)
(save-excursion
(push (find-file-noselect "~") bufs)
(push (find-file-noselect "./~") bufs)
(should (equal (mapcar #'buffer-name bufs)
'("~<test>" "~<>")))
(push (find-file-noselect "~/foo") bufs)
(push (find-file-noselect "./~/foo") bufs)
(should (equal (mapcar #'buffer-name bufs)
'("foo<~>" "foo</nonexistent>" "~<test>" "~<>")))
(while bufs
(kill-buffer (pop bufs))))))
(ert-deftest uniquify-rename-to-dir ()
"Giving a buffer a name which matches a directory doesn't rename the buffer"
(let ((uniquify-buffer-name-style 'forward)
@ -125,5 +140,23 @@ uniquify-trailing-separator-p is ignored"
(should (equal (buffer-name) "| foo"))
(kill-buffer)))
(require 'project)
(ert-deftest uniquify-project-transform ()
"`project-uniquify-dirname-transform' works"
(let ((uniquify-dirname-transform #'project-uniquify-dirname-transform)
(project-vc-name "foo1/bar")
bufs)
(save-excursion
(should (file-exists-p "../README"))
(push (find-file-noselect "../README") bufs)
(push (find-file-noselect "other/README") bufs)
(should (equal (mapcar #'buffer-name bufs)
'("README<other>" "README<bar>")))
(push (find-file-noselect "foo2/bar/README") bufs)
(should (equal (mapcar #'buffer-name bufs)
'("README<foo2/bar>" "README<other>" "README<foo1/bar>")))
(while bufs
(kill-buffer (pop bufs))))))
(provide 'uniquify-tests)
;;; uniquify-tests.el ends here