288 lines
12 KiB
EmacsLisp
288 lines
12 KiB
EmacsLisp
;;; +modeline.el --- my modeline customizations -*- lexical-binding: t; -*-
|
|
|
|
;;; Commentary:
|
|
|
|
;; `+modeline.el' is kind of a dumping ground for various
|
|
;; modeline-related functions. I probably don't use everything in
|
|
;; here. Credit given where possible.
|
|
|
|
;;; Code:
|
|
|
|
(require '+util)
|
|
(require 'simple-modeline)
|
|
(require 'minions)
|
|
|
|
(defgroup +modeline nil
|
|
"Various customization options for my modeline things."
|
|
:prefix "+modeline-"
|
|
:group 'simple-modeline)
|
|
|
|
(defcustom +modeline-default-spacer " "
|
|
"Default spacer to use for modeline elements.
|
|
All modeline elements take an optional argument, `spacer', which
|
|
will default to this string.")
|
|
|
|
;;; Combinators
|
|
|
|
(defun +modeline-concat (segments &optional separator)
|
|
"Concatenate multiple `simple-modeline'-style SEGMENTS.
|
|
SEGMENTS is a list of either modeline segment-functions (see
|
|
`simple-modeline' functions for an example of types of
|
|
functions), though it can also contain cons cells of the
|
|
form (SEGMENT . PREDICATE).
|
|
|
|
Segments are separated from each other using SEPARATOR, which
|
|
defaults to a \" \". space. Only segments that evaluate to a
|
|
non-trivial string (that is, a string not equal to \"\") will be
|
|
separated, for a cleaner look.
|
|
|
|
This function makes a lambda, so you can throw it straight into
|
|
`simple-modeline-segments'."
|
|
(setq separator (or separator +modeline-default-spacer))
|
|
(lambda ()
|
|
(apply #'concat
|
|
(let (this-sep result-list)
|
|
(dolist (segment segments)
|
|
(push (funcall (or (car-safe segment) segment)
|
|
this-sep)
|
|
result-list)
|
|
(if (or (cdr-safe segment)
|
|
(and (car result-list)
|
|
(not (equal (car result-list) ""))))
|
|
(setq this-sep separator)
|
|
(setq this-sep nil)))
|
|
(unless (seq-some #'null result-list)
|
|
(push +modeline-default-spacer result-list))
|
|
(nreverse result-list)))))
|
|
|
|
;;; Modeline segments
|
|
|
|
(defun +modeline-buffer-name (&optional spacer) ; gonsie
|
|
"Display the buffer name."
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(propertize
|
|
(+string-align (buffer-name) 20 :ellipsis nil)
|
|
'help-echo (or (buffer-file-name)
|
|
(buffer-name))
|
|
'mouse-face 'mode-line-highlight)))
|
|
|
|
(defcustom +modeline-minions-icon "&"
|
|
"The \"icon\" for `+modeline-minions' button."
|
|
:type 'string)
|
|
|
|
(defun +modeline-minions (&optional spacer)
|
|
"Display a button for `minions-minor-modes-menu'."
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(propertize
|
|
+modeline-minions-icon
|
|
'help-echo "Minor modes menu\nmouse-1: show menu."
|
|
'local-map (purecopy (simple-modeline-make-mouse-map
|
|
'mouse-1
|
|
(lambda (event)
|
|
(interactive "e")
|
|
(with-selected-window
|
|
(posn-window (event-start event))
|
|
(minions-minor-modes-menu)))))
|
|
'mouse-face 'mode-line-highlight)))
|
|
|
|
(defun +modeline-major-mode (&optional spacer)
|
|
"Display the current `major-mode'."
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(propertize (+string-truncate (format-mode-line mode-name) 16)
|
|
'face 'bold
|
|
'keymap mode-line-major-mode-keymap
|
|
'help-echo (concat (format-mode-line mode-name)
|
|
" mode\nmouse-1: show menu.")
|
|
'mouse-face 'mode-line-highlight)))
|
|
|
|
(defcustom +modeline-modified-icon-alist '((ephemeral . "*")
|
|
(readonly . "=")
|
|
(modified . "+")
|
|
(special . "~")
|
|
(t . "-"))
|
|
"\"Icons\" to display depending on buffer status in modeline.
|
|
The CAR of each field is one of `readonly', `modified',
|
|
`special', `ephemeral', or t, and the CDR is a string to display
|
|
in that mode.
|
|
|
|
`readonly' is true if the buffer is read-only and visiting a file.
|
|
`modified' is true if the buffer is modified.
|
|
`special' is true if the buffer is a special-mode or derived buffer.
|
|
`ephemeral' is true if the buffer is not visiting a file.
|
|
t is the fall-back, shown when nothing else in the alist applies.
|
|
|
|
The order of elements matters: whichever one matches first is applied."
|
|
:type '(alist :key-type symbol
|
|
:value-type string)
|
|
:options '("readonly" "modified" "special" "t"))
|
|
|
|
(defcustom +modeline-modified-icon-special-modes '(special-mode)
|
|
"Modes to apply the `special-mode' icon to in the
|
|
`+modeline-modified'."
|
|
:type '(repeat function))
|
|
|
|
(defun +modeline-modified (&optional spacer) ; modified from `simple-modeline-status-modified'
|
|
"Display a color-coded \"icon\" indicator for the buffer's status."
|
|
(let* ((icon (catch :icon
|
|
(dolist (cell +modeline-modified-icon-alist)
|
|
(when (pcase (car cell)
|
|
('ephemeral (not (buffer-file-name)))
|
|
('readonly buffer-read-only)
|
|
('modified (buffer-modified-p))
|
|
('special
|
|
(apply 'derived-mode-p
|
|
+modeline-modified-icon-special-modes))
|
|
('t t)
|
|
(_ nil))
|
|
(throw :icon (cdr cell)))))))
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(propertize (or icon "")
|
|
'mouse-face 'mode-line-highlight))))
|
|
|
|
(defun +modeline-buffer-modes (&optional spacer)
|
|
"Display various buffer-specific stuff cleanly."
|
|
;; This is clunky and should probably be improved.
|
|
(concat (+modeline-reading-mode)
|
|
(+modeline-narrowed (when reading-mode ","))))
|
|
|
|
(defun +modeline-narrowed (&optional spacer)
|
|
"Display an indication that the buffer is narrowed."
|
|
(when (buffer-narrowed-p)
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(propertize "N"
|
|
'help-echo (format "%s\n%s"
|
|
"Buffer is narrowed."
|
|
"mouse-2: widen buffer.")
|
|
'local-map (purecopy (simple-modeline-make-mouse-map
|
|
'mouse-2 'mode-line-widen))
|
|
'face 'font-lock-doc-face
|
|
'mouse-face 'mode-line-highlight))))
|
|
|
|
(defun +modeline-reading-mode (&optional spacer)
|
|
"Display an indication that the buffer is in `reading-mode'."
|
|
(when reading-mode
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(propertize
|
|
(concat "R" (when (bound-and-true-p +eww-readable-p) "w"))
|
|
'help-echo (format "%s\n%s"
|
|
"Buffer is in reading-mode."
|
|
"mouse-2: disable reading-mode.")
|
|
'local-map (purecopy
|
|
(simple-modeline-make-mouse-map
|
|
'mouse-2 (lambda (ev)
|
|
(interactive "e")
|
|
(with-selected-window
|
|
(posn-window
|
|
(event-start ev))
|
|
(reading-mode -1)
|
|
(force-mode-line-update)))))
|
|
'face 'font-lock-doc-face
|
|
'mouse-face 'mode-line-highlight))))
|
|
|
|
(define-minor-mode file-percentage-mode
|
|
"Toggle the percentage display in the mode line (File Percentage Mode)."
|
|
:init-value t :global t :group 'mode-line)
|
|
|
|
(defun +modeline-file-percentage (&optional spacer)
|
|
"Display the position in the current file."
|
|
`(,(or spacer +modeline-default-spacer)
|
|
(:propertize (file-percentage-mode
|
|
(" " (-3 "%p") "%%"))
|
|
font-lock-face font-lock-comment-face)))
|
|
|
|
(define-minor-mode region-indicator-mode
|
|
"Toggle the region indicator in the mode line."
|
|
:init-value t :global t :group 'mode-line)
|
|
|
|
(defun +modeline-region (&optional spacer)
|
|
"Display an indicator if the region is active."
|
|
(when (and region-indicator-mode
|
|
(region-active-p))
|
|
(list
|
|
(format "%s%6s"
|
|
(or spacer +modeline-default-spacer)
|
|
(propertize (format "%s%d"
|
|
(if (and (< (point) (mark))) "-" "+")
|
|
(apply '+ (mapcar (lambda (pos)
|
|
(- (cdr pos)
|
|
(car pos)))
|
|
(region-bounds))))
|
|
'font-lock-face 'font-lock-variable-name-face)))))
|
|
|
|
(defun +modeline-line-column (&optional spacer) ; adapted from `simple-modeline'
|
|
"Display the current cursor line and column depending on modes."
|
|
(let ((sep "|") (before " [") (after "]"))
|
|
`(,(or spacer +modeline-default-spacer)
|
|
(:propertize (line-number-mode
|
|
((column-number-mode
|
|
(column-number-indicator-zero-based
|
|
,(concat before "%l" sep "%c" after)
|
|
,(concat before "%l" sep "%C" after))
|
|
,(concat before "%l" sep "" after)))
|
|
((column-number-mode
|
|
(column-number-indicator-zero-based
|
|
,(concat before sep "%c" after)
|
|
,(concat before sep "%C" after)))))
|
|
font-lock-face font-lock-comment-face))))
|
|
|
|
(defun +modeline-position (&optional _)
|
|
"Display the current cursor position.
|
|
See `line-number-mode', `column-number-mode', `file-percentage-mode'"
|
|
(append (+modeline-line-column)
|
|
(+modeline-region)
|
|
(+modeline-file-percentage)))
|
|
|
|
(defun +modeline-vc (&optional spacer)
|
|
"Display the version control branch of the current buffer in the modeline."
|
|
;; from https://www.gonsie.com/blorg/modeline.html, from Doom
|
|
(if-let ((backend (vc-backend buffer-file-name)))
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)))))
|
|
|
|
(defun +modeline-track (&optional spacer)
|
|
"Display `tracking-mode' information."
|
|
(when tracking-mode
|
|
tracking-mode-line-buffers))
|
|
|
|
(defun +modeline-anzu (&optional spacer)
|
|
"Display `anzu--update-mode-line'."
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(anzu--update-mode-line)))
|
|
|
|
(defun +modeline-text-scale (&optional spacer)
|
|
"Display text scaling level."
|
|
;; adapted from https://github.com/seagle0128/doom-modeline
|
|
(when (and (boundp 'text-scale-mode-amount)
|
|
(/= text-scale-mode-amount 0))
|
|
(format (if (> text-scale-mode-amount 0) "%s(%+d)" "%s(%-d)")
|
|
(or spacer +modeline-default-spacer)
|
|
text-scale-mode-amount)))
|
|
|
|
(defun +modeline-ace-window-display (&optional spacer)
|
|
"Display `ace-window-display-mode' information in the modeline."
|
|
(when (and +ace-window-display-mode
|
|
ace-window-mode)
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(window-parameter (selected-window) 'ace-window-path))))
|
|
|
|
(defun +modeline-god-mode (&optional spacer)
|
|
"Display an icon when `god-mode' is active."
|
|
(when (and (boundp 'god-local-mode) god-local-mode)
|
|
(concat (or spacer +modeline-default-spacer)
|
|
(propertize "Ω"
|
|
'help-echo (concat "God mode is active."
|
|
"\nmouse-1: exit God mode.")
|
|
'local-map (purecopy
|
|
(simple-modeline-make-mouse-map
|
|
'mouse-1 (lambda (e)
|
|
(interactive "e")
|
|
(with-selected-window
|
|
(posn-window
|
|
(event-start ev))
|
|
(god-local-mode -1)
|
|
(force-mode-line-update)))))
|
|
'mouse-face 'mode-line-highlight))))
|
|
|
|
(provide '+modeline)
|
|
;;; +modeline.el ends here
|