aboutsummaryrefslogtreecommitdiff
path: root/.emacs.d/rul-lisp/packages/rul-modeline.el
diff options
context:
space:
mode:
Diffstat (limited to '.emacs.d/rul-lisp/packages/rul-modeline.el')
-rw-r--r--.emacs.d/rul-lisp/packages/rul-modeline.el159
1 files changed, 159 insertions, 0 deletions
diff --git a/.emacs.d/rul-lisp/packages/rul-modeline.el b/.emacs.d/rul-lisp/packages/rul-modeline.el
new file mode 100644
index 0000000..264719e
--- /dev/null
+++ b/.emacs.d/rul-lisp/packages/rul-modeline.el
@@ -0,0 +1,159 @@
+;; Most of the code in this file is based on:
+;; https://git.sr.ht/~protesilaos/dotfiles/tree/cf26bc34/item/emacs/.emacs.d/prot-lisp/prot-modeline.el
+;;
+;; All Kudos to Prot.
+
+;;;; Faces
+(defface rul-modeline-indicator-red
+ '((default :inherit bold)
+ (((class color) (min-colors 88) (background light))
+ :foreground "#880000")
+ (((class color) (min-colors 88) (background dark))
+ :foreground "#ff9f9f")
+ (t :foreground "red"))
+ "Face for modeline indicators.")
+
+;;;; Common helper functions
+(defcustom rul-modeline-string-truncate-length 9
+ "String length after which truncation should be done in small windows."
+ :type 'natnum)
+
+(defun rul-modeline--string-truncate-p (str)
+ "Return non-nil if STR should be truncated."
+ (and (< (window-total-width) split-width-threshold)
+ (> (length str) rul-modeline-string-truncate-length)
+ (not (one-window-p :no-minibuffer))))
+
+(defun rul-modeline-string-truncate (str)
+ "Return truncated STR, if appropriate, else return STR.
+Truncation is done up to `rul-modeline-string-truncate-length'."
+ (if (rul-modeline--string-truncate-p str)
+ (concat (substring str 0 rul-modeline-string-truncate-length) "...")
+ str))
+
+;;;; Major mode
+(defun rul-modeline-major-mode-indicator ()
+ "Return appropriate propertized mode line indicator for the major mode."
+ (let ((indicator (cond
+ ((derived-mode-p 'text-mode) "§")
+ ((derived-mode-p 'prog-mode) "λ")
+ ((derived-mode-p 'comint-mode) ">_")
+ (t "◦"))))
+ (propertize indicator 'face 'shadow)))
+
+(defun rul-modeline-major-mode-name ()
+ "Return capitalized `major-mode' without the -mode suffix."
+ (capitalize (string-replace "-mode" "" (symbol-name major-mode))))
+
+(defun rul-modeline-major-mode-help-echo ()
+ "Return `help-echo' value for `rul-modeline-major-mode'."
+ (if-let ((parent (get major-mode 'derived-mode-parent)))
+ (format "Symbol: `%s'. Derived from: `%s'" major-mode parent)
+ (format "Symbol: `%s'." major-mode)))
+
+(defvar-local rul-modeline-major-mode
+ (list
+ (propertize "%[" 'face 'rul-modeline-indicator-red)
+ '(:eval
+ (concat
+ (rul-modeline-major-mode-indicator)
+ " "
+ (propertize
+ (rul-modeline-string-truncate
+ (rul-modeline-major-mode-name))
+ 'mouse-face 'mode-line-highlight
+ 'help-echo (rul-modeline-major-mode-help-echo))))
+ (propertize "%]" 'face 'rul-modeline-indicator-red))
+ "Mode line construct for displaying major modes.")
+
+;(makunbound 'rul-modeline-major-mode)
+
+;;;; Align right
+(defun prot-modeline--right-align-rest ()
+ "Return string if everything after `prot-modeline-align-right'."
+ (format-mode-line
+ `(""
+ ,@(cdr (memq 'prot-modeline-align-right mode-line-format)))))
+
+(defun prot-modeline--right-align-width ()
+ "Return pixel width of `prot-modeline--right-align-rest'."
+ (string-pixel-width (prot-modeline--right-align-rest)))
+
+(defun prot-modeline--box-p ()
+ "Return non-nil if the `mode-line' has a box attribute."
+ (and (face-attribute 'mode-line :box)
+ (null (eq (face-attribute 'mode-line :box) 'unspecified))))
+
+(defun prot-modeline--variable-pitch-p ()
+ "Return non-nil if the `mode-line' inherits `variable-pitch'."
+ (when-let* ((mode-line-inherit (face-attribute 'mode-line :inherit))
+ ((string-match-p "variable-pitch" (symbol-name mode-line-inherit)))
+ (family-face (face-attribute mode-line-inherit :inherit))
+ (variable-pitch
+ (if (listp family-face)
+ (memq 'variable-pitch family-face)
+ (eq 'variable-pitch family-face))))
+ variable-pitch))
+
+(defun prot-modeline--magic-number ()
+ "Return constant for use in `prot-modeline-align-right'."
+ (let ((height (face-attribute 'mode-line :height nil 'default))
+ (m-width (string-pixel-width (propertize "m" 'face 'mode-line))))
+ (round height (* m-width (* height m-width 0.001)))))
+
+(defvar-local prot-modeline-align-right
+ '(:eval
+ (propertize
+ " "
+ 'display
+ (let ((box-p (prot-modeline--box-p))
+ (variable-pitch-p (prot-modeline--variable-pitch-p))
+ (magic-number (prot-modeline--magic-number)))
+ `(space
+ :align-to
+ (- right
+ right-fringe
+ right-margin
+ ,(ceiling
+ (prot-modeline--right-align-width)
+ (string-pixel-width (propertize "m" 'face 'mode-line)))
+ ,(cond
+ ((and variable-pitch-p box-p)
+ (* magic-number 0.5))
+ ((and (not variable-pitch-p) box-p)
+ (* magic-number 0.25))
+ ((and variable-pitch-p (not box-p))
+ (* magic-number -0.05))
+ (t (* magic-number -0.1))))))))
+ "Mode line construct to align following elements to the right.
+Read Info node `(elisp) Pixel Specification'.")
+
+
+;;;; Variables used in the modeline need to be in `risky-local-variable'.
+(dolist (construct '(
+ rul-modeline-major-mode
+ rul-modeline-misc-info
+ prot-modeline-align-right
+ ))
+ (put construct 'risky-local-variable t))
+
+;;;; Miscellaneous
+(defvar-local rul-modeline-misc-info
+ '(:eval
+ (when (mode-line-window-selected-p)
+ mode-line-misc-info))
+ "Mode line construct displaying `mode-line-misc-info'.
+Specific to the current window's mode line.")
+
+;;;; Finally, define the modeline format
+(setq-default mode-line-format
+ '("%e"
+ mode-line-front-space
+ mode-line-buffer-identification
+ mode-line-front-space
+ rul-modeline-major-mode
+ prot-modeline-align-right
+ rul-modeline-misc-info
+ ))
+
+(provide 'rul-modeline)
nihil fit ex nihilo