denote-rename-buffer.el (6889B)
1 ;;; denote-rename-buffer.el --- Rename Denote buffers to be shorter and easier to read -*- lexical-binding: t -*- 2 3 ;; Copyright (C) 2023-2024 Free Software Foundation, Inc. 4 5 ;; Author: Protesilaos Stavrou <info@protesilaos.com> 6 ;; Maintainer: Protesilaos Stavrou <info@protesilaos.com> 7 ;; URL: https://github.com/protesilaos/denote 8 9 ;; This file is NOT part of GNU Emacs. 10 11 ;; This program is free software; you can redistribute it and/or modify 12 ;; it under the terms of the GNU General Public License as published by 13 ;; the Free Software Foundation, either version 3 of the License, or 14 ;; (at your option) any later version. 15 ;; 16 ;; This program is distributed in the hope that it will be useful, 17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 ;; GNU General Public License for more details. 20 ;; 21 ;; You should have received a copy of the GNU General Public License 22 ;; along with this program. If not, see <https://www.gnu.org/licenses/>. 23 24 ;;; Commentary: 25 ;; 26 ;; Rename Denote buffers to be shorter and easier to read. Enable 27 ;; `denote-rename-buffer-mode' to automatically rename the buffer of a 28 ;; Denote file. The renaming function is specified in the user option 29 ;; `denote-rename-buffer-function'. 30 31 ;;; Code: 32 33 (require 'denote) 34 35 (defgroup denote-rename-buffer nil 36 "Rename Denote buffers to be shorter and easier to read." 37 :group 'denote 38 :link '(info-link "(denote) Top") 39 :link '(url-link :tag "Homepage" "https://protesilaos.com/emacs/denote")) 40 41 (defcustom denote-rename-buffer-format "%t" 42 "The format of the buffer name `denote-rename-buffer' should use. 43 Thie value is a string that treats specially the following 44 specifiers: 45 46 - The %t is the Denote TITLE of the file. 47 - The %i is the Denote IDENTIFIER of the file. 48 - The %d is the same as %i (DATE mnemonic). 49 - The %s is the Denote SIGNATURE of the file. 50 - The %k is the Denote KEYWORDS of the file. 51 - The %% is a literal percent sign. 52 53 In addition, the following flags are available for each of the specifiers: 54 55 - 0 :: Pad to the width, if given, with zeros instead of spaces. 56 - - :: Pad to the width, if given, on the right instead of the left. 57 - < :: Truncate to the width and precision, if given, on the left. 58 - > :: Truncate to the width and precision, if given, on the right. 59 - ^ :: Convert to upper case. 60 - _ :: Convert to lower case. 61 62 When combined all together, the above are written thus: 63 64 %<flags><width><precision>SPECIFIER-CHARACTER 65 66 Any other string it taken as-is. Users may want, for example, to 67 include some text that makes Denote buffers stand out, such as 68 a [D] prefix." 69 :type 'string 70 :package-version '(denote . "2.1.0") 71 :group 'denote-rename-buffer) 72 73 (defcustom denote-rename-buffer-function #'denote-rename-buffer 74 "Symbol of function that is called to rename the Denote file buffer. 75 The default `denote-rename-buffer' function uses the pattern 76 described in `denote-rename-buffer-format'. 77 78 Users can set this variable to an arbitrary function that does 79 something else. The function is called without arguments from 80 the `find-file-hook' and `denote-after-new-note-hook'. 81 82 A nil value for this variable means that the title of the Denote 83 buffer will be used, if available." 84 :type '(choice 85 (const :tag "Rename using the `denote-rename-buffer-format'" denote-rename-buffer) 86 (function :tag "Use a custom renaming function")) 87 :package-version '(denote . "2.1.0") 88 :group 'denote-rename-buffer) 89 90 (defun denote-rename-buffer--format (buffer) 91 "Parse the BUFFER through the `denote-rename-buffer-format'." 92 (when-let ((file (buffer-file-name buffer)) 93 (type (denote-filetype-heuristics file))) 94 (string-trim 95 (format-spec denote-rename-buffer-format 96 (list (cons ?t (cond 97 ((denote-retrieve-front-matter-title-value file type)) 98 ((denote-retrieve-filename-title file)) 99 (t ""))) 100 (cons ?i (or (denote-retrieve-filename-identifier file) "")) 101 (cons ?d (or (denote-retrieve-filename-identifier file) "")) 102 (cons ?s (or (denote-retrieve-filename-signature file) "")) 103 (cons ?k (if-let ((kws (denote-retrieve-front-matter-keywords-value file type))) 104 (denote-keywords-combine kws) 105 (or (denote-retrieve-filename-keywords file) ""))) 106 (cons ?% "%")) 107 'delete)))) 108 109 (defun denote-rename-buffer (&optional buffer) 110 "Rename current buffer or optional BUFFER with `denote-rename-buffer-format'. 111 The symbol of this function is the default value of the user 112 option `denote-rename-buffer-function' and is thus used by the 113 `denote-rename-buffer-mode'." 114 (when-let ((file (buffer-file-name buffer)) 115 ((denote-file-has-identifier-p file)) 116 (new-name (denote-rename-buffer--format (or buffer (current-buffer)))) 117 ((not (string-blank-p new-name)))) 118 (rename-buffer new-name :unique))) 119 120 (make-obsolete 121 'denote-rename-buffer-with-title 122 'denote-rename-buffer 123 "2.1.0") 124 125 (make-obsolete 126 'denote-rename-buffer-with-identifier 127 'denote-rename-buffer 128 "2.1.0") 129 130 (defun denote-rename-buffer--fallback (&optional buffer) 131 "Fallback to rename BUFFER or `current-buffer'. 132 This is called if `denote-rename-buffer-rename-function' is nil." 133 (let ((denote-rename-buffer-format "%t")) 134 (denote-rename-buffer buffer))) 135 136 (defun denote-rename-buffer-rename-function-or-fallback () 137 "Call `denote-rename-buffer-function' or its fallback to rename with title. 138 Add this to `find-file-hook' and `denote-after-new-note-hook'." 139 (funcall (or denote-rename-buffer-function #'denote-rename-buffer--fallback))) 140 141 ;;;###autoload 142 (define-minor-mode denote-rename-buffer-mode 143 "Automatically rename Denote buffers to be easier to read. 144 A buffer is renamed upon visiting the underlying file. This 145 means that existing buffers are not renamed until they are 146 visited again in a new buffer (files are visited with the command 147 `find-file' or related)." 148 :global t 149 (if denote-rename-buffer-mode 150 (progn 151 (add-hook 'denote-after-new-note-hook #'denote-rename-buffer-rename-function-or-fallback) 152 (add-hook 'denote-after-rename-file-hook #'denote-rename-buffer-rename-function-or-fallback) 153 (add-hook 'find-file-hook #'denote-rename-buffer-rename-function-or-fallback)) 154 (remove-hook 'denote-after-new-note-hook #'denote-rename-buffer-rename-function-or-fallback) 155 (remove-hook 'denote-after-rename-file-hook #'denote-rename-buffer-rename-function-or-fallback) 156 (remove-hook 'find-file-hook #'denote-rename-buffer-rename-function-or-fallback))) 157 158 (provide 'denote-rename-buffer) 159 ;;; denote-rename-buffer.el ends here