1 ;;; rich-minority.el --- Clean-up and Beautify the list of minor-modes.
3 ;; Copyright (C) 2014, 2015 Free Software Foundation, Inc.
5 ;; Author: Artur Malabarba <emacs@endlessparentheses.com>
6 ;; URL: https://github.com/Malabarba/rich-minority
7 ;; Package-Requires: ((cl-lib "0.5"))
9 ;; Keywords: mode-line faces
13 ;; Emacs package for hiding and/or highlighting the list of minor-modes
20 ;; To activate the enrichment of your minor-modes list, call `M-x
21 ;; rich-minority-mode', or add this to your init file:
24 ;; │ (rich-minority-mode 1)
27 ;; By default, this has a couple of small effects (provided as examples)
28 ;; it is up to you to customize it to your liking with the following
31 ;; `rm-blacklist': List of minor mode names that will be hidden from the
32 ;; minor-modes list. Use this to hide *only* a few modes
33 ;; that are always active and don’t really contribute
35 ;; `rm-whitelist': List of minor mode names that are allowed on the
36 ;; minor-modes list. Use this to hide *all but* a few
38 ;; `rm-text-properties': List text properties to apply to each minor-mode
39 ;; lighter. For instance, by default we highlight
40 ;; `Ovwrt' with a red face, so you always know if
41 ;; you’re in `overwrite-mode'.
44 ;; Comparison to Diminish
45 ;; ──────────────────────
47 ;; Diminish is an established player in the mode-line world, who also
48 ;; handles the minor-modes list. What can rich-minority /offer in
51 ;; • rich-minority is more versatile:
52 ;; 1. It accepts *regexps*, instead of having to specify each
53 ;; minor-mode individually;
54 ;; 2. It also offers a *whitelist* behaviour, in addition to the
56 ;; 3. It supports *highlighting* specific minor-modes with completely
57 ;; arbitrary text properties.
58 ;; • rich-minority takes a cleaner, functional approach. It doesn’t hack
59 ;; into the `minor-mode-alist' variable.
61 ;; What is rich-minority /missing/?
63 ;; 1. It doesn’t have a quick and simple replacement functionality yet.
64 ;; Although you can set the `display' property of a minor-mode to
65 ;; whatever string you want and that will function as a replacement.
66 ;; 2. Its source comments lack [Will Mengarini’s poetry]. :-)
69 ;; [Will Mengarini’s poetry] http://www.eskimo.com/~seldon/diminish.el
75 ;; This package is available fom Melpa, you may install it by calling
76 ;; `M-x package-install'.
82 (declare-function lm-version "lisp-mnt")
83 (defun rm-bug-report ()
84 "Opens github issues page in a web browser. Please send any bugs you find.
85 Please include your Emacs and rich-minority versions."
88 (message "Your rm-version is: %s, and your emacs version is: %s.\nPlease include this in your report!"
89 (lm-version "rich-minority.el") emacs-version)
90 (browse-url "https://github.com/Malabarba/rich-minority/issues/new"))
91 (defun rm-customize ()
92 "Open the customization menu in the `rich-minority' group."
94 (customize-group 'rich-minority t))
97 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
98 ;; Customization variables.
99 (defcustom rm-blacklist '(" hl-p")
100 "List of minor modes you want to hide from the mode-line.
102 Has three possible values:
104 - nil: All minor modes are shown in the mode-line (but see also
107 - List of strings: Represents a list of minor mode names that
108 will be hidden from the minor-modes list.
110 - A string: If this variable is set to a single string, this
111 string must be a regexp. This regexp will be compared to each
112 minor-mode lighter, and those which match are hidden from the
115 If you'd like to use a list of regexps, simply use something like the following:
116 (setq rm-blacklist (mapconcat 'identity list-of-regexps \"\\\\|\"))
118 Don't forget to start each string with a blank space, as most
119 minor-mode lighters start with a space."
120 :type '(choice (repeat string)
121 (regexp :tag "Regular expression."))
122 :group 'rich-minority
123 :package-version '(rich-minority . "0.1.1"))
124 (define-obsolete-variable-alias 'rm-excluded-modes 'rm-blacklist "0.1.1")
125 (define-obsolete-variable-alias 'rm-hidden-modes 'rm-blacklist "0.1.1")
127 (defcustom rm-whitelist nil
128 "List of minor modes you want to include in the mode-line.
130 - nil: All minor modes are shown in the mode-line (but see also
133 - List of strings: Represents a list of minor mode names that are
134 allowed on the minor-modes list. Any minor-mode whose lighter
135 is not in this list will NOT be displayed.
137 - A string: If this variable is set to a single string, this
138 string must be a regexp. This regexp will be compared to each
139 minor-mode lighter, and only those which match are displayed on
142 If you'd like to use a list of regexps, simply use something like the following:
143 (setq rm-whitelist (mapconcat 'identity list-of-regexps \"\\\\|\"))
145 Don't forget to start each string with a blank space, as most
146 minor-mode lighters start with a space."
147 :type '(choice (repeat string)
148 (regexp :tag "Regular expression."))
149 :group 'rich-minority
150 :package-version '(rich-minority . "0.1.1"))
151 (define-obsolete-variable-alias 'rm-included-modes 'rm-whitelist "0.1.1")
153 (defcustom rm-text-properties
154 '(("\\` Ovwrt\\'" 'face 'font-lock-warning-face))
155 "Alist of text properties to be applied to minor-mode lighters.
156 The car of each element must be a regexp, and the cdr must be a
157 list of text properties.
159 (REGEXP PROPERTY-NAME PROPERTY-VALUE ...)
161 If the regexp matches a minor mode lighter, the text properties
162 are applied to it. They are tested in order, and search stops at
165 These properties take priority over those defined in
166 `rm-base-text-properties'."
167 :type '(repeat (cons regexp (repeat sexp)))
168 :group 'rich-minority
169 :package-version '(rich-minority . "0.1"))
172 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
173 ;; Functions and Defvars
174 (defconst rm--help-echo-bottom
175 "Mouse-1: Mode Menu.\nMouse-2: Mode Help.\nMouse-3: Toggle Minor Modes.")
177 (defvar-local rm--help-echo nil
178 "Used to set the help-echo string dynamically.")
181 (defun rm--mode-list-as-string-list ()
182 "Return `minor-mode-list' as a simple list of strings."
183 (let ((full-list (delete "" (mapcar #'format-mode-line minor-mode-alist))))
185 (format "Full list:\n %s\n\n%s"
186 (mapconcat 'identity full-list "\n ")
187 rm--help-echo-bottom))
188 (mapcar #'rm--propertize
189 (rm--remove-hidden-modes full-list))))
191 (defcustom rm-base-text-properties
192 '('help-echo 'rm--help-echo
193 'mouse-face 'mode-line-highlight
194 'local-map mode-line-minor-mode-keymap)
195 "List of text propeties to apply to every minor mode."
197 :group 'rich-minority
198 :package-version '(rich-minority . "0.1"))
200 (defun rm--propertize (mode)
201 "Propertize the string MODE according to `rm-text-properties'."
202 (if (null (stringp mode))
203 `(:propertize ,mode ,@rm-base-text-properties)
204 (let ((al rm-text-properties)
206 (while (and (null done) al)
208 (if (string-match (car done) mode)
209 (setq prop (cdr done))
211 (eval `(propertize ,mode ,@prop ,@rm-base-text-properties)))))
213 (defun rm--remove-hidden-modes (li)
214 "Remove from LI elements that match `rm-blacklist' or don't match `rm-whitelist'."
215 (let ((pred (if (listp rm-blacklist) #'member #'rm--string-match))
221 (lambda (x) (unless (and (stringp x)
222 (funcall pred x rm-blacklist))
226 (setq pred (if (listp rm-whitelist) #'member #'rm--string-match))
230 (lambda (x) (unless (and (stringp x)
231 (null (funcall pred x rm-whitelist)))
236 (defun rm--string-match (string regexp)
237 "Like `string-match', but arg STRING comes before REGEXP."
238 (string-match regexp string))
241 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
243 (defvar rm--mode-line-construct
244 '(:eval (rm--mode-list-as-string-list))
245 "Construct used to replace `minor-mode-alist'.")
247 (defvar rm--warning-absent-element
248 "Couldn't find %S inside `mode-line-modes'. If you didn't change it yourself, please file a bug report with M-x rm-bug-report"
249 "Warning message used when something wasn't found.")
251 (defvar rm--backup-construct nil
252 "Construct containing `minor-mode-alist' which we removed from the mode-line.")
255 (define-minor-mode rich-minority-mode nil nil " $"
257 (if rich-minority-mode
258 (let ((place (or (member 'minor-mode-alist mode-line-modes)
260 (lambda (x) (and (listp x)
261 (equal (car x) :propertize)
262 (equal (cadr x) '("" minor-mode-alist))))
266 (setq rm--backup-construct (car place))
267 (setcar place rm--mode-line-construct))
268 (setq rich-minority-mode nil)
269 (if (member 'sml/pos-id-separator mode-line-format)
270 (message "You don't need to activate rich-minority-mode if you're using smart-mode-line")
271 (warn rm--warning-absent-element 'minor-mode-alist))))
272 (let ((place (member rm--mode-line-construct mode-line-modes)))
274 (setcar place rm--backup-construct)
275 (warn rm--warning-absent-element rm--mode-line-construct)))))
277 (provide 'rich-minority)
279 ;;; rich-minority.el ends here
282 ;; nameless-current-name: "rm"