Merge from develop branch of doom-theme.

This commit is contained in:
Vincent Zhang 2018-06-13 20:43:03 +08:00
parent 21b9230fc7
commit ababcb464f

View file

@ -4,7 +4,7 @@
;; Author: Vincent Zhang <seagle0128@gmail.com> ;; Author: Vincent Zhang <seagle0128@gmail.com>
;; URL: https://github.com/seagle0128/doom-modeline ;; URL: https://github.com/seagle0128/doom-modeline
;; Version: 0.1.1 ;; Version: 0.2.0
;; Package-Requires: ((emacs "24.4") (dash "2.11.0") (all-the-icons "1.0.0") (projectile "0.10.0") (shrink-path "0.2.0") (eldoc-eval "0.1")) ;; Package-Requires: ((emacs "24.4") (dash "2.11.0") (all-the-icons "1.0.0") (projectile "0.10.0") (shrink-path "0.2.0") (eldoc-eval "0.1"))
;; Keywords: modeline mode-line doom ;; Keywords: modeline mode-line doom
@ -237,13 +237,23 @@ If STRICT-P, return nil if no project was found, otherwise return
;; anzu and evil-anzu expose current/total state that can be displayed in the ;; anzu and evil-anzu expose current/total state that can be displayed in the
;; mode-line. ;; mode-line.
(when (featurep 'evil-anzu)
(doom-modeline-add-transient-hook! #'evil-ex-start-search (require 'evil-anzu))
(when (featurep '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)
(defun doom-modeline-fix-anzu-count (positions here)
(cl-loop for (start . end) in positions
collect t into before
when (and (>= here start) (<= here end))
return (length before)
finally return 0))
(advice-add #'anzu--where-is-here :override #'doom-modeline-fix-anzu-count))
(when (featurep 'evil-anzu)
(doom-modeline-add-transient-hook! #'evil-ex-start-search (require 'evil-anzu))
;; Avoid anzu conflicts across buffers ;; Avoid anzu conflicts across buffers
(mapc #'make-variable-buffer-local (mapc #'make-variable-buffer-local
'(anzu--total-matched anzu--current-position anzu--state '(anzu--total-matched anzu--current-position anzu--state
@ -262,12 +272,18 @@ If STRICT-P, return nil if no project was found, otherwise return
"Set `doom-modeline-current-window' appropriately." "Set `doom-modeline-current-window' appropriately."
(-when-let* ((win (frame-selected-window))) (-when-let* ((win (frame-selected-window)))
(unless (minibuffer-window-active-p win) (unless (minibuffer-window-active-p win)
(setq doom-modeline-current-window win)))) (setq doom-modeline-current-window win)
(force-mode-line-update))))
(defun doom-modeline-unset-selected-window ()
(setq doom-modeline-current-window nil)
(force-mode-line-update))
(add-hook 'window-configuration-change-hook #'doom-modeline-set-selected-window) (add-hook 'window-configuration-change-hook #'doom-modeline-set-selected-window)
(add-hook 'focus-in-hook #'doom-modeline-set-selected-window) (add-hook 'focus-in-hook #'doom-modeline-set-selected-window)
(advice-add #'handle-switch-frame :after #'doom-modeline-set-selected-window) (add-hook 'focus-out-hook #'doom-modeline-unset-selected-window)
(advice-add #'select-window :after #'doom-modeline-set-selected-window) (add-hook 'doom-after-switch-window-hook #'doom-modeline-set-selected-window)
(add-hook 'doom-after-switch-frame-hook #'doom-modeline-set-selected-window)
;; ;;
;; Variables ;; Variables
@ -279,12 +295,9 @@ If STRICT-P, return nil if no project was found, otherwise return
(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)
"TODO")
(defvar doom-modeline-buffer-file-name-style 'truncate-upto-project (defvar doom-modeline-buffer-file-name-style 'truncate-upto-project
"Determines the style used by `doom-modeline-buffer-file-name'. "Determines the style used by `doom-modeline-buffer-file-name'.
Given ~/Projects/FOSS/emacs/lisp/comint.el Given ~/Projects/FOSS/emacs/lisp/comint.el
truncate-upto-project => ~/P/F/emacs/lisp/comint.el truncate-upto-project => ~/P/F/emacs/lisp/comint.el
truncate-upto-root => ~/P/F/e/lisp/comint.el truncate-upto-root => ~/P/F/e/lisp/comint.el
@ -305,26 +318,26 @@ file-name => comint.el")
;; ;;
(defgroup doom-modeline nil (defgroup doom-modeline nil
"" "TODO"
:group 'doom) :group 'faces)
(defface doom-modeline-buffer-path (defface doom-modeline-buffer-path
'((t (:inherit mode-line-emphasis :bold t))) '((t (:inherit (mode-line-emphasis bold))))
"Face used for the dirname part of the buffer path." "Face used for the dirname part of the buffer path."
:group 'doom-modeline) :group 'doom-modeline)
(defface doom-modeline-buffer-file (defface doom-modeline-buffer-file
'((t (:inherit mode-line-buffer-id))) '((t (:inherit (mode-line-buffer-id bold))))
"Face used for the filename part of the mode-line buffer path." "Face used for the filename part of the mode-line buffer path."
:group 'doom-modeline) :group 'doom-modeline)
(defface doom-modeline-buffer-modified (defface doom-modeline-buffer-modified
'((t (:inherit error :background nil :bold t))) '((t (:inherit (error bold) :background nil)))
"Face used for the 'unsaved' symbol in the mode-line." "Face used for the 'unsaved' symbol in the mode-line."
:group 'doom-modeline) :group 'doom-modeline)
(defface doom-modeline-buffer-major-mode (defface doom-modeline-buffer-major-mode
'((t (:inherit mode-line-emphasis :bold t))) '((t (:inherit (mode-line-emphasis bold))))
"Face used for the major-mode segment in the mode-line." "Face used for the major-mode segment in the mode-line."
:group 'doom-modeline) :group 'doom-modeline)
@ -340,17 +353,17 @@ file-name => comint.el")
:group 'doom-modeline) :group 'doom-modeline)
(defface doom-modeline-info (defface doom-modeline-info
`((t (:inherit success :bold t))) `((t (:inherit (success bold))))
"Face for info-level messages in the modeline. Used by `*vc'." "Face for info-level messages in the modeline. Used by `*vc'."
:group 'doom-modeline) :group 'doom-modeline)
(defface doom-modeline-warning (defface doom-modeline-warning
`((t (:inherit warning :bold t))) `((t (:inherit (warning bold))))
"Face for warnings in the modeline. Used by `*flycheck'" "Face for warnings in the modeline. Used by `*flycheck'"
:group 'doom-modeline) :group 'doom-modeline)
(defface doom-modeline-urgent (defface doom-modeline-urgent
`((t (:inherit error :bold t))) `((t (:inherit (error bold))))
"Face for errors in the modeline. Used by `*flycheck'" "Face for errors in the modeline. Used by `*flycheck'"
:group 'doom-modeline) :group 'doom-modeline)
@ -368,18 +381,10 @@ active."
"The face used for the left-most bar on the mode-line of an inactive window." "The face used for the left-most bar on the mode-line of an inactive window."
:group 'doom-modeline) :group 'doom-modeline)
(defface doom-modeline-persp '((t ()))
"The face used for persp number."
:group 'doom-modeline)
(defface doom-modeline-eyebrowse '((t ())) (defface doom-modeline-eyebrowse '((t ()))
"The face used for eyebrowse." "The face used for eyebrowse."
:group 'doom-modeline) :group 'doom-modeline)
(defface doom-modeline-bracket '((t (:inherit shadow)))
"The face used for brackets around the project."
:group 'doom-modeline)
;; ;;
;; Bootstrap ;; Bootstrap
;; ;;
@ -409,63 +414,65 @@ active."
(defsubst doom-modeline--active () (defsubst doom-modeline--active ()
(eq (selected-window) doom-modeline-current-window)) (eq (selected-window) doom-modeline-current-window))
;; Inspired from `powerline's `pl/make-xpm'. (defun doom-modeline--make-xpm (face width height)
(defmemoize doom-modeline--make-xpm (color height width) "Create an XPM bitmap. Inspired by `powerline''s `pl/make-xpm'."
"Create an XPM bitmap."
(propertize (propertize
" " 'display " " 'display
(let ((data (make-list height (make-list width 1))) (let ((data (make-list height (make-list width 1)))
(color (or color "None"))) (color (or (face-background face nil t) "None")))
(create-image (ignore-errors
(concat (create-image
(format "/* XPM */\nstatic char * percent[] = {\n\"%i %i 2 1\",\n\". c %s\",\n\" c %s\"," (concat
(length (car data)) (format "/* XPM */\nstatic char * percent[] = {\n\"%i %i 2 1\",\n\". c %s\",\n\" c %s\","
(length data) (length (car data))
color (length data)
color) color
(apply #'concat color)
(cl-loop with idx = 0 (apply #'concat
with len = (length data) (cl-loop with idx = 0
for dl in data with len = (length data)
do (cl-incf idx) for dl in data
collect do (cl-incf idx)
(concat "\"" collect
(cl-loop for d in dl (concat "\""
if (= d 0) collect (string-to-char " ") (cl-loop for d in dl
else collect (string-to-char ".")) if (= d 0) collect (string-to-char " ")
(if (eq idx len) "\"};" "\",\n"))))) else collect (string-to-char "."))
'xpm t :ascent 'center)))) (if (eq idx len) "\"};" "\",\n")))))
'xpm t :ascent 'center)))))
(defun doom-modeline-buffer-file-name () (defun doom-modeline-buffer-file-name ()
"Propertized `buffer-file-name' based on `doom-modeline-buffer-file-name-style'." "Propertized `buffer-file-name' based on `doom-modeline-buffer-file-name-style'."
(propertize (let ((buffer-file-name (or buffer-file-name ""))
(pcase doom-modeline-buffer-file-name-style (buffer-file-truename (or buffer-file-truename "")))
('truncate-upto-project (doom-modeline--buffer-file-name 'shrink)) (propertize
('truncate-upto-root (doom-modeline--buffer-file-name-truncate)) (pcase doom-modeline-buffer-file-name-style
('truncate-all (doom-modeline--buffer-file-name-truncate t)) (`truncate-upto-project (doom-modeline--buffer-file-name 'shrink))
('relative-to-project (doom-modeline--buffer-file-name-relative)) (`truncate-upto-root (doom-modeline--buffer-file-name-truncate))
('relative-from-project (doom-modeline--buffer-file-name-relative 'include-project)) (`truncate-all (doom-modeline--buffer-file-name-truncate t))
('file-name (propertize (file-name-nondirectory buffer-file-name) (`relative-to-project (doom-modeline--buffer-file-name-relative))
'face (`relative-from-project (doom-modeline--buffer-file-name-relative 'include-project))
(let ((face (or (and (buffer-modified-p) (`file-name (propertize (file-name-nondirectory buffer-file-name)
'doom-modeline-buffer-modified) 'face
(and (doom-modeline--active) (let ((face (or (and (buffer-modified-p)
'doom-modeline-buffer-file)))) 'doom-modeline-buffer-modified)
(when face `(:inherit ,face)))))) (and (active)
'help-echo buffer-file-truename)) 'doom-modeline-buffer-file))))
(when face `(:inherit ,face))))))
'help-echo buffer-file-truename)))
(defun doom-modeline--buffer-file-name-truncate (&optional truncate-tail) (defun doom-modeline--buffer-file-name-truncate (&optional truncate-tail)
"Propertized `buffer-file-name' that truncates every dir along path. "Propertized `buffer-file-name' that truncates every dir along path.
If TRUNCATE-TAIL is t also truncate the parent directory of the file." If TRUNCATE-TAIL is t also truncate the parent directory of the file."
(let ((dirs (shrink-path-prompt (file-name-directory buffer-file-truename))) (let ((dirs (shrink-path-prompt (file-name-directory buffer-file-truename)))
(active (doom-modeline--active))) (doom-modeline--active (doom-modeline--active)))
(if (null dirs) (if (null dirs)
(propertize "%b" 'face (if active 'doom-modeline-buffer-file)) (propertize "%b" 'face (if doom-modeline--active 'doom-modeline-buffer-file))
(let ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified))) (let ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified)))
(let ((dirname (car dirs)) (let ((dirname (car dirs))
(basename (cdr dirs)) (basename (cdr dirs))
(dir-faces (or modified-faces (if active 'doom-modeline-project-root-dir))) (dir-faces (or modified-faces (if doom-modeline--active 'doom-modeline-project-root-dir)))
(file-faces (or modified-faces (if active 'doom-modeline-buffer-file)))) (file-faces (or modified-faces (if doom-modeline--active 'doom-modeline-buffer-file))))
(concat (propertize (concat dirname (concat (propertize (concat dirname
(if truncate-tail (substring basename 0 1) basename) (if truncate-tail (substring basename 0 1) basename)
"/") "/")
@ -473,25 +480,21 @@ If TRUNCATE-TAIL is t also truncate the parent directory of the file."
(propertize (file-name-nondirectory buffer-file-name) (propertize (file-name-nondirectory buffer-file-name)
'face (if file-faces `(:inherit ,file-faces))))))))) 'face (if file-faces `(:inherit ,file-faces)))))))))
(defun doom-modeline-maybe-icon-octicon (&rest args)
(when (and (display-graphic-p) (not (eq system-type 'windows-nt)))
(apply 'all-the-icons-octicon args)))
(defun doom-modeline-maybe-icon-faicon (&rest args)
(when (and (display-graphic-p) (not (eq system-type 'windows-nt)))
(apply 'all-the-icons-faicon args)))
(defun doom-modeline-maybe-icon-material (&rest args)
(when (and (display-graphic-p) (not (eq system-type 'windows-nt)))
(apply 'all-the-icons-material args)))
(defmemoize doom-modeline-file-relative-name (filename directory) (defmemoize doom-modeline-file-relative-name (filename directory)
(file-relative-name filename directory)) (file-relative-name filename directory))
(defun doom-modeline--buffer-file-name-relative (&optional include-project)
"Propertized `buffer-file-name' showing directories relative to project's root only."
(let ((root (doom-modeline-project-root))
(active (doom-modeline--active)))
(if (null root)
(propertize "%b" 'face (if active 'doom-modeline-buffer-file))
(let* ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified))
(relative-dirs (file-relative-name (file-name-directory buffer-file-truename)
(if include-project (concat root "../") root)))
(relative-faces (or modified-faces (if active 'doom-modeline-buffer-path)))
(file-faces (or modified-faces (if active 'doom-modeline-buffer-file))))
(if (equal "./" relative-dirs) (setq relative-dirs ""))
(concat (propertize relative-dirs 'face (if relative-faces `(:inherit ,relative-faces)))
(propertize (file-name-nondirectory buffer-file-truename)
'face (if file-faces `(:inherit ,file-faces))))))))
(defmemoize doom-modeline-abbreviate-file-name (file-name) (defmemoize doom-modeline-abbreviate-file-name (file-name)
(abbreviate-file-name file-name)) (abbreviate-file-name file-name))
@ -500,16 +503,34 @@ If TRUNCATE-TAIL is t also truncate the parent directory of the file."
(file-name-directory file-name) (file-name-directory file-name)
file-name)) file-name))
(defun doom-modeline--buffer-file-name-relative (&optional include-project)
"Propertized `buffer-file-name' showing directories relative to project's root only."
(let ((root (doom-modeline-project-root))
(active (doom-modeline--active)))
(if (null root)
(propertize "%b" 'face (if active 'doom-modeline-buffer-file))
(let* ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified))
(true-filename (file-truename buffer-file-name))
(relative-dirs (file-relative-name (file-name-directory true-filename)
(if include-project (concat root "../") root)))
(relative-faces (or modified-faces (if active 'doom-modeline-buffer-path)))
(file-faces (or modified-faces (if active 'doom-modeline-buffer-file))))
(if (equal "./" relative-dirs) (setq relative-dirs ""))
(concat (propertize relative-dirs 'face (if relative-faces `(:inherit ,relative-faces)))
(propertize (file-name-nondirectory true-filename)
'face (if file-faces `(:inherit ,file-faces))))))))
(defun doom-modeline--buffer-file-name (truncate-project-root-parent) (defun doom-modeline--buffer-file-name (truncate-project-root-parent)
"Propertized `buffer-file-name'. "Propertized `buffer-file-name'.
If TRUNCATE-PROJECT-ROOT-PARENT is t space will be saved by truncating it down If TRUNCATE-PROJECT-ROOT-PARENT is t space will be saved by truncating it down
fish-shell style. fish-shell style.
Example: Example:
~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el" ~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el"
(let* ((project-root (doom-modeline-project-root)) (let* ((project-root (doom-modeline-project-root))
(file-name-split (shrink-path-file-mixed project-root (file-name-split (shrink-path-file-mixed project-root
(file-name-directory buffer-file-truename) (file-name-directory buffer-file-name)
buffer-file-truename)) buffer-file-name))
(active (doom-modeline--active))) (active (doom-modeline--active)))
(if (null file-name-split) (if (null file-name-split)
(propertize "%b" 'face (if active 'doom-modeline-buffer-file)) (propertize "%b" 'face (if active 'doom-modeline-buffer-file))
@ -533,10 +554,9 @@ Example:
;; ;;
;; Segments ;; buffer information
;; ;;
(doom-modeline-def-segment! buffer-default-directory (doom-modeline-def-segment! buffer-default-directory
"Displays `default-directory'. This is for special buffers like the scratch "Displays `default-directory'. This is for special buffers like the scratch
buffer where knowing the current project directory is important." buffer where knowing the current project directory is important."
@ -550,42 +570,39 @@ buffer where knowing the current project directory is important."
(propertize (concat " " (abbreviate-file-name default-directory)) (propertize (concat " " (abbreviate-file-name default-directory))
'face face)))) 'face face))))
;; ;;
(doom-modeline-def-segment! buffer-info (doom-modeline-def-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)."
(concat (concat (cond (buffer-read-only
(cond (buffer-read-only (concat (doom-modeline-maybe-icon-octicon
(concat (doom-modeline-maybe-icon-octicon "lock"
"lock" :face 'doom-modeline-warning
:face 'doom-modeline-warning :v-adjust -0.05)
:v-adjust -0.05) " "))
" ")) ((buffer-modified-p)
((buffer-modified-p) (concat (doom-modeline-maybe-icon-faicon
(concat (doom-modeline-maybe-icon-faicon "floppy-o"
"floppy-o" :face 'doom-modeline-buffer-modified
:face 'doom-modeline-buffer-modified :v-adjust -0.0575)
:v-adjust -0.0575) " "))
" ")) ((and buffer-file-name
((and buffer-file-name (not (file-exists-p buffer-file-name)))
(not (file-exists-p buffer-file-name))) (concat (doom-modeline-maybe-icon-octicon
(concat (doom-modeline-maybe-icon-octicon "circle-slash"
"circle-slash" :face 'doom-modeline-urgent
:face 'doom-modeline-urgent :v-adjust -0.05)
:v-adjust -0.05) " "))
" ")) ((buffer-narrowed-p)
((buffer-narrowed-p) (concat (doom-modeline-maybe-icon-octicon
(concat (doom-modeline-maybe-icon-octicon "fold"
"fold" :face 'doom-modeline-warning
:face 'doom-modeline-warning :v-adjust -0.05)
:v-adjust -0.05) " ")))
" "))) (if buffer-file-name
(if buffer-file-name (doom-modeline-buffer-file-name)
(doom-modeline-buffer-file-name) "%b")))
"%b")))
;;
(doom-modeline-def-segment! buffer-info-simple (doom-modeline-def-segment! buffer-info-simple
"Display only the current buffer's name, but with fontification." "Display only the current buffer's name, but with fontification."
(propertize (propertize
@ -608,6 +625,9 @@ directory, the file name, and its state (modified, read-only or non-existent)."
" ")) " "))
;; ;;
;; major-mode
;;
(doom-modeline-def-segment! major-mode (doom-modeline-def-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
@ -622,56 +642,61 @@ directory, the file name, and its state (modified, read-only or non-existent)."
'face (if (doom-modeline--active) 'doom-modeline-buffer-major-mode))) 'face (if (doom-modeline--active) 'doom-modeline-buffer-major-mode)))
(defun doom-modeline-maybe-icon-octicon (&rest args)
(when (and (display-graphic-p) (not (eq system-type 'windows-nt)))
(apply 'all-the-icons-octicon args)))
(defun doom-modeline-maybe-icon-faicon (&rest args)
(when (and (display-graphic-p) (not (eq system-type 'windows-nt)))
(apply 'all-the-icons-faicon args)))
(defun doom-modeline-maybe-icon-material (&rest args)
(when (and (display-graphic-p) (not (eq system-type 'windows-nt)))
(apply 'all-the-icons-material args)))
;; ;;
;; vcs
;;
(defvar-local doom-modeline--vcs nil)
(defun doom-modeline--update-vcs ()
(setq doom-modeline--vcs
(when (and vc-mode buffer-file-name)
(let* ((backend (vc-backend buffer-file-name))
(state (vc-state buffer-file-name backend)))
(let ((face 'mode-line-inactive)
(active (doom-modeline--active))
(all-the-icons-default-adjust -0.1))
(concat " "
(cond ((memq state '(edited added))
(if active (setq face 'doom-modeline-info))
(doom-modeline-maybe-icon-octicon
"git-compare"
:face face
:v-adjust -0.05))
((eq state 'needs-merge)
(if active (setq face 'doom-modeline-info))
(doom-modeline-maybe-icon-octicon "git-merge" :face face))
((eq state 'needs-update)
(if active (setq face 'doom-modeline-warning))
(doom-modeline-maybe-icon-octicon "arrow-down" :face face))
((memq state '(removed conflict unregistered))
(if active (setq face 'doom-modeline-urgent))
(doom-modeline-maybe-icon-octicon "alert" :face face))
(t
(if active (setq face 'font-lock-doc-face))
(doom-modeline-maybe-icon-octicon
"git-branch"
:face face
:v-adjust -0.05)))
" "
(propertize (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2))
'face (if active face))
" "))))))
(add-hook 'after-save-hook #'doom-modeline--update-vcs)
(add-hook 'find-file-hook #'doom-modeline--update-vcs t)
(doom-modeline-def-segment! vcs (doom-modeline-def-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) doom-modeline--vcs)
(let* ((backend (vc-backend buffer-file-name))
(state (vc-state buffer-file-name backend)))
(let ((face 'mode-line-inactive)
(active (doom-modeline--active))
(all-the-icons-default-adjust -0.1))
(concat (if (display-graphic-p) " ")
(cond ((memq state '(edited added))
(if active (setq face 'doom-modeline-info))
(doom-modeline-maybe-icon-octicon
"git-compare"
:face face
:v-adjust -0.05))
((eq state 'needs-merge)
(if active (setq face 'doom-modeline-info))
(doom-modeline-maybe-icon-octicon "git-merge" :face face))
((eq state 'needs-update)
(if active (setq face 'doom-modeline-warning))
(doom-modeline-maybe-icon-octicon "arrow-down" :face face))
((memq state '(removed conflict unregistered))
(if active (setq face 'doom-modeline-urgent))
(doom-modeline-maybe-icon-octicon "alert" :face face))
(t
(if active (setq face 'font-lock-doc-face))
(doom-modeline-maybe-icon-octicon
"git-branch"
:face face
:v-adjust -0.05)))
" "
(propertize (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2))
'face (if active face))
" ")))))
;; ;;
;; flycheck
;;
(defvar doom-modeline-vspc
(propertize " " 'face 'variable-pitch)
"TODO")
(defun doom-modeline-icon (icon &optional text face voffset) (defun doom-modeline-icon (icon &optional text face voffset)
"Displays an ICON with FACE, followed by TEXT. Uses "Displays an ICON with FACE, followed by TEXT. Uses
`all-the-icons-material' to fetch the icon." `all-the-icons-material' to fetch the icon."
@ -680,58 +705,75 @@ directory, the file name, and its state (modified, read-only or non-existent)."
(concat (concat
(doom-modeline-maybe-icon-material icon :face face :height 1.1 :v-adjust (or voffset -0.2)) (doom-modeline-maybe-icon-material icon :face face :height 1.1 :v-adjust (or voffset -0.2))
(if text doom-modeline-vspc))) (if text doom-modeline-vspc)))
(when text (if text (propertize text 'face face))
(propertize text 'face face))
(if vc-mode " " " "))) (if vc-mode " " " ")))
(defvar-local doom-modeline--flycheck nil)
(add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck-segment)
(add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck-segment)
(defun doom-modeline-update-flycheck-segment (&optional status)
(setq doom-modeline--flycheck
(pcase status
('finished (if flycheck-current-errors
(let-alist (flycheck-count-errors flycheck-current-errors)
(let ((sum (+ (or .error 0) (or .warning 0))))
(doom-modeline-icon "do_not_disturb_alt"
(number-to-string sum)
(if .error 'doom-modeline-urgent 'doom-modeline-warning)
-0.25)))
(doom-modeline-icon "check" nil 'doom-modeline-info)))
('running (doom-modeline-icon "access_time" nil 'font-lock-doc-face -0.25))
('no-checker (doom-modeline-icon "sim_card_alert" "-" 'font-lock-doc-face))
('errored (doom-modeline-icon "sim_card_alert" "Error" 'doom-modeline-urgent))
('interrupted (doom-modeline-icon "pause" "Interrupted" 'font-lock-doc-face)))))
(doom-modeline-def-segment! flycheck (doom-modeline-def-segment! flycheck
"Displays color-coded flycheck error status in the current buffer with pretty "Displays color-coded flycheck error status in the current buffer with pretty
icons." icons."
(when (boundp 'flycheck-last-status-change) doom-modeline--flycheck)
(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-modeline-icon "do_not_disturb_alt"
(number-to-string sum)
(if .error 'doom-modeline-urgent 'doom-modeline-warning)
-0.25)))
(doom-modeline-icon "check" nil 'doom-modeline-info)))
('running (doom-modeline-icon "access_time" nil 'font-lock-doc-face -0.25))
('no-checker (doom-modeline-icon "sim_card_alert" "-" 'font-lock-doc-face))
('errored (doom-modeline-icon "sim_card_alert" "Error" 'doom-modeline-urgent))
('interrupted (doom-modeline-icon "pause" "Interrupted" 'font-lock-doc-face)))))
;; ('interrupted (doom-modeline-icon "x" "Interrupted" 'font-lock-doc-face)))))
;; ;;
;; selection-info
;;
(defsubst doom-modeline-column (pos) (defsubst doom-modeline-column (pos)
(save-excursion (goto-char pos) (save-excursion (goto-char pos)
(current-column))) (current-column)))
(defvar-local doom-modeline-enable-word-count nil
"If non-nil, a word count will be added to the selection-info modeline
segment.")
(doom-modeline-def-segment! selection-info (doom-modeline-def-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 (doom-modeline--active) (or mark-active (eq evil-state 'visual))) (when (and mark-active (doom-modeline--active))
(let ((reg-beg (region-beginning)) (cl-destructuring-bind (beg . end)
(reg-end (region-end))) (if (eq evil-state 'visual)
(cons evil-visual-beginning evil-visual-end)
(cons (region-beginning) (region-end)))
(propertize (propertize
(let ((lines (count-lines reg-beg (min (1+ reg-end) (point-max))))) (let ((lines (count-lines beg (min end (point-max)))))
(cond ((or (bound-and-true-p rectangle-mark-mode) (concat (cond ((or (bound-and-true-p rectangle-mark-mode)
(eq 'block evil-visual-selection)) (eq 'block evil-visual-selection))
(let ((cols (abs (- (doom-modeline-column reg-end) (let ((cols (abs (- (doom-column end)
(doom-modeline-column reg-beg))))) (doom-column beg)))))
(format "%dx%dB" lines cols))) (format "%dx%dB" lines cols)))
((eq 'line evil-visual-selection) ((eq evil-visual-selection 'line)
(format "%dL" lines)) (format "%dL" lines))
((> lines 1) ((> lines 1)
(format "%dC %dL" (- (1+ reg-end) reg-beg) lines)) (format "%dC %dL" (- end beg) lines))
(t ((format "%dC" (- end beg))))
(format "%dC" (- (1+ reg-end) reg-beg))))) (when doom-modeline-enable-word-count
(format " %dW" (count-words beg end)))))
'face 'doom-modeline-highlight)))) 'face 'doom-modeline-highlight))))
;; ;;
;; matches (anzu, evil-substitute, iedit, macro)
;;
(defun doom-modeline--macro-recording () (defun doom-modeline--macro-recording ()
"Display current Emacs or evil macro being recorded." "Display current Emacs or evil macro being recorded."
(when (and (doom-modeline--active) (or defining-kbd-macro executing-kbd-macro)) (when (and (doom-modeline--active) (or defining-kbd-macro executing-kbd-macro))
@ -744,13 +786,12 @@ lines are selected, or the NxM dimensions of a block selection."
sep sep
(doom-modeline-maybe-icon-octicon "triangle-right" (doom-modeline-maybe-icon-octicon "triangle-right"
:face 'doom-modeline-panel :face 'doom-modeline-panel
:v-adjust -0.05)) :v-adjust -0.05)
sep))) sep))))
(defsubst doom-modeline--anzu () (defsubst doom-modeline--anzu ()
"Show the match index and total number thereof. Requires `anzu', also "Show the match index and total number thereof. Requires `anzu', also
`evil-anzu' if using `evil-mode' for compatibility with `evil-search'." `evil-anzu' if using `evil-mode' for compatibility with `evil-search'."
(setq anzu-cons-mode-line-p nil)
(when (and anzu--state (not iedit-mode)) (when (and anzu--state (not iedit-mode))
(propertize (propertize
(let ((here anzu--current-position) (let ((here anzu--current-position)
@ -814,61 +855,50 @@ with `evil-ex-substitute', and/or 4. The number of active `iedit' regions."
(or (and (not (equal meta "")) meta) (or (and (not (equal meta "")) meta)
(if buffer-file-name " %I ")))) (if buffer-file-name " %I "))))
;; TODO Include other information ;;
;; media-info
;;
(doom-modeline-def-segment! media-info (doom-modeline-def-segment! media-info
"Metadata regarding the current file, such as dimensions for images." "Metadata regarding the current file, such as dimensions for images."
;; TODO Include other information
(cond ((eq major-mode 'image-mode) (cond ((eq major-mode 'image-mode)
(cl-destructuring-bind (width . height) (cl-destructuring-bind (width . height)
(image-size (image-get-display-property) :pixels) (image-size (image-get-display-property) :pixels)
(format " %dx%d " width height))))) (format " %dx%d " width height)))))
;;
;; bar
;;
(defvar doom-modeline--bar-active nil)
(defvar doom-modeline--bar-inactive nil)
(doom-modeline-def-segment! bar (doom-modeline-def-segment! bar
"The bar regulates the height of the mode-line in GUI Emacs. "The bar regulates the height of the mode-line in GUI Emacs.
Returns \"\" to not break --no-window-system." Returns \"\" to not break --no-window-system."
(if (display-graphic-p) (if window-system
(doom-modeline--make-xpm (if (doom-modeline--active)
(face-background (if (doom-modeline--active) doom-modeline--bar-active
'doom-modeline-bar doom-modeline--bar-inactive)
'doom-modeline-inactive-bar)
nil t)
doom-modeline-height
doom-modeline-bar-width)
"")) ""))
(defun doom-modeline-eyebrowse-number () (when (>= emacs-major-version 26)
(when (and (bound-and-true-p eyebrowse-mode) (add-variable-watcher
(< 1 (length (eyebrowse--get 'window-configs)))) 'doom-modeline-height
(let* ((num (eyebrowse--get 'current-slot)) (lambda (_sym val op _where)
(tag (when num (nth 2 (assoc num (eyebrowse--get 'window-configs))))) (when (and (eq op 'set) (integerp val))
(str (if (and tag (< 0 (length tag))) (doom-modeline-refresh-bars doom-modeline-bar-width val))))
tag
(when num (int-to-string num)))))
str)))
(defun doom-modeline-window-bottom-left-p () (add-variable-watcher
(let* ((edges (window-edges)) 'doom-modeline-bar-width
(minibuffer-edges (window-edges (minibuffer-window)))) (lambda (_sym val op _where)
(and (eq 0 (car edges)) (when (and (eq op 'set) (integerp val))
(eq (nth 3 edges) (doom-modeline-refresh-bars val doom-modeline-height)))))
(cadr minibuffer-edges)))))
(doom-modeline-def-segment! persp-number
"The persp number."
(when (featurep 'persp-mode)
(when (doom-modeline-window-bottom-left-p)
(-when-let* ((persp (get-current-persp)))
(propertize
(concat
(number-to-string
(+ 1
(cl-position
(persp-name persp)
(persp-names-current-frame-fast-ordered))))
"."
(or (doom-modeline-eyebrowse-number) "1")
" ")
'face 'doom-modeline-persp)))))
;;
;; window number
;;
(advice-add #'window-numbering-install-mode-line :override #'ignore) (advice-add #'window-numbering-install-mode-line :override #'ignore)
(advice-add #'window-numbering-clear-mode-line :override #'ignore) (advice-add #'window-numbering-clear-mode-line :override #'ignore)
@ -881,6 +911,10 @@ Returns \"\" to not break --no-window-system."
'doom-modeline-inactive-bar)) 'doom-modeline-inactive-bar))
"")) ""))
;;
;; workspace-number
;;
(declare-function eyebrowse--get 'eyebrowse) (declare-function eyebrowse--get 'eyebrowse)
(doom-modeline-def-segment! workspace-number (doom-modeline-def-segment! workspace-number
"The current workspace name or number. Requires `eyebrowse-mode' to be "The current workspace name or number. Requires `eyebrowse-mode' to be
@ -920,32 +954,63 @@ enabled."
(media-info major-mode)) (media-info major-mode))
;; ;;
;; Bootstrap ;; Hooks
;; ;;
(defun doom-modeline-refresh-bars (&optional width height)
(setq doom-modeline--bar-active
(doom-modeline--make-xpm 'doom-modeline-bar
(or width doom-modeline-bar-width)
(or height doom-modeline-height))
doom-modeline--bar-inactive
(doom-modeline--make-xpm 'doom-modeline-inactive-bar
(or width doom-modeline-bar-width)
(or height doom-modeline-height))))
;;;###autoload ;;;###autoload
(defun doom-modeline-init () (defun doom-modeline-init ()
"Set the default modeline." ;; Create bars
(doom-modeline-set-modeline 'main t) (doom-modeline-refresh-bars)
(unless after-init-time
;; This scratch and messages buffer is already created and doesn't get a ;; These buffers are already created and don't get modelines. For the love
;; modeline. ;; of Emacs, someone give the man a modeline!
(with-current-buffer "*Messages*" (dolist (bname '("*scratch*" "*Messages*"))
(doom-modeline-set-modeline 'main)) (with-current-buffer bname
(with-current-buffer "*scratch*" (doom-modeline-set-modeline 'main)))))
(doom-modeline-set-modeline 'main)))
(defun doom-modeline-set-special-modeline () (defun doom-modeline-set-special-modeline ()
"Set the special modeline."
(doom-modeline-set-modeline 'special)) (doom-modeline-set-modeline 'special))
(defun doom-modeline-set-media-modeline () (defun doom-modeline-set-media-modeline ()
"Set the media modeline."
(doom-modeline-set-modeline 'media)) (doom-modeline-set-modeline 'media))
(add-hook 'image-mode-hook #'doom-modeline-set-media-modeline) (defun doom-modeline-set-project-modeline ()
(add-hook 'org-src-mode-hook #'doom-modeline-set-special-modeline) (doom-modeline-set-modeline 'project))
(add-hook 'circe-mode-hook #'doom-modeline-set-special-modeline)
;;
;; Bootstrap
;;
(doom-modeline-set-modeline 'main t) ; set default modeline
;; (add-hook 'doom-load-theme-hook #'doom-modeline-init)
;; (add-hook 'doom-scratch-buffer-hook #'doom-modeline-set-special-modeline)
;; (add-hook 'doom-dashboard-mode-hook #'doom-modeline-set-project-modeline)
(add-hook 'image-mode-hook #'doom-modeline-set-media-modeline)
(add-hook 'circe-mode-hook #'doom-modeline-set-special-modeline)
;; Ensure modeline is inactive when Emacs is unfocused (and active otherwise)
(defvar doom-modeline-remap-face-cookie nil)
(defun doom-modeline-focus ()
(when doom-modeline-remap-face-cookie
(require 'face-remap)
(face-remap-remove-relative doom-modeline-remap-face-cookie)))
(defun doom-modeline-unfocus ()
(setq doom-modeline-remap-face-cookie (face-remap-add-relative 'mode-line 'mode-line-inactive)))
(add-hook 'focus-in-hook #'doom-modeline-focus)
(add-hook 'focus-out-hook #'doom-modeline-unfocus)
(provide 'doom-modeline) (provide 'doom-modeline)