]> code.delx.au - gnu-emacs-elpa/blob - delight.el
3edee24c124542cf8e4380613120b40d68785d10
[gnu-emacs-elpa] / delight.el
1 ;;; delight.el --- A dimmer switch for your lighter text.
2 ;;
3 ;; Copyright (C) 2013, 2014, 2016 Phil Sainty
4 ;; Author: Phil Sainty <psainty@orcon.net.nz>
5 ;; URL: http://www.emacswiki.org/emacs/DelightedModes
6 ;; Keywords: convenience
7 ;; Created: 25 Jun 2013
8 ;; Version: 1.05
9
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24 ;;
25 ;; Enables you to customise the mode names displayed in the mode line.
26 ;;
27 ;; For major modes, the buffer-local `mode-name' variable is modified.
28 ;; For minor modes, the associated value in `minor-mode-alist' is set.
29 ;;
30 ;; Example usage:
31 ;;
32 ;; (require 'delight)
33 ;;
34 ;; (delight 'abbrev-mode " Abv" "abbrev")
35 ;;
36 ;; (delight '((abbrev-mode " Abv" "abbrev")
37 ;; (smart-tab-mode " \\t" "smart-tab")
38 ;; (eldoc-mode nil "eldoc")
39 ;; (rainbow-mode)
40 ;; (overwrite-mode " Ov" t)
41 ;; (emacs-lisp-mode "Elisp" :major)))
42 ;;
43 ;; The first argument is the mode symbol.
44 ;;
45 ;; The second argument is the replacement name to use in the mode line
46 ;; (or nil to hide it).
47 ;;
48 ;; The third argument is either the keyword :major for major modes or,
49 ;; for minor modes, the library which defines the mode. This is passed
50 ;; to ‘eval-after-load’ and so should be either the name (as a string)
51 ;; of the library file which defines the mode, or the feature (symbol)
52 ;; provided by that library. If this argument is nil, the mode symbol
53 ;; will be passed as the feature. If this argument is either t or 'emacs
54 ;; then it is assumed that the mode is already loaded (you can use this
55 ;; with standard minor modes that are pre-loaded by default when Emacs
56 ;; starts).
57 ;;
58 ;; To determine which library defines a mode, use e.g.: C-h f
59 ;; eldoc-mode RET. The name of the library is displayed in the first
60 ;; paragraph, with an “.el” suffix (in this example it displays
61 ;; “eldoc.el”, and therefore we could use the value “eldoc” for the
62 ;; library).
63 ;;
64 ;; Important note:
65 ;;
66 ;; Although strings are common, any mode-line construct is permitted
67 ;; as the value (for both minor and major modes); so before you
68 ;; override a value you should check the existing one, as you may
69 ;; want to replicate any structural elements in your replacement
70 ;; if it turns out not to be a simple string.
71 ;;
72 ;; For major modes, M-: mode-name
73 ;; For minor modes, M-: (cadr (assq 'MODE minor-mode-alist))
74 ;; for the minor MODE in question.
75 ;;
76 ;; Conversely, you may incorporate additional mode-line constructs in
77 ;; your replacement values, if you so wish. e.g.:
78 ;;
79 ;; (delight 'emacs-lisp-mode
80 ;; '("Elisp" (lexical-binding ":Lex" ":Dyn"))
81 ;; :major)
82 ;;
83 ;; See `mode-line-format' for information about mode-line constructs,
84 ;; and M-: (info "(elisp) Mode Line Format") for further details.
85 ;;
86 ;; Also bear in mind that some modes may dynamically update these
87 ;; values themselves (for instance dired-mode updates mode-name if
88 ;; you change the sorting criteria) in which cases this library may
89 ;; prove inadequate.
90
91 ;;; Change Log:
92 ;;
93 ;; 1.05 (2016-03-01) Support FILE value t, meaning that the minor MODE
94 ;; in question is guaranteed to already be loaded.
95 ;; 1.04 (2016-02-28) Respect `inhibit-mode-name-delight' when already set.
96 ;; 1.03 (2014-05-30) Added support for `mode-line-mode-menu'.
97 ;; 1.02 (2014-05-04) Bug fix for missing 'cl requirement for
98 ;; destructuring-bind macro.
99 ;; 1.01 (2014-05-04) Allow the keyword :major as the FILE argument for
100 ;; major modes, to avoid also processing them as minor modes.
101 ;; 1.00 (2013-06-25) Initial release.
102
103 ;;; Code:
104
105 (eval-when-compile
106 (require 'cl))
107
108 (defvar delighted-modes ()
109 "List of specs for modifying the display of mode names in the mode line.
110
111 See `delight'.")
112
113 ;;;###autoload
114 (defun delight (spec &optional value file)
115 "Modify the lighter value displayed in the mode line for the given mode SPEC
116 if and when the mode is loaded.
117
118 SPEC can be either a mode symbol, or a list containing multiple elements of
119 the form (MODE VALUE FILE). In the latter case the two optional arguments are
120 omitted, as they are instead specified for each element of the list.
121
122 For minor modes, VALUE is the replacement lighter value (or nil to disable)
123 to set in the `minor-mode-alist' variable. For major modes VALUE is the
124 replacement buffer-local `mode-name' value to use when a buffer changes to
125 that mode.
126
127 In both cases VALUE is commonly a string, but may in fact contain any valid
128 mode-line construct. For details see the `mode-line-format' variable, and
129 Info node `(elisp) Mode Line Format'.
130
131 The FILE argument is passed through to `eval-after-load'. If FILE is nil then
132 the mode symbol is passed as the required feature. If FILE is t then it is
133 assumed that the mode is already loaded. (Note that you can also use 'emacs
134 for this purpose). These FILE options are relevant to minor modes only.
135
136 For major modes you should specify the keyword :major as the value of FILE,
137 to prevent the mode being treated as a minor mode."
138 (add-hook 'after-change-major-mode-hook 'delight-major-mode)
139 (let ((glum (if (consp spec) spec (list (list spec value file)))))
140 (while glum
141 (destructuring-bind (mode &optional value file) (pop glum)
142 (assq-delete-all mode delighted-modes)
143 (add-to-list 'delighted-modes (list mode value file))
144 (unless (eq file :major)
145 (eval-after-load (if (eq file t) 'emacs (or file mode))
146 `(let ((minor-delight (assq ',mode minor-mode-alist)))
147 (when minor-delight
148 (setcar (cdr minor-delight) ',value)
149 (delight-mode-line-mode-menu ',mode ',value)))))))))
150
151 (defun delight-mode-line-mode-menu (mode value)
152 "Delight `mode-line-mode-menu' (the \"Toggle minor modes\" menu)
153 so that the Lighter text displayed in the menu matches that displayed in
154 the mode line (when such menu items exist).
155
156 The expected naming scheme for the menu items is: \"Friendly name (Lighter)\"
157 e.g.: \"Highlight changes (Chg)\".
158
159 We replace the \"Lighter\" portion of that with our delighted VALUE, for the
160 specified MODE, unless VALUE is empty/nil, in which case we remove the text
161 and parentheses altogether.
162
163 If the delighted VALUE is not a string and not nil, we do nothing."
164 (when (string-or-null-p value)
165 (let* ((menu-keymap mode-line-mode-menu)
166 (menu-item (assq mode (cdr menu-keymap))))
167 (when menu-item
168 ;; Lighter text is typically prefixed with a space to separate
169 ;; it from the preceding lighter. We need to trim that space.
170 (let* ((trimmed-value (if (and value (string-match "\\`\\s-+" value))
171 (replace-match "" t t value)
172 value))
173 (wrapped-value (if (> (length trimmed-value) 0)
174 (concat " (" trimmed-value ")")
175 ""))
176 (menu-def (cdr menu-item))
177 (label (cadr menu-def))
178 (new-label (and (stringp label)
179 (or (string-match "\\s-+(.+?)\\s-*\\'" label)
180 (string-match "\\s-*\\'" label))
181 (replace-match wrapped-value t t label))))
182 (when new-label
183 ;; Pure storage is used for the default menu items, so we
184 ;; cannot modify those objects directly.
185 (setq menu-def (copy-sequence menu-def))
186 (setf (cadr menu-def) new-label)
187 (define-key menu-keymap (vector mode) menu-def)))))))
188
189 (defun delight-major-mode ()
190 "Delight the 'pretty name' of the current buffer's major mode
191 when displayed in the mode-line.
192
193 When `mode-name' is displayed in other contexts (such as in the
194 `describe-mode' help buffer), its original value will be used."
195 (let ((major-delight (assq major-mode delighted-modes)))
196 (when major-delight
197 (setq mode-name `(inhibit-mode-name-delight
198 ,mode-name ;; glum
199 ,(cadr major-delight)))))) ;; delighted
200
201 (defvar inhibit-mode-name-delight)
202
203 (defadvice format-mode-line (around delighted-modes-are-glum activate)
204 "Delighted modes should exhibit their original `mode-name' when
205 `format-mode-line' is called. See `delight-major-mode'."
206 (let ((inhibit-mode-name-delight (if (boundp 'inhibit-mode-name-delight)
207 inhibit-mode-name-delight
208 t)))
209 ad-do-it))
210
211 (provide 'delight)
212 ;;; delight.el ends here