-;;; uniquify.el --- unique buffer names dependent on file name
+;;; uniquify.el --- unique buffer names dependent on file name -*- lexical-binding: t -*-
-;; Copyright (C) 1989, 1995, 1996, 1997, 2001, 2002, 2003,
-;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 1989, 1995-1997, 2001-2013 Free Software Foundation,
+;; Inc.
;; Author: Dick King <king@reasoning.com>
;; Maintainer: FSF
;; Keywords: files
;; Created: 15 May 86
+;; Package: emacs
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
;;; User-visible variables
(defgroup uniquify nil
"Unique buffer names dependent on file name."
- :group 'applications)
+ :group 'files)
(defcustom uniquify-buffer-name-style nil
- "*If non-nil, buffer names are uniquified with parts of directory name.
+ "If non-nil, buffer names are uniquified with parts of directory name.
The value determines the buffer name style and is one of `forward',
`reverse', `post-forward', or `post-forward-angle-brackets'.
For example, files `/foo/bar/mumble/name' and `/baz/quux/mumble/name'
reverse name\\mumble\\bar name\\mumble\\quux
post-forward name|bar/mumble name|quux/mumble
post-forward-angle-brackets name<bar/mumble> name<quux/mumble>
- nil name name<2>"
+ nil name name<2>
+Of course, the \"mumble\" part may be stripped as well, depending on the setting
+of `uniquify-strip-common-suffix'."
:type '(radio (const forward)
(const reverse)
(const post-forward)
:group 'uniquify)
(defcustom uniquify-ask-about-buffer-names-p nil
- "*If non-nil, permit user to choose names for buffers with same base file.
+ "If non-nil, permit user to choose names for buffers with same base file.
If the user chooses to name a buffer, uniquification is preempted and no
other buffer names are changed."
:type 'boolean
;; The default value matches certain Gnus buffers.
(defcustom uniquify-ignore-buffers-re nil
- "*Regular expression matching buffer names that should not be uniquified.
+ "Regular expression matching buffer names that should not be uniquified.
For instance, set this to \"^draft-[0-9]+$\" to avoid having uniquify rename
draft buffers even if `uniquify-after-kill-buffer-p' is non-nil and the
visited file name isn't the same as that of the buffer."
:group 'uniquify)
(defcustom uniquify-min-dir-content 0
- "*Minimum number of directory name components included in buffer name."
+ "Minimum number of directory name components included in buffer name."
:type 'integer
:group 'uniquify)
(defcustom uniquify-separator nil
- "*String separator for buffer name components.
+ "String separator for buffer name components.
When `uniquify-buffer-name-style' is `post-forward', separates
base file name from directory part in buffer names (default \"|\").
When `uniquify-buffer-name-style' is `reverse', separates all
:group 'uniquify)
(defcustom uniquify-trailing-separator-p nil
- "*If non-nil, add a file name separator to dired buffer names.
+ "If non-nil, add a file name separator to dired buffer names.
If `uniquify-buffer-name-style' is `forward', add the separator at the end;
if it is `reverse', add the separator at the beginning; otherwise, this
variable is ignored."
:type 'boolean
:group 'uniquify)
-(defvar uniquify-list-buffers-directory-modes '(dired-mode cvs-mode)
+(defvar uniquify-list-buffers-directory-modes '(dired-mode cvs-mode vc-dir-mode)
"List of modes for which uniquify should obey `list-buffers-directory'.
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.")
;;; Utilities
;; uniquify-fix-list data structure
-(defstruct (uniquify-item
+(cl-defstruct (uniquify-item
(:constructor nil) (:copier nil)
(:constructor uniquify-make-item
(base dirname buffer &optional proposed)))
;; Internal variables used free
(defvar uniquify-possibly-resolvable nil)
-(defvar uniquify-managed nil
+(defvar-local uniquify-managed nil
"Non-nil if the name of this buffer is managed by uniquify.
It actually holds the list of `uniquify-item's corresponding to the conflict.")
-(make-variable-buffer-local 'uniquify-managed)
(put 'uniquify-managed 'permanent-local t)
;; Used in desktop.el to save the non-uniquified buffer name
(directory-file-name filename))))))))
(defun uniquify-rerationalize-w/o-cb (fix-list)
- "Re-rationalize the buffers in FIX-LIST, but ignoring current-buffer."
+ "Re-rationalize the buffers in FIX-LIST, but ignoring `current-buffer'."
(let ((new-fix-list nil))
(dolist (item fix-list)
(let ((buf (uniquify-item-buffer item)))
proposed)
;; Divide fix-list into items with same proposed names and pass them
;; to uniquify-rationalize-conflicting-sublist.
- (dolist (item (sort fix-list 'uniquify-item-greaterp))
+ (dolist (item (sort (copy-sequence fix-list) 'uniquify-item-greaterp))
(setq proposed (uniquify-item-proposed item))
(unless (equal proposed old-proposed)
(uniquify-rationalize-conflicting-sublist conflicting-sublist
(defun uniquify-get-proposed-name (base dirname &optional depth)
(unless depth (setq depth uniquify-min-dir-content))
- (assert (equal (directory-file-name dirname) dirname)) ;No trailing slash.
+ (cl-assert (equal (directory-file-name dirname) dirname)) ;No trailing slash.
;; Distinguish directories by adding extra separator.
(if (and uniquify-trailing-separator-p
;;; Hooks from the rest of Emacs
+(defun uniquify-maybe-rerationalize-w/o-cb ()
+ "Re-rationalize buffer names, ignoring current buffer."
+ (and (cdr uniquify-managed)
+ uniquify-buffer-name-style
+ (uniquify-rerationalize-w/o-cb uniquify-managed)))
+
;; Buffer deletion
;; Rerationalize after a buffer is killed, to reduce coinciding buffer names.
;; This mechanism uses `kill-buffer-hook', which runs *before* deletion, so
;; it calls `uniquify-rerationalize-w/o-cb' to rerationalize the buffer list
;; ignoring the current buffer (which is going to be deleted anyway).
-(defun uniquify-maybe-rerationalize-w/o-cb ()
+(defun uniquify-kill-buffer-function ()
"Re-rationalize buffer names, ignoring current buffer.
For use on `kill-buffer-hook'."
- (if (and (cdr uniquify-managed)
- uniquify-buffer-name-style
- uniquify-after-kill-buffer-p)
- (uniquify-rerationalize-w/o-cb uniquify-managed)))
+ (and uniquify-after-kill-buffer-p
+ (uniquify-maybe-rerationalize-w/o-cb)))
;; Ideally we'd like to add it buffer-locally, but that doesn't work
;; because kill-buffer-hook is not permanent-local :-(
-(add-hook 'kill-buffer-hook 'uniquify-maybe-rerationalize-w/o-cb)
+;; FIXME kill-buffer-hook _is_ permanent-local in 22+.
+(add-hook 'kill-buffer-hook 'uniquify-kill-buffer-function)
;; The logical place to put all this code is in generate-new-buffer-name.
;; It's written in C, so we would add a generate-new-buffer-name-function
;; rename-buffer and create-file-buffer. (Setting find-file-hook isn't
;; sufficient.)
-(defadvice rename-buffer (after rename-buffer-uniquify activate)
+(advice-add 'rename-buffer :around #'uniquify--rename-buffer-advice)
+(defun uniquify--rename-buffer-advice (rb-fun newname &optional unique &rest args)
"Uniquify buffer names with parts of directory name."
+ (let ((retval (apply rb-fun newname unique args)))
(uniquify-maybe-rerationalize-w/o-cb)
- (if (null (ad-get-arg 1)) ; no UNIQUE argument.
+ (if (null unique)
;; Mark this buffer so it won't be renamed by uniquify.
(setq uniquify-managed nil)
(when uniquify-buffer-name-style
;; Rerationalize w.r.t the new name.
(uniquify-rationalize-file-buffer-names
- (ad-get-arg 0)
+ newname
(uniquify-buffer-file-name (current-buffer))
(current-buffer))
- (setq ad-return-value (buffer-name (current-buffer))))))
+ (setq retval (buffer-name (current-buffer)))))
+ retval))
+
-(defadvice create-file-buffer (after create-file-buffer-uniquify activate)
+(advice-add 'create-file-buffer :around #'uniquify--create-file-buffer-advice)
+(defun uniquify--create-file-buffer-advice (cfb-fun filename &rest args)
"Uniquify buffer names with parts of directory name."
+ (let ((retval (apply cfb-fun filename args)))
(if uniquify-buffer-name-style
- (let ((filename (expand-file-name (directory-file-name (ad-get-arg 0)))))
+ (let ((filename (expand-file-name (directory-file-name filename))))
(uniquify-rationalize-file-buffer-names
(file-name-nondirectory filename)
- (file-name-directory filename) ad-return-value))))
+ (file-name-directory filename) retval)))
+ retval))
;;; The End
(set-buffer buf)
(when uniquify-managed
(push (cons buf (uniquify-item-base (car uniquify-managed))) buffers)))
- (dolist (fun '(rename-buffer create-file-buffer))
- (ad-remove-advice fun 'after (intern (concat (symbol-name fun) "-uniquify")))
- (ad-update fun))
+ (advice-remove 'rename-buffer #'uniquify--rename-buffer-advice)
+ (advice-remove 'create-file-buffer #'uniquify--create-file-buffer-advice)
(dolist (buf buffers)
(set-buffer (car buf))
(rename-buffer (cdr buf) t))))
(provide 'uniquify)
-;; arch-tag: e763faa3-56c9-4903-8eb8-26e1c45a0065
;;; uniquify.el ends here