300 lines
11 KiB
EmacsLisp
300 lines
11 KiB
EmacsLisp
;;; rich-minority.el --- Clean-up and Beautify the list of minor-modes.
|
||
|
||
;; Copyright (C) 2014, 2015 Free Software Foundation, Inc.
|
||
|
||
;; Author: Artur Malabarba <emacs@endlessparentheses.com>
|
||
;; URL: https://github.com/Malabarba/rich-minority
|
||
;; Package-Version: 20160725.1255
|
||
;; Package-Requires: ((cl-lib "0.5"))
|
||
;; Version: 1.0.1
|
||
;; Keywords: mode-line faces
|
||
|
||
;;; Commentary:
|
||
;;
|
||
;; Emacs package for hiding and/or highlighting the list of minor-modes
|
||
;; in the mode-line.
|
||
;;
|
||
;;
|
||
;; Usage
|
||
;; ─────
|
||
;;
|
||
;; To activate the enrichment of your minor-modes list, call `M-x
|
||
;; rich-minority-mode', or add this to your init file:
|
||
;;
|
||
;; ┌────
|
||
;; │ (rich-minority-mode 1)
|
||
;; └────
|
||
;;
|
||
;; By default, this has a couple of small effects (provided as examples)
|
||
;; it is up to you to customize it to your liking with the following
|
||
;; three variables:
|
||
;;
|
||
;; `rm-blacklist': List of minor mode names that will be hidden from the
|
||
;; minor-modes list. Use this to hide *only* a few modes
|
||
;; that are always active and don’t really contribute
|
||
;; information.
|
||
;; `rm-whitelist': List of minor mode names that are allowed on the
|
||
;; minor-modes list. Use this to hide *all but* a few
|
||
;; modes.
|
||
;; `rm-text-properties': List text properties to apply to each minor-mode
|
||
;; lighter. For instance, by default we highlight
|
||
;; `Ovwrt' with a red face, so you always know if
|
||
;; you’re in `overwrite-mode'.
|
||
;;
|
||
;;
|
||
;; Comparison to Diminish
|
||
;; ──────────────────────
|
||
;;
|
||
;; Diminish is an established player in the mode-line world, who also
|
||
;; handles the minor-modes list. What can rich-minority /offer in
|
||
;; contrast/?
|
||
;;
|
||
;; • rich-minority is more versatile:
|
||
;; 1. It accepts *regexps*, instead of having to specify each
|
||
;; minor-mode individually;
|
||
;; 2. It also offers a *whitelist* behaviour, in addition to the
|
||
;; blacklist;
|
||
;; 3. It supports *highlighting* specific minor-modes with completely
|
||
;; arbitrary text properties.
|
||
;; • rich-minority takes a cleaner, functional approach. It doesn’t hack
|
||
;; into the `minor-mode-alist' variable.
|
||
;;
|
||
;; What is rich-minority /missing/?
|
||
;;
|
||
;; 1. It doesn’t have a quick and simple replacement functionality yet.
|
||
;; Although you can set the `display' property of a minor-mode to
|
||
;; whatever string you want and that will function as a replacement.
|
||
;; 2. Its source comments lack [Will Mengarini’s poetry]. :-)
|
||
;;
|
||
;;
|
||
;; [Will Mengarini’s poetry] http://www.eskimo.com/~seldon/diminish.el
|
||
;;
|
||
;;
|
||
;; Installation
|
||
;; ────────────
|
||
;;
|
||
;; This package is available fom Melpa, you may install it by calling
|
||
;; `M-x package-install'.
|
||
|
||
|
||
;;; Code:
|
||
(require 'cl-lib)
|
||
|
||
(declare-function lm-version "lisp-mnt")
|
||
(defun rm-bug-report ()
|
||
"Opens github issues page in a web browser. Please send any bugs you find.
|
||
Please include your Emacs and rich-minority versions."
|
||
(interactive)
|
||
(require 'lisp-mnt)
|
||
(message "Your rm-version is: %s, and your emacs version is: %s.\nPlease include this in your report!"
|
||
(lm-version "rich-minority.el") emacs-version)
|
||
(browse-url "https://github.com/Malabarba/rich-minority/issues/new"))
|
||
(defun rm-customize ()
|
||
"Open the customization menu in the `rich-minority' group."
|
||
(interactive)
|
||
(customize-group 'rich-minority t))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Customization variables.
|
||
(defcustom rm-blacklist '(" hl-p")
|
||
"List of minor modes you want to hide from the mode-line.
|
||
|
||
Has three possible values:
|
||
|
||
- nil: All minor modes are shown in the mode-line (but see also
|
||
`rm-whitelist').
|
||
|
||
- List of strings: Represents a list of minor mode names that
|
||
will be hidden from the minor-modes list.
|
||
|
||
- A string: If this variable is set to a single string, this
|
||
string must be a regexp. This regexp will be compared to each
|
||
minor-mode lighter, and those which match are hidden from the
|
||
minor-mode list.
|
||
|
||
If you'd like to use a list of regexps, simply use something like the following:
|
||
(setq rm-blacklist (mapconcat 'identity list-of-regexps \"\\\\|\"))
|
||
|
||
Don't forget to start each string with a blank space, as most
|
||
minor-mode lighters start with a space."
|
||
:type '(choice (repeat string)
|
||
(regexp :tag "Regular expression."))
|
||
:group 'rich-minority
|
||
:package-version '(rich-minority . "0.1.1"))
|
||
(define-obsolete-variable-alias 'rm-excluded-modes 'rm-blacklist "0.1.1")
|
||
(define-obsolete-variable-alias 'rm-hidden-modes 'rm-blacklist "0.1.1")
|
||
|
||
(defcustom rm-whitelist nil
|
||
"List of minor modes you want to include in the mode-line.
|
||
|
||
- nil: All minor modes are shown in the mode-line (but see also
|
||
`rm-blacklist').
|
||
|
||
- List of strings: Represents a list of minor mode names that are
|
||
allowed on the minor-modes list. Any minor-mode whose lighter
|
||
is not in this list will NOT be displayed.
|
||
|
||
- A string: If this variable is set to a single string, this
|
||
string must be a regexp. This regexp will be compared to each
|
||
minor-mode lighter, and only those which match are displayed on
|
||
the minor-mode list.
|
||
|
||
If you'd like to use a list of regexps, simply use something like the following:
|
||
(setq rm-whitelist (mapconcat 'identity list-of-regexps \"\\\\|\"))
|
||
|
||
Don't forget to start each string with a blank space, as most
|
||
minor-mode lighters start with a space."
|
||
:type '(choice (repeat string)
|
||
(regexp :tag "Regular expression."))
|
||
:group 'rich-minority
|
||
:package-version '(rich-minority . "0.1.1"))
|
||
(define-obsolete-variable-alias 'rm-included-modes 'rm-whitelist "0.1.1")
|
||
|
||
(defcustom rm-text-properties
|
||
'(("\\` Ovwrt\\'" 'face 'font-lock-warning-face))
|
||
"Alist of text properties to be applied to minor-mode lighters.
|
||
The car of each element must be a regexp, and the cdr must be a
|
||
list of text properties.
|
||
|
||
(REGEXP PROPERTY-NAME PROPERTY-VALUE ...)
|
||
|
||
If the regexp matches a minor mode lighter, the text properties
|
||
are applied to it. They are tested in order, and search stops at
|
||
the first match.
|
||
|
||
These properties take priority over those defined in
|
||
`rm-base-text-properties'."
|
||
:type '(repeat (cons regexp (repeat sexp)))
|
||
:group 'rich-minority
|
||
:package-version '(rich-minority . "0.1"))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; Functions and Defvars
|
||
(defconst rm--help-echo-bottom
|
||
"Mouse-1: Mode Menu.\nMouse-2: Mode Help.\nMouse-3: Toggle Minor Modes.")
|
||
|
||
(defvar-local rm--help-echo nil
|
||
"Used to set the help-echo string dynamically.")
|
||
|
||
(defun rm-format-mode-line-entry (entry)
|
||
"Format an ENTRY of `minor-mode-alist'.
|
||
Return a cons of the mode line string and the mode name, or nil
|
||
if the mode line string is empty."
|
||
(let ((mode-symbol (car entry))
|
||
(mode-string (format-mode-line entry)))
|
||
(unless (string= mode-string "")
|
||
(cons mode-string mode-symbol))))
|
||
|
||
;;;###autoload
|
||
(defun rm--mode-list-as-string-list ()
|
||
"Return `minor-mode-list' as a simple list of strings."
|
||
(let ((full-list (delq nil (mapcar #'rm-format-mode-line-entry
|
||
minor-mode-alist)))
|
||
(spacer (propertize " " 'display '(space :align-to 15))))
|
||
(setq rm--help-echo
|
||
(format "Full list:\n%s\n\n%s"
|
||
(mapconcat (lambda (pair)
|
||
(format " %s%s(%S)"
|
||
(car pair) spacer (cdr pair)))
|
||
full-list "\n")
|
||
rm--help-echo-bottom))
|
||
(mapcar #'rm--propertize
|
||
(rm--remove-hidden-modes
|
||
(mapcar #'car full-list)))))
|
||
|
||
(defcustom rm-base-text-properties
|
||
'('help-echo 'rm--help-echo
|
||
'mouse-face 'mode-line-highlight
|
||
'local-map mode-line-minor-mode-keymap)
|
||
"List of text propeties to apply to every minor mode."
|
||
:type '(repeat sexp)
|
||
:group 'rich-minority
|
||
:package-version '(rich-minority . "0.1"))
|
||
|
||
(defun rm--propertize (mode)
|
||
"Propertize the string MODE according to `rm-text-properties'."
|
||
(if (null (stringp mode))
|
||
`(:propertize ,mode ,@rm-base-text-properties)
|
||
(let ((al rm-text-properties)
|
||
done prop)
|
||
(while (and (null done) al)
|
||
(setq done (pop al))
|
||
(if (string-match (car done) mode)
|
||
(setq prop (cdr done))
|
||
(setq done nil)))
|
||
(eval `(propertize ,mode ,@prop ,@rm-base-text-properties)))))
|
||
|
||
(defun rm--remove-hidden-modes (li)
|
||
"Remove from LI elements that match `rm-blacklist' or don't match `rm-whitelist'."
|
||
(let ((pred (if (listp rm-blacklist) #'member #'rm--string-match))
|
||
(out li))
|
||
(when rm-blacklist
|
||
(setq out
|
||
(remove nil
|
||
(mapcar
|
||
(lambda (x) (unless (and (stringp x)
|
||
(funcall pred x rm-blacklist))
|
||
x))
|
||
out))))
|
||
(when rm-whitelist
|
||
(setq pred (if (listp rm-whitelist) #'member #'rm--string-match))
|
||
(setq out
|
||
(remove nil
|
||
(mapcar
|
||
(lambda (x) (unless (and (stringp x)
|
||
(null (funcall pred x rm-whitelist)))
|
||
x))
|
||
out))))
|
||
out))
|
||
|
||
(defun rm--string-match (string regexp)
|
||
"Like `string-match', but arg STRING comes before REGEXP."
|
||
(string-match regexp string))
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; minor-mode
|
||
(defvar rm--mode-line-construct
|
||
'(:eval (rm--mode-list-as-string-list))
|
||
"Construct used to replace `minor-mode-alist'.")
|
||
|
||
(defvar rm--warning-absent-element
|
||
"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"
|
||
"Warning message used when something wasn't found.")
|
||
|
||
(defvar rm--backup-construct nil
|
||
"Construct containing `minor-mode-alist' which we removed from the mode-line.")
|
||
|
||
;;;###autoload
|
||
(define-minor-mode rich-minority-mode nil nil " $"
|
||
:global t
|
||
(if rich-minority-mode
|
||
(let ((place (or (member 'minor-mode-alist mode-line-modes)
|
||
(cl-member-if
|
||
(lambda (x) (and (listp x)
|
||
(equal (car x) :propertize)
|
||
(equal (cadr x) '("" minor-mode-alist))))
|
||
mode-line-modes))))
|
||
(if place
|
||
(progn
|
||
(setq rm--backup-construct (car place))
|
||
(setcar place rm--mode-line-construct))
|
||
(setq rich-minority-mode nil)
|
||
(if (member 'sml/pos-id-separator mode-line-format)
|
||
(message "You don't need to activate rich-minority-mode if you're using smart-mode-line")
|
||
(warn rm--warning-absent-element 'minor-mode-alist))))
|
||
(let ((place (member rm--mode-line-construct mode-line-modes)))
|
||
(if place
|
||
(setcar place rm--backup-construct)
|
||
(warn rm--warning-absent-element rm--mode-line-construct)))))
|
||
|
||
(provide 'rich-minority)
|
||
|
||
;;; rich-minority.el ends here
|
||
|
||
;; Local Variables:
|
||
;; nameless-current-name: "rm"
|
||
;; End:
|