A => README.org +16 -0
@@ 0,0 1,16 @@
+* xaltsc's config mode line
+
+[[./screenshot.png]]
+
+A simple vim-like mode-line with special faces for evil.
+
+Names of the faces come from [[https://github.com/nvim-lualine/lualine.nvim][Lualine]].
+
+The default theme is based off [[https://carbondesignsystem.com/guidelines/color/overview][IBM's Carbon Design Language]].
+
+** Usage
+
+#+BEGIN_SRC emacs-lisp
+ (require 'xc-look-mode-line)
+ (setq-default mode-line-format xc-line/mode-line)
+#+END_SRC
A => screenshot.png +0 -0
A => xc-look-mode-line.el +258 -0
@@ 0,0 1,258 @@
+;; -*- lexical-binding: t; -*-
+
+;; copyright xaltsc 2022
+;; Default colours based off IBM's Carbon Design Language
+
+(defgroup xc-line nil
+ "lel"
+ :group 'mode-line)
+
+(defface xc-line-part-a-normal
+ '((t (:background "#0043ce"
+ :foreground "#f2f4f8"
+ :bold t :extend t)))
+ "Face for the leftmost part when Evil is in normal mode"
+ :group 'xc-line)
+(defface xc-line-part-a-insert
+ '((t (:background "#f1c21b"
+ :foreground "#21272a"
+ :bold t)))
+ "Face for the leftmost part when Evil is in insert mode"
+ :group 'xc-line)
+(defface xc-line-part-a-visual
+ '((t (:background "#007d79"
+ :foreground "#f2f4f8"
+ :bold t)))
+ "Face for the leftmost part when Evil is in visual mode"
+ :group 'xc-line)
+(defface xc-line-part-a-replace
+ '((t (:background "#da1e28"
+ :foreground "#f2f4f8"
+ :bold t)))
+ "Face for the leftmost part when Evil is in replace mode"
+ :group 'xc-line)
+(defface xc-line-part-a-operator
+ '((t (:background "#21272a"
+ :foreground "#f2f4f8"
+ :bold t)))
+ "Face for the leftmost part when Evil is in operator mode"
+ :group 'xc-line)
+(defface xc-line-part-a-emacs
+ '((t (:background "#8a3ffc"
+ :foreground "#f2f4f8"
+ :bold t)))
+ "Face for the leftmost part when Evil is in Emacs mode"
+ :group 'xc-line)
+(defface xc-line-part-a-motion
+ '((t (:inherit xc-line-part-a-operator)))
+ "Face for the leftmost part when Evil is in motion mode"
+ :group 'xc-line)
+(defface xc-line-part-b
+ '((t (:background "#c1c7cd" :foreground "#343a3f")))
+ "Face for the second leftmost part"
+ :group 'xc-line)
+(defface xc-line-part-c
+ '((t (:foreground "#4d5558")))
+ "Face for the third leftmost part"
+ :group 'xc-line)
+
+(defface xc-line-part-x
+ '((t (:inherit (xc-line-part-c))))
+ "Face for the third rightmost part"
+ :group 'xc-line)
+(defface xc-line-part-y
+ '((t (:inherit (xc-line-part-b))))
+ "Face for the second rightmost part"
+ :group 'xc-line)
+
+(defface xc-line-part-z-normal
+ '((t (:inherit (xc-line-part-a-normal))))
+ "Face for the rightmost part when Evil is in normal mode"
+ :group 'xc-line)
+(defface xc-line-part-z-insert
+ '((t (:inherit (xc-line-part-a-insert))))
+ "Face for the rightmost part when Evil is in insert mode"
+ :group 'xc-line)
+(defface xc-line-part-z-visual
+ '((t (:inherit (xc-line-part-a-visual))))
+ "Face for the rightmost part when Evil is in visual mode"
+ :group 'xc-line)
+(defface xc-line-part-z-replace
+ '((t (:inherit (xc-line-part-a-replace))))
+ "Face for the rightmost part when Evil is in replace mode"
+ :group 'xc-line)
+(defface xc-line-part-z-operator
+ '((t (:inherit (xc-line-part-a-operator))))
+ "Face for the rightmost part when Evil is in operator mode"
+ :group 'xc-line)
+(defface xc-line-part-z-emacs
+ '((t (:inherit (xc-line-part-a-emacs))))
+ "Face for the rightmost part when Evil is in Emacs mode"
+ :group 'xc-line)
+(defface xc-line-part-z-motion
+ '((t (:inherit (xc-line-part-a-motion))))
+ "Face for the rightmost part when Evil is in motion mode"
+ :group 'xc-line)
+(defface xc-line-container
+ '((t (:box (:line-width (-1 . 7)
+ :style flat-button))))
+ "Additional face applied to all the components of the mode line"
+ :group 'xc-line)
+
+
+(defcustom xc-line-separator " · "
+ "Divider string between segments in a part")
+
+(defcustom xc-line-modified "+"
+ "Icon for when the buffer has been modified")
+
+(defcustom xc-line-readonly ""
+ "Icon for when the buffer is read-only")
+
+(require 's)
+(require 'dash)
+
+(defun --escape-percent-construct (string)
+ (s-replace "%" "%%" string))
+
+;(defun --merge-face-in-list (sexp face-to-merge)
+; (let ((head (car sexp)))
+; (if (eq :propertize head)
+; (let* ((copied-sexp (-copy sexp))
+; (face-field (plist-get copied-sexp 'face))
+;; (if face-field
+; (cond
+; ((and (listp face-field) (not (memq face-to-merge face-field)))
+; (plist-put copied-sexp 'face
+; (append face-field (list face-to-merge))
+; ((not (or (listp face-field) (eq face-field face-to-merge)))
+; (plist-put copied-sexp 'face (list face-field face-to-merge))
+; (t copied-sexp)
+; (plist-put copied-sexp 'face face-to-merge)
+; sexp))
+
+;(defun --merge-face-properties (sexp face-to-merge)
+; (if (proper-list-p sexp)
+; (mapcar (-cut --merge-face-properties <> face-to-merge)
+; (--merge-face-in-list sexp face-to-merge)
+; sexp)))
+;
+(defun xc-line/centre-space (right-length)
+ "Creates the space for the centre of the mode line"
+ `(:propertize " " display (space :align-to (- right ,right-length))))
+
+(defun xc-line/format-part-expand-symbols (sym)
+ "Expands symbols when they are bound"
+ (if (and (symbolp sym) (boundp sym))
+ (symbol-value sym)
+ sym))
+
+(defun format-and-escape (format-spec)
+ (--escape-percent-construct (format-mode-line format-spec)))
+
+(defun xc-line/format-part (part face &optional extra-right-space-p)
+ "Formats `part' of the mode line while adding the face `face' at the end of
+ the face text property of its components. Adds an extra space at the end if
+ `extra-right-space-p' is non-nil.
+
+ Returns the resulting string."
+ (let* ((part-elt (if (and (listp part) (eq (car part) :multi))
+ (-interpose xc-line-separator
+ (mapcar #'xc-line/format-part-expand-symbols
+ (cdr part)))
+ part))
+ (formatted-part (format-and-escape
+ (list " " part-elt " "
+ (and extra-right-space-p " "))))
+ (f-p-length (length formatted-part)))
+ (add-face-text-property 0 f-p-length face t formatted-part)
+ formatted-part))
+
+; (part-w-face `(:eval (--merge-face-properties ',part-elt ',face)))
+; `(:propertize (" " ,part-w-face " " ,)
+; face ,face))
+
+(defun xc-line/get-face-for-mode (seg-identifier)
+ "Gets the correct face for the segment `seg-identifier' according to the
+ current `evil-state'"
+
+ (let ((face-string (format "xc-line-part-%s-%s" seg-identifier evil-state)))
+ (intern face-string)))
+
+(defun xc-line/format-left (a b c)
+ "Makes the left part of the mode line"
+ (let ((a-propd (xc-line/format-part a (xc-line/get-face-for-mode 'a)))
+ (b-propd (xc-line/format-part b 'xc-line-part-b))
+ (c-propd (xc-line/format-part c 'xc-line-part-c)))
+ (list a-propd b-propd c-propd)))
+
+(defun xc-line/format-right (x y z)
+ "Makes the right part of the mode line"
+ (let ((x-propd (xc-line/format-part x 'xc-line-part-x))
+ (y-propd (xc-line/format-part y 'xc-line-part-y))
+ (z-propd (xc-line/format-part z (xc-line/get-face-for-mode 'z) t)))
+ (list x-propd y-propd z-propd)))
+
+(defun xc-line/format (left right)
+ "Makes the mode line format"
+
+ (let* ((middle (xc-line/centre-space
+ (- (length (format-mode-line right)) 1)))
+ (mode-line-string (format-and-escape (list left middle right)))
+ (mls-length (length mode-line-string)))
+ (add-face-text-property 0 mls-length 'xc-line-container t mode-line-string)
+ mode-line-string))
+
+(setq xc-line/seg-evil
+ '(:eval (s-pad-right 3 " " (plist-get '(normal "NOR"
+ insert "INS"
+ visual "VIS"
+ operator "OP"
+ replace "REP"
+ motion "MOT"
+ emacs "EMX")
+ evil-state))))
+
+(defun xc-line/seg-buffer-status ()
+ (let ((modified (if (buffer-modified-p) xc-line-modified ""))
+ (readonly (if buffer-read-only xc-line-readonly "")))
+ (format "%s%s" modified readonly)))
+
+(setq xc-line/seg-buffer
+ '("%b" (:eval (xc-line/seg-buffer-status))))
+
+(setq xc-line/seg-major-mode
+ 'mode-name)
+
+(setq xc-line/seg-minor-modes
+ 'minor-mode-alist)
+
+(defun --xc-line/try-trim (obj)
+ (let ((maybe-str (or (and (symbolp obj) (boundp obj) (symbol-value obj))
+ obj)))
+ (if (stringp maybe-str) (s-trim maybe-str) maybe-str)))
+
+(setq xc-line/seg-misc-info
+ '(:eval (mapcar #'--xc-line/try-trim global-mode-string)))
+
+
+(setq xc-line/seg-progress
+ '(:eval (downcase (--escape-percent-construct
+ (format-mode-line '(-3 "%p"))))))
+
+(setq xc-line/seg-position
+ '(:eval (--escape-percent-construct
+ (s-pad-left 6 " " (format-mode-line "%l:%c")))))
+
+(defcustom xc-line/mode-line
+ '(:eval (xc-line/format
+ (xc-line/format-left xc-line/seg-evil
+ xc-line/seg-misc-info
+ xc-line/seg-buffer)
+ (xc-line/format-right xc-line/seg-minor-modes
+ xc-line/seg-progress
+ (list :multi xc-line/seg-position
+ xc-line/seg-major-mode))))
+ "xaltsc's config mode-line")
+
+(provide 'xc-look-mode-line)