ui/doom-modeline: update + refactor + new modeline macros

This commit is contained in:
Henrik Lissner 2017-02-11 06:49:57 -05:00
parent addc67b965
commit 0f5dbd0bac
2 changed files with 166 additions and 207 deletions

View file

@ -1,5 +1,7 @@
;;; ui/doom-modeline/config.el ;;; ui/doom-modeline/config.el
(provide '+doom-modeline)
(eval-when-compile
(require 'powerline))
;; all-the-icons doesn't work in the terminal, so we "disable" it. ;; all-the-icons doesn't work in the terminal, so we "disable" it.
(unless (display-graphic-p) (unless (display-graphic-p)
@ -9,12 +11,10 @@
(defun all-the-icons-wicon (&rest _) "" "") (defun all-the-icons-wicon (&rest _) "" "")
(defun all-the-icons-alltheicon (&rest _) "" "")) (defun all-the-icons-alltheicon (&rest _) "" ""))
(use-package powerline :demand t) (@def-package all-the-icons :demand t
(use-package all-the-icons :demand t
:when (display-graphic-p)) :when (display-graphic-p))
(use-package eldoc-eval :demand t (@def-package eldoc-eval :demand t
:config :config
;; Show eldoc in the mode-line with `eval-expression' ;; Show eldoc in the mode-line with `eval-expression'
(setq eldoc-in-minibuffer-show-fn '+doom-modeline--show-eldoc) (setq eldoc-in-minibuffer-show-fn '+doom-modeline--show-eldoc)
@ -22,12 +22,13 @@
;; anzu and evil-anzu make it possible to display current/total in the ;; anzu and evil-anzu make it possible to display current/total in the
;; mode-line. ;; mode-line.
(use-package! evil-anzu (@def-package evil-anzu
:when (featurep 'evil)
:init :init
(defun +evil*lazy-load-evil-anzu (&rest _) (require 'evil-anzu)) (defun +evil*lazy-load-evil-anzu (&rest _) (require 'evil-anzu))
(advice-add 'evil-ex-start-setup :before '+evil*lazy-load-evil-anzu) (advice-add 'evil-ex-start-search :before '+evil*lazy-load-evil-anzu)
:config :config
(advice-remove 'evil-ex-start-setup '+evil*lazy-load-evil-anzu) (advice-remove 'evil-ex-start-search '+evil*lazy-load-evil-anzu)
(setq anzu-cons-mode-line-p nil (setq anzu-cons-mode-line-p nil
anzu-minimum-input-length 1 anzu-minimum-input-length 1
anzu-search-threshold 250)) anzu-search-threshold 250))
@ -53,7 +54,7 @@
;; and it's a symbol, use it to find the modeline format in ;; and it's a symbol, use it to find the modeline format in
;; `doom-modeline-formats'. If nil, show the mode-line as normal. If t, then ;; `doom-modeline-formats'. If nil, show the mode-line as normal. If t, then
;; hide the modeline entirely. ;; hide the modeline entirely.
(add-hook! doom-popup-mode (@add-hook doom-popup-mode
(if (and (not doom-popup-mode) (if (and (not doom-popup-mode)
doom-hide-modeline-mode) doom-hide-modeline-mode)
(doom-hide-modeline-mode -1) (doom-hide-modeline-mode -1)
@ -69,15 +70,16 @@
;; Variables ;; Variables
;; ;;
(defvar doom-modeline-formats '() (defvar +doom-modeline-height 29
"An alist of mode-line formats. Use `+doom-modeline' to retrieve one.")
(defvar doom-modeline-height 29
"How tall the mode-line should be (only respected in GUI emacs).") "How tall the mode-line should be (only respected in GUI emacs).")
(defvar doom-modeline-bar-width 3 (defvar +doom-modeline-bar-width 3
"How wide the mode-line bar should be (only respected in GUI emacs).") "How wide the mode-line bar should be (only respected in GUI emacs).")
(defvar +doom-modeline-vspc
(propertize " " 'face 'variable-pitch)
"docstring")
;; ;;
;; Custom faces ;; Custom faces
@ -105,7 +107,7 @@
(defface doom-modeline-panel (defface doom-modeline-panel
'((t (:inherit mode-line))) '((t (:inherit mode-line)))
"Face for 'X out of Y' segments, such as `*anzu', `*evil-substitute' and "Face for 'X out of Y' segments, such as `+doom-modeline--anzu', `+doom-modeline--evil-substitute' and
`iedit'") `iedit'")
(defface doom-modeline-info (defface doom-modeline-info
@ -149,23 +151,8 @@ active.")
s))))) s)))))
;; Only support python and ruby for now ;; Only support python and ruby for now
(add-hook! python-mode (setq +doom-modeline-env-command "python --version 2>&1 | cut -d' ' -f2")) (@add-hook python-mode (setq +doom-modeline-env-command "python --version 2>&1 | cut -d' ' -f2"))
(add-hook! ruby-mode (setq +doom-modeline-env-command "ruby --version 2>&1 | cut -d' ' -f2")) (@add-hook ruby-mode (setq +doom-modeline-env-command "ruby --version 2>&1 | cut -d' ' -f2"))
;;
;; Library
;;
(defun +doom-modeline (key)
(let ((modeline (assq key doom-modeline-formats)))
(unless modeline
(error "Modeline preset doesn't exist: %s" key))
(cdr modeline)))
(defun +doom-modeline-define (name &rest forms)
"Define a modeline format."
(push `(,name . ,forms) doom-modeline-formats))
;; ;;
@ -174,13 +161,6 @@ active.")
(defsubst active () (eq (selected-window) powerline-selected-window)) (defsubst active () (eq (selected-window) powerline-selected-window))
(defun +doom-modeline--flycheck-count (state)
"Return flycheck information for the given error type STATE."
(when (flycheck-has-current-errors-p state)
(if (eq 'running flycheck-last-status-change)
"?"
(cdr-safe (assq state (flycheck-count-errors flycheck-current-errors))))))
(defun +doom-modeline--make-xpm (color height width) (defun +doom-modeline--make-xpm (color height width)
"Create an XPM bitmap." "Create an XPM bitmap."
(when (display-graphic-p) (when (display-graphic-p)
@ -224,7 +204,7 @@ project root). Excludes the file basename. See `doom-buffer-name' for that."
(str (and (stringp input) (concat " " input))) (str (and (stringp input) (concat " " input)))
(len (length str)) (len (length str))
(tmp-str str) (tmp-str str)
(mode-line-format (or (and str (doom-eldoc-modeline)) (mode-line-format (or (and str (doom-modeline 'eldoc))
mode-line-format)) mode-line-format))
roll mode-line-in-non-selected-windows) roll mode-line-in-non-selected-windows)
(catch 'break (catch 'break
@ -250,8 +230,9 @@ project root). Excludes the file basename. See `doom-buffer-name' for that."
;; Segments ;; Segments
;; ;;
(defun *buffer-project () (@def-modeline-segment buffer-project
"Displays `default-directory', for special buffers like the scratch buffer." "Displays `doom-project-root'. This is for special buffers like the scratch
buffer where knowing the current project directory is important."
(let ((face (if (active) 'doom-modeline-buffer-project))) (let ((face (if (active) 'doom-modeline-buffer-project)))
(concat (all-the-icons-octicon (concat (all-the-icons-octicon
"file-directory" "file-directory"
@ -261,7 +242,7 @@ project root). Excludes the file basename. See `doom-buffer-name' for that."
(propertize (concat " " (abbreviate-file-name (doom-project-root))) (propertize (concat " " (abbreviate-file-name (doom-project-root)))
'face face)))) 'face face))))
(defun *buffer-info () (@def-modeline-segment buffer-info
"Combined information about the current buffer, including the current working "Combined information about the current buffer, including the current working
directory, the file name, and its state (modified, read-only or non-existent)." directory, the file name, and its state (modified, read-only or non-existent)."
(let ((all-the-icons-scale-factor 1.2) (let ((all-the-icons-scale-factor 1.2)
@ -290,8 +271,8 @@ directory, the file name, and its state (modified, read-only or non-existent)."
(propertize (+doom-modeline--buffer-path) (propertize (+doom-modeline--buffer-path)
'face (if faces `(:inherit ,faces)))))) 'face (if faces `(:inherit ,faces))))))
(defun *buffer-encoding () (@def-modeline-segment buffer-encoding
"The encoding and eol style of the buffer." "Displays the encoding and eol style of the buffer the same way Atom does."
(concat (let ((eol-type (coding-system-eol-type buffer-file-coding-system))) (concat (let ((eol-type (coding-system-eol-type buffer-file-coding-system)))
(cond ((eq eol-type 0) "LF ") (cond ((eq eol-type 0) "LF ")
((eq eol-type 1) "CRLF ") ((eq eol-type 1) "CRLF ")
@ -304,7 +285,7 @@ directory, the file name, and its state (modified, read-only or non-existent)."
(t (upcase (symbol-name sys-name))))) (t (upcase (symbol-name sys-name)))))
" ")) " "))
(defun *major-mode () (@def-modeline-segment major-mode
"The major mode, including process, environment and text-scale info." "The major mode, including process, environment and text-scale info."
(propertize (propertize
(concat (format-mode-line mode-name) (concat (format-mode-line mode-name)
@ -315,7 +296,7 @@ directory, the file name, and its state (modified, read-only or non-existent)."
(format " (%+d)" text-scale-mode-amount))) (format " (%+d)" text-scale-mode-amount)))
'face (if (active) 'doom-modeline-buffer-major-mode))) 'face (if (active) 'doom-modeline-buffer-major-mode)))
(defun *vc () (@def-modeline-segment vcs
"Displays the current branch, colored based on its state." "Displays the current branch, colored based on its state."
(when (and vc-mode buffer-file-name) (when (and vc-mode buffer-file-name)
(let ((backend (vc-backend buffer-file-name)) (let ((backend (vc-backend buffer-file-name))
@ -324,7 +305,7 @@ directory, the file name, and its state (modified, read-only or non-existent)."
(active (active)) (active (active))
(all-the-icons-scale-factor 1.0) (all-the-icons-scale-factor 1.0)
(all-the-icons-default-adjust -0.1)) (all-the-icons-default-adjust -0.1))
(concat (propertize " " 'face 'variable-pitch) (concat +doom-modeline-vspc
(cond ((memq state '(edited added)) (cond ((memq state '(edited added))
(if active (setq face 'doom-modeline-info)) (if active (setq face 'doom-modeline-info))
(all-the-icons-octicon (all-the-icons-octicon
@ -352,69 +333,60 @@ directory, the file name, and its state (modified, read-only or non-existent)."
(propertize (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)) (propertize (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2))
'face (if active face)) 'face (if active face))
" " " "
(propertize " " 'face 'variable-pitch))))) +doom-modeline-vspc))))
(defvar-local doom--flycheck-err-cache nil "") (defun +doom-ml-icon (icon &optional text face)
(defvar-local doom--flycheck-cache nil "") "Displays an octicon ICON with FACE, followed by TEXT. Uses
(defun *flycheck () `all-the-icons-octicon' to fetch the icon."
"Persistent and cached flycheck indicators in the mode-line."
(when (and (featurep 'flycheck) flycheck-mode)
(if (or flycheck-current-errors
(eq 'running flycheck-last-status-change))
(or (and (or (eq doom--flycheck-err-cache doom--flycheck-cache)
(memq flycheck-last-status-change '(running not-checked)))
(if (eq flycheck-last-status-change 'running)
(concat " "
(all-the-icons-octicon
"ellipsis"
:face 'font-lock-doc-face
:height 1.1
:v-adjust 0)
" ")
doom--flycheck-cache))
(and (setq doom--flycheck-err-cache flycheck-current-errors)
(setq doom--flycheck-cache
(let ((fw (+doom-modeline--flycheck-count 'warning))
(fe (+doom-modeline--flycheck-count 'error)))
(concat (if (or fe fw) " ")
(if fe (concat
(all-the-icons-octicon "circle-slash" :face 'doom-modeline-urgent :height 1.0 :v-adjust 0)
(propertize " " 'face 'variable-pitch)
(propertize (format "%d" fe) 'face 'doom-modeline-urgent)
" "
))
(if fw (concat
(all-the-icons-octicon "alert" :face 'doom-modeline-warning :height 0.9 :v-adjust 0)
(propertize " " 'face 'variable-pitch)
(propertize (format "%d" fw) 'face 'doom-modeline-warning)
" "
))
(if (or fe fw)
" "
(when (active)
(all-the-icons-octicon "check" :height 1.2 :v-adjust -0.06))))))))
(concat (concat
" " " "
(all-the-icons-octicon "check" (when icon
:face (if (active) 'doom-modeline-info) (concat
:height 1.2 (all-the-icons-octicon icon :face face :height 1.0 :v-adjust 0)
:v-adjust -0.06) (when text
" ")))) (propertize " " 'face 'variable-pitch))))
(when text
(propertize text 'face face))))
(defun *selection-info () (@def-modeline-segment flycheck
"Displays color-coded flycheck error status in the current buffer with pretty
icons."
(when (boundp 'flycheck-last-status-change)
(pcase flycheck-last-status-change
(`finished (if flycheck-current-errors
(let-alist (flycheck-count-errors flycheck-current-errors)
(let ((sum (+ (or .error 0) (or .warning 0))))
(+doom-ml-icon "circle-slash" (format "%s issue%s" sum (if (eq 1 sum) "" "s"))
(if .error 'doom-modeline-urgent 'doom-modeline-warning))))
(concat
(+doom-ml-icon "check" nil 'doom-modeline-info) " ")))
(`running (+doom-ml-icon "ellipsis" "Running" 'font-lock-doc-face))
(`no-checker (+doom-ml-icon "alert" "-" 'font-lock-doc-face))
(`errored (+doom-ml-icon "alert" "Error" 'doom-modeline-urgent))
(`interrupted (+doom-ml-icon "x" "Interrupted" 'font-lock-doc-face))
;; (`suspicious "")
)))
(defsubst doom-column (pos)
(save-excursion
(when pos (goto-char pos))
(current-column)))
(@def-modeline-segment selection-info
"Information about the current selection, such as how many characters and "Information about the current selection, such as how many characters and
lines are selected, or the NxM dimensions of a block selection." lines are selected, or the NxM dimensions of a block selection."
(when (and (active) (evil-visual-state-p)) (when mark-active
(let ((evil-p (featurep 'evil)))
(concat (concat
" " " "
(propertize (propertize
(let ((reg-beg (region-beginning)) (let ((reg-beg (region-beginning))
(reg-end (region-end)) (reg-end (region-end))
(evil (eq 'visual evil-state))) (evil (and evil-p (eq 'visual evil-state))))
(let ((lines (count-lines reg-beg (min (1+ reg-end) (point-max)))) (let ((lines (count-lines reg-beg (min (1+ reg-end) (point-max))))
(chars (- (1+ reg-end) reg-beg)) (chars (- (1+ reg-end) reg-beg))
(cols (1+ (abs (- (evil-column reg-end) (cols (1+ (abs (- (doom-column reg-end)
(evil-column reg-beg)))))) (doom-column reg-beg))))))
(cond (cond
;; rectangle selection ;; rectangle selection
((or (bound-and-true-p rectangle-mark-mode) ((or (bound-and-true-p rectangle-mark-mode)
@ -426,9 +398,10 @@ lines are selected, or the NxM dimensions of a block selection."
(format " %dL " lines) (format " %dL " lines)
(format " %dC %dL " chars lines))) (format " %dC %dL " chars lines)))
(t (format " %dC " (if evil chars (1- chars))))))) (t (format " %dC " (if evil chars (1- chars)))))))
'face 'doom-modeline-highlight)))) 'face 'doom-modeline-highlight)))))
(defun *macro-recording ()
(defun +doom-modeline--macro-recording ()
"Display current macro being recorded." "Display current macro being recorded."
(when (and (active) defining-kbd-macro) (when (and (active) defining-kbd-macro)
(let ((sep (propertize " " 'face 'doom-modeline-panel))) (let ((sep (propertize " " 'face 'doom-modeline-panel)))
@ -442,20 +415,20 @@ lines are selected, or the NxM dimensions of a block selection."
sep)))) sep))))
(make-variable-buffer-local 'anzu--state) (make-variable-buffer-local 'anzu--state)
(defun *anzu () (defsubst +doom-modeline--anzu ()
"Show the match index and total number thereof. Requires `evil-anzu'." "Show the match index and total number thereof. Requires `evil-anzu'."
(when (or (featurep 'anzu) (when (evil-ex-hl-active-p 'evil-ex-search)
(and (featurep 'evil-ex-hl-active-p)
(evil-ex-hl-active-p 'evil-ex-search)))
(propertize (propertize
(format " %s/%d%s " (format " %s/%d%s "
anzu--current-position anzu--total-matched anzu--current-position anzu--total-matched
(if anzu--overflow-p "+" "")) (if anzu--overflow-p "+" ""))
'face (if (active) 'doom-modeline-panel)))) 'face (if (active) 'doom-modeline-panel))))
(defun *evil-substitute () (defsubst +doom-modeline--evil-substitute ()
"Show number of :s matches in real time." "Show number of :s matches in real time."
(when (and (evil-ex-p) (evil-ex-hl-active-p 'evil-ex-substitute)) (when (and (evil-ex-p) (or (evil-ex-hl-active-p 'evil-ex-substitute)
(evil-ex-hl-active-p 'evil-ex-global-match)
(evil-ex-hl-active-p 'evil-ex-buffer-match)))
(propertize (propertize
(let ((range (if evil-ex-range (let ((range (if evil-ex-range
(cons (car evil-ex-range) (cadr evil-ex-range)) (cons (car evil-ex-range) (cadr evil-ex-range))
@ -468,14 +441,13 @@ lines are selected, or the NxM dimensions of a block selection."
" ... ")) " ... "))
'face (if (active) 'doom-modeline-panel)))) 'face (if (active) 'doom-modeline-panel))))
(defun *iedit () (defsubst +doom-modeline--iedit ()
"Show the number of iedit regions matches + what match you're on." "Show the number of iedit regions matches + what match you're on."
(when (and (boundp 'iedit-mode) iedit-mode) (when iedit-mode
(propertize (propertize
(let ((this-oc (let (message-log-max) (iedit-find-current-occurrence-overlay))) (let ((this-oc (let (message-log-max) (iedit-find-current-occurrence-overlay)))
(length (or (ignore-errors (length iedit-occurrences-overlays)) 0))) (length (or (ignore-errors (length iedit-occurrences-overlays)) 0)))
(format (format " %s/%s "
" %s/%s "
(save-excursion (save-excursion
(unless this-oc (unless this-oc
(iedit-prev-occurrence) (iedit-prev-occurrence)
@ -487,82 +459,68 @@ lines are selected, or the NxM dimensions of a block selection."
length)) length))
'face (if (active) 'doom-modeline-panel)))) 'face (if (active) 'doom-modeline-panel))))
(defun *media-info () (@def-modeline-segment matches
"TODO"
(or (concat (if (active) (+doom-modeline--macro-recording))
(when (featurep 'evil)
(concat (+doom-modeline--anzu)
(+doom-modeline--evil-substitute)))
(if (boundp 'iedit-mode) (+doom-modeline--iedit))
)
" %I "))
(@def-modeline-segment media-info
"TODO" "TODO"
(cond ((eq major-mode 'image-mode) (cond ((eq major-mode 'image-mode)
(let ((size (image-size (image-get-display-property) :pixels))) (let ((size (image-size (image-get-display-property) :pixels)))
(format " %dx%d " (car size) (cdr size)))))) (format " %dx%d " (car size) (cdr size))))))
(@def-modeline-segment eldoc
"TODO"
(and (boundp 'str) str))
(@def-modeline-segment bar
(+doom-modeline--make-xpm
(face-background (if (active)
'doom-modeline-bar
'doom-modeline-inactive-bar))
+doom-modeline-height
+doom-modeline-bar-width))
(@def-modeline-segment eldoc-bar
(+doom-modeline--make-xpm
(face-background 'doom-modeline-eldoc-bar)
+doom-modeline-height
+doom-modeline-bar-width))
;; ;;
;; Mode lines ;; Mode lines
;; ;;
(+doom-modeline-define 'main (@def-modeline main
`(:eval (bar matches " " buffer-info " %l:%c %p " selection-info)
(let* ((meta (concat ,(if (featurep 'evil) '(*macro-recording)) (buffer-encoding vcs major-mode flycheck))
(*anzu)
,(if (featurep 'evil) '(*evil-substitute))
(*iedit)))
(lhs (list (+doom-modeline--make-xpm (face-background (if (active)
'doom-modeline-bar
'doom-modeline-inactive-bar))
doom-modeline-height
doom-modeline-bar-width)
(if (= (length meta) 0) " %I " meta)
" "
(*buffer-info)
" %l:%c %p "
,(if (featurep 'evil) '(*selection-info))))
(rhs (list (*buffer-encoding)
(*vc)
(*major-mode)
(*flycheck)))
(mid (propertize
" " 'display `((space :align-to (- (+ right right-fringe right-margin)
,(+ 1 (string-width (format-mode-line rhs)))))))))
(list lhs mid rhs))))
(+doom-modeline-define 'eldoc (@def-modeline eldoc
`(:eval (eldoc-bar " " eldoc)
(list (list ,(when (display-graphic-p) (media-info major-mode))
`(+doom-modeline--make-xpm (face-background 'doom-modeline-eldoc-bar)
doom-modeline-height
doom-modeline-bar-width))
(and (bound-and-true-p str) str))
(propertize " " 'display `((space :align-to (1- (+ right right-fringe right-margin))))))))
(+doom-modeline-define 'minimal (@def-modeline minimal
`(:eval (bar matches " " buffer-info)
(let* ((lhs (list (+doom-modeline--make-xpm (face-background (if (active) (media-info major-mode))
'doom-modeline-bar
'doom-modeline-inactive-bar))
doom-modeline-height
doom-modeline-bar-width)
" "
(*buffer-info)))
(rhs (list (*media-info)
(*major-mode)))
(mid (propertize
" " 'display `((space :align-to (- (+ right right-fringe right-margin)
,(+ 1 (string-width (format-mode-line rhs)))))))))
(list lhs mid rhs))))
(+doom-modeline-define 'project (@def-modeline project
`(:eval (bar " " bufer-project)
(let* ((lhs (list (+doom-modeline--make-xpm (face-background (if (active) (major-mode))
'doom-modeline-bar
'doom-modeline-inactive-bar))
doom-modeline-height
doom-modeline-bar-width)
" "
(*buffer-project)))
(rhs (list (*major-mode)))
(mid (propertize
" " 'display `((space :align-to (- (+ right right-fringe right-margin)
,(+ 1 (string-width (format-mode-line rhs)))))))))
(list lhs mid rhs))))
;; ;;
(setq-default mode-line-format (+doom-modeline 'main)) (setq-default mode-line-format (doom-modeline 'main))
;; This scratch buffer is already created, and doesn't get a modeline. For the
;; love of Emacs, someone give the man a modeline!
(with-current-buffer "*scratch*"
(setq mode-line-format (doom-modeline 'main)))

View file

@ -16,8 +16,9 @@
;;(require 'iedit) ;;(require 'iedit)
;;(require 'evil-multiedit) ;;(require 'evil-multiedit)
(package! all-the-icons) (@package all-the-icons)
(package! eldoc-eval) (@package eldoc-eval)
(package! evil-anzu :needs evil) (@package powerline)
(package! powerline) (when (@featurep :feature evil)
(@package evil-anzu))