Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
11 KiB

  1. ;;; rich-minority.el --- Clean-up and Beautify the list of minor-modes. -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2014, 2015 Free Software Foundation, Inc.
  3. ;; Author: Artur Malabarba <emacs@endlessparentheses.com>
  4. ;; URL: https://github.com/Malabarba/rich-minority
  5. ;; Package-Version: 1.0.3
  6. ;; Package-Commit: d33d2e357c8eb0b38624dbc51e8b953b08b0cc98
  7. ;; Package-Requires: ((cl-lib "0.5"))
  8. ;; Version: 1.0.3
  9. ;; License: GNU General Public License v3 or newer
  10. ;; Keywords: mode-line faces
  11. ;;; Commentary:
  12. ;;
  13. ;; Emacs package for hiding and/or highlighting the list of minor-modes
  14. ;; in the mode-line.
  15. ;;
  16. ;;
  17. ;; Usage
  18. ;; ─────
  19. ;;
  20. ;; To activate the enrichment of your minor-modes list, call `M-x
  21. ;; rich-minority-mode', or add this to your init file:
  22. ;;
  23. ;; ┌────
  24. ;; │ (rich-minority-mode 1)
  25. ;; └────
  26. ;;
  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
  29. ;; three variables:
  30. ;;
  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
  34. ;; information.
  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
  37. ;; modes.
  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'.
  42. ;;
  43. ;;
  44. ;; Comparison to Diminish
  45. ;; ──────────────────────
  46. ;;
  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
  49. ;; contrast/?
  50. ;;
  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
  55. ;; blacklist;
  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.
  60. ;;
  61. ;; What is rich-minority /missing/?
  62. ;;
  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]. :-)
  67. ;;
  68. ;;
  69. ;; [Will Mengarini’s poetry] http://www.eskimo.com/~seldon/diminish.el
  70. ;;
  71. ;;
  72. ;; Installation
  73. ;; ────────────
  74. ;;
  75. ;; This package is available fom Melpa, you may install it by calling
  76. ;; `M-x package-install'.
  77. ;;; Code:
  78. (require 'cl-lib)
  79. (declare-function lm-version "lisp-mnt")
  80. (defun rm-bug-report ()
  81. "Opens github issues page in a web browser. Please send any bugs you find.
  82. Please include your Emacs and rich-minority versions."
  83. (interactive)
  84. (require 'lisp-mnt)
  85. (message "Your rm-version is: %s, and your emacs version is: %s.\nPlease include this in your report!"
  86. (lm-version "rich-minority.el") emacs-version)
  87. (browse-url "https://github.com/Malabarba/rich-minority/issues/new"))
  88. (defun rm-customize ()
  89. "Open the customization menu in the `rich-minority' group."
  90. (interactive)
  91. (customize-group 'rich-minority t))
  92. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  93. ;; Customization variables.
  94. (defcustom rm-blacklist '(" hl-p")
  95. "List of minor modes you want to hide from the mode-line.
  96. Has three possible values:
  97. - nil: All minor modes are shown in the mode-line (but see also
  98. `rm-whitelist').
  99. - List of strings: Represents a list of minor mode names that
  100. will be hidden from the minor-modes list.
  101. - A string: If this variable is set to a single string, this
  102. string must be a regexp. This regexp will be compared to each
  103. minor-mode lighter, and those which match are hidden from the
  104. minor-mode list.
  105. If you'd like to use a list of regexps, simply use something like the following:
  106. (setq rm-blacklist (mapconcat 'identity list-of-regexps \"\\\\|\"))
  107. Don't forget to start each string with a blank space, as most
  108. minor-mode lighters start with a space."
  109. :type '(choice (repeat string)
  110. (regexp :tag "Regular expression."))
  111. :group 'rich-minority
  112. :package-version '(rich-minority . "0.1.1"))
  113. (define-obsolete-variable-alias 'rm-excluded-modes 'rm-blacklist "0.1.1")
  114. (define-obsolete-variable-alias 'rm-hidden-modes 'rm-blacklist "0.1.1")
  115. (defcustom rm-whitelist nil
  116. "List of minor modes you want to include in the mode-line.
  117. - nil: All minor modes are shown in the mode-line (but see also
  118. `rm-blacklist').
  119. - List of strings: Represents a list of minor mode names that are
  120. allowed on the minor-modes list. Any minor-mode whose lighter
  121. is not in this list will NOT be displayed.
  122. - A string: If this variable is set to a single string, this
  123. string must be a regexp. This regexp will be compared to each
  124. minor-mode lighter, and only those which match are displayed on
  125. the minor-mode list.
  126. If you'd like to use a list of regexps, simply use something like the following:
  127. (setq rm-whitelist (mapconcat 'identity list-of-regexps \"\\\\|\"))
  128. Don't forget to start each string with a blank space, as most
  129. minor-mode lighters start with a space."
  130. :type '(choice (repeat string)
  131. (regexp :tag "Regular expression."))
  132. :group 'rich-minority
  133. :package-version '(rich-minority . "0.1.1"))
  134. (define-obsolete-variable-alias 'rm-included-modes 'rm-whitelist "0.1.1")
  135. (defcustom rm-text-properties
  136. '(("\\` Ovwrt\\'" 'face 'font-lock-warning-face))
  137. "Alist of text properties to be applied to minor-mode lighters.
  138. The car of each element must be a regexp, and the cdr must be a
  139. list of text properties.
  140. (REGEXP PROPERTY-NAME PROPERTY-VALUE ...)
  141. If the regexp matches a minor mode lighter, the text properties
  142. are applied to it. They are tested in order, and search stops at
  143. the first match.
  144. These properties take priority over those defined in
  145. `rm-base-text-properties'."
  146. :type '(repeat (cons regexp (repeat sexp)))
  147. :group 'rich-minority
  148. :package-version '(rich-minority . "0.1"))
  149. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  150. ;; Functions and Defvars
  151. (defconst rm--help-echo-bottom
  152. "Mouse-1: Mode Menu.\nMouse-2: Mode Help.\nMouse-3: Toggle Minor Modes.")
  153. (defvar-local rm--help-echo nil
  154. "Used to set the help-echo string dynamically.")
  155. (defun rm-format-mode-line-entry (entry)
  156. "Format an ENTRY of `minor-mode-alist'.
  157. Return a cons of the mode line string and the mode name, or nil
  158. if the mode line string is empty."
  159. (let ((mode-symbol (car entry))
  160. (mode-string (format-mode-line entry)))
  161. (unless (string= mode-string "")
  162. (cons mode-string mode-symbol))))
  163. (defconst rm--help-echo-spacer
  164. (propertize " " 'display '(space :align-to 15)))
  165. (defun rm--help-echo-descriptor (pair)
  166. (format " %s%s(%S)" (car pair) rm--help-echo-spacer (cdr pair)))
  167. ;;;###autoload
  168. (defun rm--mode-list-as-string-list ()
  169. "Return `minor-mode-list' as a simple list of strings."
  170. (let ((full-list (delq nil (mapcar #'rm-format-mode-line-entry
  171. minor-mode-alist))))
  172. (setq rm--help-echo
  173. (format "Full list:\n%s\n\n%s"
  174. (mapconcat #'rm--help-echo-descriptor full-list "\n")
  175. rm--help-echo-bottom))
  176. (mapcar #'rm--propertize
  177. (rm--remove-hidden-modes
  178. (mapcar #'car full-list)))))
  179. (defcustom rm-base-text-properties
  180. '('help-echo 'rm--help-echo
  181. 'mouse-face 'mode-line-highlight
  182. 'local-map mode-line-minor-mode-keymap)
  183. "List of text propeties to apply to every minor mode."
  184. :type '(repeat sexp)
  185. :group 'rich-minority
  186. :package-version '(rich-minority . "0.1"))
  187. (defun rm--propertize (mode)
  188. "Propertize the string MODE according to `rm-text-properties'."
  189. (if (null (stringp mode))
  190. `(:propertize ,mode ,@rm-base-text-properties)
  191. (let ((al rm-text-properties)
  192. done prop)
  193. (while (and (null done) al)
  194. (setq done (pop al))
  195. (if (string-match (car done) mode)
  196. (setq prop (cdr done))
  197. (setq done nil)))
  198. (eval `(propertize ,mode ,@prop ,@rm-base-text-properties)))))
  199. (defun rm--remove-hidden-modes (li)
  200. "Remove from LI elements that match `rm-blacklist' or don't match `rm-whitelist'."
  201. (let ((pred (if (listp rm-blacklist) #'member #'rm--string-match))
  202. (out li))
  203. (when rm-blacklist
  204. (setq out
  205. (remove nil
  206. (mapcar
  207. (lambda (x) (unless (and (stringp x)
  208. (funcall pred x rm-blacklist))
  209. x))
  210. out))))
  211. (when rm-whitelist
  212. (setq pred (if (listp rm-whitelist) #'member #'rm--string-match))
  213. (setq out
  214. (remove nil
  215. (mapcar
  216. (lambda (x) (unless (and (stringp x)
  217. (null (funcall pred x rm-whitelist)))
  218. x))
  219. out))))
  220. out))
  221. (defun rm--string-match (string regexp)
  222. "Like `string-match', but arg STRING comes before REGEXP."
  223. (string-match regexp string))
  224. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  225. ;; minor-mode
  226. (defvar rm--mode-line-construct
  227. '(:eval (rm--mode-list-as-string-list))
  228. "Construct used to replace `minor-mode-alist'.")
  229. (defvar rm--warning-absent-element
  230. "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"
  231. "Warning message used when something wasn't found.")
  232. (defvar rm--backup-construct nil
  233. "Construct containing `minor-mode-alist' which we removed from the mode-line.")
  234. ;;;###autoload
  235. (define-minor-mode rich-minority-mode nil nil " $"
  236. :global t
  237. (if rich-minority-mode
  238. (let ((place (or (member 'minor-mode-alist mode-line-modes)
  239. (cl-member-if
  240. (lambda (x) (and (listp x)
  241. (equal (car x) :propertize)
  242. (equal (cadr x) '("" minor-mode-alist))))
  243. mode-line-modes))))
  244. (if place
  245. (progn
  246. (setq rm--backup-construct (car place))
  247. (setcar place rm--mode-line-construct))
  248. (setq rich-minority-mode nil)
  249. (if (member 'sml/pos-id-separator mode-line-format)
  250. (message "You don't need to activate rich-minority-mode if you're using smart-mode-line")
  251. (warn rm--warning-absent-element 'minor-mode-alist))))
  252. (let ((place (member rm--mode-line-construct mode-line-modes)))
  253. (if place
  254. (setcar place rm--backup-construct)
  255. (warn rm--warning-absent-element rm--mode-line-construct)))))
  256. (provide 'rich-minority)
  257. ;;; rich-minority.el ends here
  258. ;; Local Variables:
  259. ;; nameless-current-name: "rm"
  260. ;; End: