doom-modeline-segments.el (137196B)
1 ;;; doom-modeline-segments.el --- The segments for doom-modeline -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2018-2024 Vincent Zhang 4 5 ;; This file is not part of GNU Emacs. 6 7 ;; 8 ;; This program is free software; you can redistribute it and/or modify 9 ;; it under the terms of the GNU General Public License as published by 10 ;; the Free Software Foundation, either version 3 of the License, or 11 ;; (at your option) any later version. 12 ;; 13 ;; This program is distributed in the hope that it will be useful, 14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 ;; GNU General Public License for more details. 17 ;; 18 ;; You should have received a copy of the GNU General Public License 19 ;; along with this program. If not, see <https://www.gnu.org/licenses/>. 20 ;; 21 22 ;;; Commentary: 23 ;; 24 ;; The segments for doom-modeline. 25 ;; Use `doom-modeline-def-segment' to create a new segment. 26 ;; 27 28 ;;; Code: 29 30 (require 'doom-modeline-core) 31 (require 'doom-modeline-env) 32 (eval-when-compile 33 (require 'cl-lib) 34 (require 'seq) 35 (require 'subr-x)) 36 37 38 ;; 39 ;; Externals 40 ;; 41 42 (defvar Info-current-file) 43 (defvar Info-current-node) 44 (defvar Info-mode-line-node-keymap) 45 (defvar anzu--cached-count) 46 (defvar anzu--current-position) 47 (defvar anzu--overflow-p) 48 (defvar anzu--state) 49 (defvar anzu--total-matched) 50 (defvar anzu-cons-mode-line-p) 51 (defvar aw-keys) 52 (defvar battery-echo-area-format) 53 (defvar battery-load-critical) 54 (defvar battery-mode-line-format) 55 (defvar battery-mode-line-limit) 56 (defvar battery-status-function) 57 (defvar boon-command-state) 58 (defvar boon-insert-state) 59 (defvar boon-off-state) 60 (defvar boon-special-state) 61 (defvar display-time-string) 62 (defvar edebug-execution-mode) 63 (defvar eglot--managed-mode) 64 (defvar erc-modified-channels-alist) 65 (defvar evil-ex-active-highlights-alist) 66 (defvar evil-ex-argument) 67 (defvar evil-ex-range) 68 (defvar evil-mc-frozen) 69 (defvar evil-state) 70 (defvar evil-visual-beginning) 71 (defvar evil-visual-end) 72 (defvar evil-visual-selection) 73 (defvar flycheck--automatically-enabled-checkers) 74 (defvar flycheck-current-errors) 75 (defvar flycheck-mode-menu-map) 76 (defvar flymake--mode-line-format) 77 (defvar flymake--state) 78 (defvar flymake-menu) 79 (defvar gnus-newsrc-alist) 80 (defvar gnus-newsrc-hashtb) 81 (defvar grip--process) 82 (defvar helm--mode-line-display-prefarg) 83 (defvar iedit-occurrences-overlays) 84 (defvar kele-menu-map) 85 (defvar meow--indicator) 86 (defvar minions-mode-line-lighter) 87 (defvar minions-mode-line-minor-modes-map) 88 (defvar mlscroll-minimum-current-width) 89 (defvar mlscroll-right-align) 90 (defvar mu4e--modeline-item) 91 (defvar mu4e-alert-mode-line) 92 (defvar mu4e-alert-modeline-formatter) 93 (defvar mu4e-modeline-mode) 94 (defvar nyan-minimum-window-width) 95 (defvar objed--obj-state) 96 (defvar objed--object) 97 (defvar objed-modeline-setup-func) 98 (defvar persp-nil-name) 99 (defvar phi-replace--mode-line-format) 100 (defvar phi-search--overlays) 101 (defvar phi-search--selection) 102 (defvar phi-search-mode-line-format) 103 (defvar poke-line-minimum-window-width) 104 (defvar rcirc-activity) 105 (defvar sml-modeline-len) 106 (defvar symbol-overlay-keywords-alist) 107 (defvar symbol-overlay-temp-symbol) 108 (defvar text-scale-mode-amount) 109 (defvar tracking-buffers) 110 (defvar winum-auto-setup-mode-line) 111 (defvar xah-fly-insert-state-p) 112 113 (declare-function anzu--reset-status "ext:anzu") 114 (declare-function anzu--where-is-here "ext:anzu") 115 (declare-function async-inject-variables "ext:async") 116 (declare-function async-start "ext:async") 117 (declare-function avy-traverse "ext:avy") 118 (declare-function avy-tree "ext:avy") 119 (declare-function aw-update "ext:ace-window") 120 (declare-function aw-window-list "ext:ace-window") 121 (declare-function battery-format "battery") 122 (declare-function battery-update "battery") 123 (declare-function boon-modeline-string "ext:boon") 124 (declare-function boon-state-string "ext:boon") 125 (declare-function cider--connection-info "ext:cider") 126 (declare-function cider-connected-p "ext:cider") 127 (declare-function cider-current-repl "ext:cider") 128 (declare-function cider-jack-in "ext:cider") 129 (declare-function cider-quit "ext:cider") 130 (declare-function citre-mode "ext:citre-basic-tools") 131 (declare-function compilation-goto-in-progress-buffer "compile") 132 (declare-function dap--cur-session "ext:dap-mode") 133 (declare-function dap--debug-session-name "ext:dap-mode") 134 (declare-function dap--debug-session-state "ext:dap-mode") 135 (declare-function dap--session-running "ext:dap-mode") 136 (declare-function dap-debug-recent "ext:dap-mode") 137 (declare-function dap-disconnect "ext:dap-mode") 138 (declare-function dap-hydra "ext:dap-hydra") 139 (declare-function edebug-help "edebug") 140 (declare-function edebug-next-mode "edebug") 141 (declare-function edebug-stop "edebug") 142 (declare-function eglot "ext:eglot") 143 (declare-function eglot--major-modes "ext:eglot" t t) 144 (declare-function eglot--project-nickname "ext:eglot" t t) 145 (declare-function eglot-clear-status "ext:eglot") 146 (declare-function eglot-current-server "ext:eglot") 147 (declare-function eglot-events-buffer "ext:eglot") 148 (declare-function eglot-forget-pending-continuations "ext:eglot") 149 (declare-function eglot-managed-p "ext:glot") 150 (declare-function eglot-reconnect "ext:eglot") 151 (declare-function eglot-shutdown "ext:eglot") 152 (declare-function eglot-stderr-buffer "ext:eglot") 153 (declare-function erc-switch-to-buffer "erc") 154 (declare-function erc-track-switch-buffer "erc-track") 155 (declare-function evil-delimited-arguments "ext:evil-common") 156 (declare-function evil-emacs-state-p "ext:evil-states" t t) 157 (declare-function evil-force-normal-state "ext:evil-commands" t t) 158 (declare-function evil-insert-state-p "ext:evil-states" t t) 159 (declare-function evil-motion-state-p "ext:evil-states" t t) 160 (declare-function evil-normal-state-p "ext:evil-states" t t) 161 (declare-function evil-operator-state-p "ext:evil-states" t t) 162 (declare-function evil-replace-state-p "ext:evil-states" t t) 163 (declare-function evil-state-property "ext:evil-common") 164 (declare-function evil-visual-state-p "ext:evil-states" t t) 165 (declare-function eyebrowse--get "ext:eyebrowse") 166 (declare-function face-remap-remove-relative "face-remap") 167 (declare-function fancy-narrow-active-p "ext:fancy-narrow") 168 (declare-function flycheck-buffer "ext:flycheck") 169 (declare-function flycheck-count-errors "ext:flycheck") 170 (declare-function flycheck-error-level-compilation-level "ext:flycheck") 171 (declare-function flycheck-list-errors "ext:flycheck") 172 (declare-function flycheck-next-error "ext:flycheck") 173 (declare-function flycheck-previous-error "ext:flycheck") 174 (declare-function flymake--diag-type "ext:flymake" t t) 175 (declare-function flymake--handle-report "ext:flymake") 176 (declare-function flymake--lookup-type-property "ext:flymake") 177 (declare-function flymake--state-diags "ext:flymake" t t) 178 (declare-function flymake-disabled-backends "ext:flymake") 179 (declare-function flymake-goto-next-error "ext:flymake") 180 (declare-function flymake-goto-prev-error "ext:flymake") 181 (declare-function flymake-reporting-backends "ext:flymake") 182 (declare-function flymake-running-backends "ext:flymake") 183 (declare-function flymake-show-buffer-diagnostics "ext:flymake") 184 (declare-function flymake-show-buffer-diagnostics "ext:flymake") 185 (declare-function flymake-start "ext:flymake") 186 (declare-function follow-all-followers "follow") 187 (declare-function gnus-demon-add-handler "gnus-demon") 188 (declare-function grip--preview-url "ext:grip-mode") 189 (declare-function grip-browse-preview "ext:grip-mode") 190 (declare-function grip-restart-preview "ext:grip-mode") 191 (declare-function grip-stop-preview "ext:grip-mode") 192 (declare-function helm-candidate-number-at-point "ext:helm-core") 193 (declare-function helm-get-candidate-number "ext:helm-core") 194 (declare-function iedit-find-current-occurrence-overlay "ext:iedit-lib") 195 (declare-function iedit-prev-occurrence "ext:iedit-lib") 196 (declare-function image-get-display-property "image-mode") 197 (declare-function jsonrpc--request-continuations "ext:jsonrpc" t t) 198 (declare-function jsonrpc-last-error "ext:jsonrpc" t t) 199 (declare-function kele-current-context-name "ext:kele") 200 (declare-function kele-current-namespace "ext:kele") 201 (declare-function lsp--workspace-print "ext:lsp-mode") 202 (declare-function lsp-describe-session "ext:lsp-mode") 203 (declare-function lsp-workspace-folders-open "ext:lsp-mode") 204 (declare-function lsp-workspace-restart "ext:lsp-mode") 205 (declare-function lsp-workspace-shutdown "ext:lsp-mode") 206 (declare-function lsp-workspaces "ext:lsp-mode") 207 (declare-function lv-message "ext:lv") 208 (declare-function mc/num-cursors "ext:multiple-cursors-core") 209 (declare-function meow--current-state "ext:meow") 210 (declare-function meow-beacon-mode-p "ext:meow") 211 (declare-function meow-insert-mode-p "ext:meow") 212 (declare-function meow-keypad-mode-p "ext:meow") 213 (declare-function meow-motion-mode-p "ext:meow") 214 (declare-function meow-normal-mode-p "ext:meow") 215 (declare-function minions--prominent-modes "ext:minions") 216 (declare-function mlscroll-mode-line "ext:mlscroll") 217 (declare-function mu4e--modeline-string "ext:mu4e-modeline") 218 (declare-function mu4e-alert-default-mode-line-formatter "ext:mu4e-alert") 219 (declare-function mu4e-alert-enable-mode-line-display "ext:mu4e-alert") 220 (declare-function nyan-create "ext:nyan-mode") 221 (declare-function org-edit-src-save "ext:org-src") 222 (declare-function parrot-create "ext:parrot") 223 (declare-function pdf-cache-number-of-pages "ext:pdf-cache" t t) 224 (declare-function persp-add-buffer "ext:persp-mode") 225 (declare-function persp-contain-buffer-p "ext:persp-mode") 226 (declare-function persp-switch "ext:persp-mode") 227 (declare-function phi-search--initialize "ext:phi-search") 228 (declare-function poke-line-create "ext:poke-line") 229 (declare-function popup-create "ext:popup") 230 (declare-function popup-delete "ext:popup") 231 (declare-function rcirc-next-active-buffer "rcirc") 232 (declare-function rcirc-short-buffer-name "rcirc") 233 (declare-function rcirc-switch-to-server-buffer "rcirc") 234 (declare-function rcirc-window-configuration-change "rcirc") 235 (declare-function rime--should-enable-p "ext:rime") 236 (declare-function rime--should-inline-ascii-p "ext:rime") 237 (declare-function sml-modeline-create "ext:sml-modeline") 238 (declare-function svg-circle "svg") 239 (declare-function svg-create "svg") 240 (declare-function svg-image "svg") 241 (declare-function svg-line "svg") 242 (declare-function symbol-overlay-assoc "ext:symbol-overlay") 243 (declare-function symbol-overlay-get-list "ext:symbol-overlay") 244 (declare-function symbol-overlay-get-symbol "ext:symbol-overlay") 245 (declare-function symbol-overlay-rename "ext:symbol-overlay") 246 (declare-function tab-bar--current-tab "tab-bar") 247 (declare-function tab-bar--current-tab-index "tab-bar") 248 (declare-function tracking-next-buffer "ext:tracking") 249 (declare-function tracking-previous-buffer "ext:tracking") 250 (declare-function tracking-shorten "ext:tracking") 251 (declare-function undo-tree-redo-1 "ext:undo-tree") 252 (declare-function undo-tree-undo-1 "ext:undo-tree") 253 (declare-function warning-numeric-level "warnings") 254 (declare-function window-numbering-clear-mode-line "ext:window-numbering") 255 (declare-function window-numbering-get-number-string "ext:window-numbering") 256 (declare-function window-numbering-install-mode-line "ext:window-numbering") 257 (declare-function winum--clear-mode-line "ext:winum") 258 (declare-function winum--install-mode-line "ext:winum") 259 (declare-function winum-get-number-string "ext:winum") 260 261 262 263 ;; 264 ;; Buffer information 265 ;; 266 267 (defvar-local doom-modeline--buffer-file-icon nil) 268 (defun doom-modeline-update-buffer-file-icon (&rest _) 269 "Update file icon in mode-line." 270 (setq doom-modeline--buffer-file-icon 271 (when (and doom-modeline-major-mode-icon 272 (doom-modeline-icon-displayable-p)) 273 (let ((icon (doom-modeline-icon-for-buffer))) 274 (propertize (if (or (null icon) (symbolp icon)) 275 (doom-modeline-icon 'faicon "nf-fa-file_o" nil nil 276 :face 'nerd-icons-dsilver) 277 (doom-modeline-propertize-icon icon)) 278 'help-echo (format "Major-mode: %s" (format-mode-line mode-name))))))) 279 (add-hook 'find-file-hook #'doom-modeline-update-buffer-file-icon) 280 (add-hook 'after-change-major-mode-hook #'doom-modeline-update-buffer-file-icon) 281 (add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-icon) 282 283 (doom-modeline-add-variable-watcher 284 'doom-modeline-icon 285 (lambda (_sym val op _where) 286 (when (eq op 'set) 287 (setq doom-modeline-icon val) 288 (dolist (buf (buffer-list)) 289 (with-current-buffer buf 290 (doom-modeline-update-buffer-file-icon)))))) 291 292 (defun doom-modeline-buffer-file-state-icon (icon unicode text face) 293 "Displays an ICON of buffer state with FACE. 294 UNICODE and TEXT are the alternatives if it is not applicable. 295 Uses `nerd-icons-mdicon' to fetch the icon." 296 (doom-modeline-icon 'mdicon icon unicode text :face face)) 297 298 (defvar-local doom-modeline--buffer-file-state-icon nil) 299 (defun doom-modeline-update-buffer-file-state-icon (&rest _) 300 "Update the buffer or file state in mode-line." 301 (setq doom-modeline--buffer-file-state-icon 302 (when doom-modeline-buffer-state-icon 303 (ignore-errors 304 (concat 305 (cond (buffer-read-only 306 (doom-modeline-buffer-file-state-icon 307 "nf-md-lock" "đ" "%1*" 308 'doom-modeline-warning)) 309 ((and buffer-file-name (buffer-modified-p) 310 doom-modeline-buffer-modification-icon) 311 (doom-modeline-buffer-file-state-icon 312 "nf-md-content_save_edit" "đž" "%1*" 313 'doom-modeline-warning)) 314 ((and buffer-file-name 315 ;; Avoid freezing while connection is lost 316 (not (file-remote-p buffer-file-name)) 317 (not (file-exists-p buffer-file-name))) 318 (doom-modeline-buffer-file-state-icon 319 "nf-md-cancel" "đĢ" "!" 320 'doom-modeline-urgent)) 321 (t "")) 322 (when (or (buffer-narrowed-p) 323 (and (bound-and-true-p fancy-narrow-mode) 324 (fancy-narrow-active-p)) 325 (bound-and-true-p dired-narrow-mode)) 326 (doom-modeline-buffer-file-state-icon 327 "nf-md-unfold_less_horizontal" "â" "><" 328 'doom-modeline-warning))))))) 329 330 (defvar-local doom-modeline--buffer-file-name nil) 331 (defun doom-modeline-update-buffer-file-name (&rest _) 332 "Update buffer file name in mode-line." 333 (setq doom-modeline--buffer-file-name 334 (ignore-errors 335 (save-match-data 336 (if buffer-file-name 337 (doom-modeline-buffer-file-name) 338 (propertize "%b" 339 'face 'doom-modeline-buffer-file 340 'mouse-face 'doom-modeline-highlight 341 'help-echo "Buffer name 342 mouse-1: Previous buffer\nmouse-3: Next buffer" 343 'local-map mode-line-buffer-identification-keymap)))))) 344 (add-hook 'find-file-hook #'doom-modeline-update-buffer-file-name) 345 (add-hook 'after-save-hook #'doom-modeline-update-buffer-file-name) 346 (add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-name) 347 (add-hook 'evil-insert-state-exit-hook #'doom-modeline-update-buffer-file-name) 348 (add-hook 'Info-selection-hook #'doom-modeline-update-buffer-file-name) 349 (advice-add #'rename-buffer :after #'doom-modeline-update-buffer-file-name) 350 (advice-add #'set-visited-file-name :after #'doom-modeline-update-buffer-file-name) 351 (advice-add #'pop-to-buffer :after #'doom-modeline-update-buffer-file-name) 352 (advice-add #'popup-create :after #'doom-modeline-update-buffer-file-name) 353 (advice-add #'popup-delete :after #'doom-modeline-update-buffer-file-name) 354 ;; (advice-add #'primitive-undo :after #'doom-modeline-update-buffer-file-name) 355 ;; (advice-add #'set-buffer-modified-p :after #'doom-modeline-update-buffer-file-name) 356 357 (with-no-warnings 358 (if (boundp 'after-focus-change-function) 359 (progn 360 (advice-add #'handle-switch-frame :after #'doom-modeline-update-buffer-file-name) 361 (add-function :after after-focus-change-function #'doom-modeline-update-buffer-file-name)) 362 (progn 363 (add-hook 'focus-in-hook #'doom-modeline-update-buffer-file-name) 364 (add-hook 'focus-out-hook #'doom-modeline-update-buffer-file-name)))) 365 366 (doom-modeline-add-variable-watcher 367 'doom-modeline-buffer-file-name-style 368 (lambda (_sym val op _where) 369 (when (eq op 'set) 370 (setq doom-modeline-buffer-file-name-style val) 371 (dolist (buf (buffer-list)) 372 (with-current-buffer buf 373 (when buffer-file-name 374 (doom-modeline-update-buffer-file-name))))))) 375 376 (defsubst doom-modeline--buffer-mode-icon () 377 "The icon of the current major mode." 378 (when (and doom-modeline-icon doom-modeline-major-mode-icon) 379 (when-let ((icon (or doom-modeline--buffer-file-icon 380 (doom-modeline-update-buffer-file-icon)))) 381 (unless (string-empty-p icon) 382 (concat 383 (if doom-modeline-major-mode-color-icon 384 (doom-modeline-display-icon icon) 385 (doom-modeline-propertize-icon 386 icon 387 (doom-modeline-face))) 388 (doom-modeline-vspc)))))) 389 390 (defsubst doom-modeline--buffer-state-icon () 391 "The icon of the current buffer state." 392 (when doom-modeline-buffer-state-icon 393 (when-let ((icon (doom-modeline-update-buffer-file-state-icon))) 394 (unless (string-empty-p icon) 395 (concat 396 (doom-modeline-display-icon icon) 397 (doom-modeline-vspc)))))) 398 399 (defsubst doom-modeline--buffer-simple-name () 400 "The buffer simple name." 401 (propertize "%b" 402 'face (doom-modeline-face 403 (if (and doom-modeline-highlight-modified-buffer-name 404 (buffer-modified-p)) 405 'doom-modeline-buffer-modified 406 'doom-modeline-buffer-file)) 407 'mouse-face 'doom-modeline-highlight 408 'help-echo "Buffer name 409 mouse-1: Previous buffer\nmouse-3: Next buffer" 410 'local-map mode-line-buffer-identification-keymap)) 411 412 (defsubst doom-modeline--buffer-name () 413 "The current buffer name." 414 (when doom-modeline-buffer-name 415 (if (and (not (eq doom-modeline-buffer-file-name-style 'file-name)) 416 doom-modeline--limited-width-p) 417 ;; Only display the buffer name if the window is small, and doesn't 418 ;; need to respect file-name style. 419 (doom-modeline--buffer-simple-name) 420 (when-let ((name (or doom-modeline--buffer-file-name 421 (doom-modeline-update-buffer-file-name)))) 422 ;; Check if the buffer is modified 423 (if (and doom-modeline-highlight-modified-buffer-name 424 (buffer-modified-p)) 425 (propertize name 'face (doom-modeline-face 'doom-modeline-buffer-modified)) 426 (doom-modeline-display-text name)))))) 427 428 (doom-modeline-def-segment buffer-info 429 "Combined information about the current buffer. 430 431 Including the current working directory, the file name, and its state (modified, 432 read-only or non-existent)." 433 (concat 434 (doom-modeline-spc) 435 (doom-modeline--buffer-mode-icon) 436 (doom-modeline--buffer-state-icon) 437 (doom-modeline--buffer-name))) 438 439 (doom-modeline-def-segment buffer-info-simple 440 "Display only the current buffer's name, but with fontification." 441 (concat 442 (doom-modeline-spc) 443 (doom-modeline--buffer-mode-icon) 444 (doom-modeline--buffer-state-icon) 445 (doom-modeline--buffer-simple-name))) 446 447 (doom-modeline-def-segment calc 448 "Display calculator icons and info." 449 (concat 450 (doom-modeline-spc) 451 (when-let ((icon (doom-modeline-icon 'faicon "nf-fa-calculator" "đŠ" ""))) 452 (concat 453 (doom-modeline-display-icon icon) 454 (doom-modeline-vspc))) 455 (doom-modeline--buffer-simple-name))) 456 457 (doom-modeline-def-segment buffer-default-directory 458 "Displays `default-directory' with the icon and state. 459 460 This is for special buffers like the scratch buffer where knowing the current 461 project directory is important." 462 (let ((face (doom-modeline-face 463 (if (and buffer-file-name (buffer-modified-p)) 464 'doom-modeline-buffer-modified 465 'doom-modeline-buffer-path)))) 466 (concat 467 (doom-modeline-spc) 468 (and doom-modeline-major-mode-icon 469 (concat 470 (doom-modeline-icon 471 'octicon "nf-oct-file_directory_fill" "đŋ" "" :face face) 472 (doom-modeline-vspc))) 473 (doom-modeline--buffer-state-icon) 474 (propertize (abbreviate-file-name default-directory) 'face face)))) 475 476 (doom-modeline-def-segment buffer-default-directory-simple 477 "Displays `default-directory'. 478 479 This is for special buffers like the scratch buffer where knowing the current 480 project directory is important." 481 (let ((face (doom-modeline-face 'doom-modeline-buffer-path))) 482 (concat 483 (doom-modeline-spc) 484 (and doom-modeline-major-mode-icon 485 (concat 486 (doom-modeline-icon 487 'octicon "nf-oct-file_directory_fill" "đŋ" "" :face face) 488 (doom-modeline-vspc))) 489 (propertize (abbreviate-file-name default-directory) 'face face)))) 490 491 492 ;; 493 ;; Encoding 494 ;; 495 496 (doom-modeline-def-segment buffer-encoding 497 "Displays the eol and the encoding style of the buffer." 498 (when doom-modeline-buffer-encoding 499 (let ((sep (doom-modeline-spc)) 500 (face (doom-modeline-face)) 501 (mouse-face 'doom-modeline-highlight)) 502 (concat 503 sep 504 505 ;; eol type 506 (let ((eol (coding-system-eol-type buffer-file-coding-system))) 507 (when (or (eq doom-modeline-buffer-encoding t) 508 (and (eq doom-modeline-buffer-encoding 'nondefault) 509 (not (equal eol doom-modeline-default-eol-type)))) 510 (propertize 511 (pcase eol 512 (0 "LF ") 513 (1 "CRLF ") 514 (2 "CR ") 515 (_ "")) 516 'face face 517 'mouse-face mouse-face 518 'help-echo (format "End-of-line style: %s\nmouse-1: Cycle" 519 (pcase eol 520 (0 "Unix-style LF") 521 (1 "DOS-style CRLF") 522 (2 "Mac-style CR") 523 (_ "Undecided"))) 524 'local-map (let ((map (make-sparse-keymap))) 525 (define-key map [mode-line mouse-1] 'mode-line-change-eol) 526 map)))) 527 528 ;; coding system 529 (let* ((sys (coding-system-plist buffer-file-coding-system)) 530 (cat (plist-get sys :category)) 531 (sym (if (memq cat 532 '(coding-category-undecided coding-category-utf-8)) 533 'utf-8 534 (plist-get sys :name)))) 535 (when (or (eq doom-modeline-buffer-encoding t) 536 (and (eq doom-modeline-buffer-encoding 'nondefault) 537 (not (eq cat 'coding-category-undecided)) 538 (not (eq sym doom-modeline-default-coding-system)))) 539 (propertize 540 (upcase (symbol-name sym)) 541 'face face 542 'mouse-face mouse-face 543 'help-echo 'mode-line-mule-info-help-echo 544 'local-map mode-line-coding-system-map))) 545 546 sep)))) 547 548 549 ;; 550 ;; Indentation 551 ;; 552 553 (doom-modeline-def-segment indent-info 554 "Displays the indentation information." 555 (when doom-modeline-indent-info 556 (let ((do-propertize 557 (lambda (mode size) 558 (propertize 559 (format " %s %d " mode size) 560 'face (doom-modeline-face))))) 561 (if indent-tabs-mode 562 (funcall do-propertize "TAB" tab-width) 563 (let ((lookup-var 564 (seq-find (lambda (var) 565 (and var (boundp var) (symbol-value var))) 566 (cdr (assoc major-mode doom-modeline-indent-alist)) nil))) 567 (funcall do-propertize "SPC" 568 (if lookup-var 569 (symbol-value lookup-var) 570 tab-width))))))) 571 572 ;; 573 ;; Remote host 574 ;; 575 576 (doom-modeline-def-segment remote-host 577 "Hostname for remote buffers." 578 (when default-directory 579 (when-let ((host (file-remote-p default-directory 'host))) 580 (propertize 581 (concat "@" host) 582 'face (doom-modeline-face 'doom-modeline-host))))) 583 584 585 ;; 586 ;; Major mode 587 ;; 588 589 (doom-modeline-def-segment major-mode 590 "The major mode, including environment and text-scale info." 591 (let ((sep (doom-modeline-spc)) 592 (face (doom-modeline-face 'doom-modeline-buffer-major-mode))) 593 (concat 594 sep 595 (propertize (concat 596 (format-mode-line 597 (or (and (boundp 'delighted-modes) 598 (cadr (assq major-mode delighted-modes))) 599 mode-name)) 600 (when (and doom-modeline-env-version doom-modeline-env--version) 601 (format " %s" doom-modeline-env--version))) 602 'help-echo "Major mode\n\ 603 mouse-1: Display major mode menu\n\ 604 mouse-2: Show help for major mode\n\ 605 mouse-3: Toggle minor modes" 606 'face face 607 'mouse-face 'doom-modeline-highlight 608 'local-map mode-line-major-mode-keymap) 609 (and (boundp 'text-scale-mode-amount) 610 (/= text-scale-mode-amount 0) 611 (propertize 612 (format 613 (if (> text-scale-mode-amount 0) " (%+d)" " (%-d)") 614 text-scale-mode-amount) 615 'face face)) 616 sep))) 617 618 619 ;; 620 ;; Process 621 ;; 622 623 (doom-modeline-def-segment process 624 "The process info." 625 (doom-modeline-display-text 626 (format-mode-line mode-line-process))) 627 628 629 ;; 630 ;; Minor modes 631 ;; 632 633 (doom-modeline-def-segment minor-modes 634 (when doom-modeline-minor-modes 635 (let ((sep (doom-modeline-spc)) 636 (face (doom-modeline-face 'doom-modeline-buffer-minor-mode)) 637 (mouse-face 'doom-modeline-highlight) 638 (help-echo "Minor mode 639 mouse-1: Display minor mode menu 640 mouse-2: Show help for minor mode 641 mouse-3: Toggle minor modes")) 642 (if (bound-and-true-p minions-mode) 643 `((:propertize ("" ,(minions--prominent-modes)) 644 face ,face 645 mouse-face ,mouse-face 646 help-echo ,help-echo 647 local-map ,mode-line-minor-mode-keymap) 648 ,sep 649 (:propertize ("" ,(doom-modeline-icon 'octicon "nf-oct-gear" "â" 650 minions-mode-line-lighter 651 :face face)) 652 mouse-face ,mouse-face 653 help-echo "Minions 654 mouse-1: Display minor modes menu" 655 local-map ,minions-mode-line-minor-modes-map) 656 ,sep) 657 `((:propertize ("" minor-mode-alist) 658 face ,face 659 mouse-face ,mouse-face 660 help-echo ,help-echo 661 local-map ,mode-line-minor-mode-keymap) 662 ,sep))))) 663 664 665 ;; 666 ;; VCS 667 ;; 668 669 (defun doom-modeline-vcs-icon (icon &optional unicode text face) 670 "Displays the vcs ICON with FACE and VOFFSET. 671 672 UNICODE and TEXT are fallbacks. 673 Uses `nerd-icons-octicon' to fetch the icon." 674 (doom-modeline-icon 'devicon (and doom-modeline-vcs-icon icon) 675 unicode text :face face)) 676 677 (defvar-local doom-modeline--vcs nil) 678 (defun doom-modeline-update-vcs (&rest _) 679 "Update vcs state in mode-line." 680 (setq doom-modeline--vcs 681 (when (and vc-mode buffer-file-name) 682 (let* ((backend (vc-backend buffer-file-name)) 683 (state (vc-state buffer-file-name backend)) 684 (icon (cond ((memq state '(edited added)) 685 (doom-modeline-vcs-icon "nf-dev-git_compare" "đ" "*" 'doom-modeline-info)) 686 ((eq state 'needs-merge) 687 (doom-modeline-vcs-icon "nf-dev-git_merge" "đ" "?" 'doom-modeline-info)) 688 ((eq state 'needs-update) 689 (doom-modeline-vcs-icon "nf-dev-git_pull_request" "âŦ" "!" 'doom-modeline-warning)) 690 ((memq state '(removed conflict unregistered)) 691 (doom-modeline-icon 'octicon "nf-oct-alert" "â " "!" :face 'doom-modeline-urgent)) 692 (t (doom-modeline-vcs-icon "nf-dev-git_branch" "î " "@" 'doom-modeline-info)))) 693 (str (if vc-display-status 694 (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)) 695 "")) 696 (face (cond ((eq state 'needs-update) 697 '(doom-modeline-warning bold)) 698 ((memq state '(removed conflict unregistered)) 699 '(doom-modeline-urgent bold)) 700 (t '(doom-modeline-info bold)))) 701 (text (propertize (if (length> str doom-modeline-vcs-max-length) 702 (concat 703 (substring str 0 (- doom-modeline-vcs-max-length 3)) 704 doom-modeline-ellipsis) 705 str) 706 'face face))) 707 `((icon . ,icon) (text . ,text)))))) 708 (add-hook 'find-file-hook #'doom-modeline-update-vcs) 709 (add-hook 'after-save-hook #'doom-modeline-update-vcs) 710 (advice-add #'vc-refresh-state :after #'doom-modeline-update-vcs) 711 712 (doom-modeline-add-variable-watcher 713 'doom-modeline-icon 714 (lambda (_sym val op _where) 715 (when (eq op 'set) 716 (setq doom-modeline-icon val) 717 (dolist (buf (buffer-list)) 718 (with-current-buffer buf 719 (doom-modeline-update-vcs)))))) 720 721 (doom-modeline-add-variable-watcher 722 'doom-modeline-unicode-fallback 723 (lambda (_sym val op _where) 724 (when (eq op 'set) 725 (setq doom-modeline-unicode-fallback val) 726 (dolist (buf (buffer-list)) 727 (with-current-buffer buf 728 (doom-modeline-update-vcs)))))) 729 730 (doom-modeline-add-variable-watcher 731 'doom-modeline-vcs-icon 732 (lambda (_sym val op _where) 733 (when (eq op 'set) 734 (setq doom-modeline-vcs-icon val) 735 (dolist (buf (buffer-list)) 736 (with-current-buffer buf 737 (doom-modeline-update-vcs)))))) 738 739 (doom-modeline-def-segment vcs 740 "Displays the current branch, colored based on its state." 741 (when doom-modeline--vcs 742 (let-alist doom-modeline--vcs 743 (let ((sep (doom-modeline-spc)) 744 (vsep (doom-modeline-vspc))) 745 (concat sep 746 (propertize (concat 747 (doom-modeline-display-icon .icon) 748 vsep 749 (doom-modeline-display-text .text)) 750 'help-echo (get-text-property 1 'help-echo vc-mode) 751 'mouse-face 'doom-modeline-highlight 752 'local-map (get-text-property 1 'local-map vc-mode)) 753 sep))))) 754 755 756 ;; 757 ;; Check 758 ;; 759 760 (defun doom-modeline-check-icon (icon unicode text face) 761 "Displays the check ICON with FACE. 762 763 UNICODE and TEXT are fallbacks. 764 Uses `nerd-icons-mdicon' to fetch the icon." 765 (doom-modeline-icon 'mdicon (and doom-modeline-check-icon icon) 766 unicode text :face face)) 767 768 (defun doom-modeline-check-text (text &optional face) 769 "Displays the check TEXT with FACE." 770 (propertize text 'face (or face 'mode-line))) 771 772 ;; Flycheck 773 774 (defun doom-modeline--flycheck-count-errors () 775 "Count the number of ERRORS, grouped by level. 776 777 Return an alist, where each ITEM is a cons cell whose `car' is an 778 error level, and whose `cdr' is the number of errors of that 779 level." 780 (let ((info 0) (warning 0) (error 0)) 781 (mapc 782 (lambda (item) 783 (let ((count (cdr item))) 784 (pcase (flycheck-error-level-compilation-level (car item)) 785 (0 (cl-incf info count)) 786 (1 (cl-incf warning count)) 787 (2 (cl-incf error count))))) 788 (flycheck-count-errors flycheck-current-errors)) 789 `((info . ,info) (warning . ,warning) (error . ,error)))) 790 791 (defvar-local doom-modeline--flycheck nil) 792 (defun doom-modeline-update-flycheck (&optional status) 793 "Update flycheck via STATUS." 794 (setq doom-modeline--flycheck 795 (let-alist (doom-modeline--flycheck-count-errors) 796 (let* ((vsep (doom-modeline-vspc)) 797 (seg (if doom-modeline-check-simple-format 798 (let ((count (+ .error .warning .info))) 799 (pcase status 800 ('finished (if (> count 0) 801 (let ((face (if (> .error 0) 'doom-modeline-urgent 'doom-modeline-warning))) 802 (concat 803 (doom-modeline-check-icon "nf-md-alert_circle_outline" "â " "!" face) 804 vsep 805 (doom-modeline-check-text (number-to-string count) face))) 806 (doom-modeline-check-icon "nf-md-check_circle_outline" "â" "" 'doom-modeline-info))) 807 ('running (concat 808 (doom-modeline-check-icon "nf-md-timer_sand" "âŗ" "*" 'doom-modeline-debug) 809 (when (> count 0) 810 (concat 811 vsep 812 (doom-modeline-check-text (number-to-string count) 'doom-modeline-debug))))) 813 ('no-checker (doom-modeline-check-icon "nf-md-alert_box_outline" "â " "-" 'doom-modeline-debug)) 814 ('errored (doom-modeline-check-icon "nf-md-alert_box_outline" "â " "!" 'doom-modeline-urgent)) 815 ('interrupted (doom-modeline-check-icon "nf-md-pause_circle_outline" "âĻˇ" "." 'doom-modeline-debug)) 816 ('suspicious (doom-modeline-check-icon "nf-md-file_question_outline" "â" "?" 'doom-modeline-debug)) 817 (_ ""))) 818 (concat (doom-modeline-check-icon "nf-md-close_circle_outline" "⎞" "!" 'doom-modeline-urgent) 819 vsep 820 (doom-modeline-check-text (number-to-string .error) 'doom-modeline-urgent) 821 vsep 822 (doom-modeline-check-icon "nf-md-alert_outline" "â " "!" 'doom-modeline-warning) 823 vsep 824 (doom-modeline-check-text (number-to-string .warning) 'doom-modeline-warning) 825 vsep 826 (doom-modeline-check-icon "nf-md-information_outline" "đ" "!" 'doom-modeline-info) 827 vsep 828 (doom-modeline-check-text (number-to-string .info) 'doom-modeline-info))))) 829 (propertize seg 830 'help-echo (concat "Flycheck\n" 831 (pcase status 832 ('finished (format "error: %d, warning: %d, info: %d" .error .warning .info)) 833 ('running "Checking...") 834 ('no-checker "No Checker") 835 ('errored "Error") 836 ('interrupted "Interrupted") 837 ('suspicious "Suspicious")) 838 "\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode") 839 'mouse-face 'doom-modeline-highlight 840 'local-map (let ((map (make-sparse-keymap))) 841 (define-key map [mode-line down-mouse-1] 842 flycheck-mode-menu-map) 843 (define-key map [mode-line mouse-2] 844 (lambda () 845 (interactive) 846 (describe-function 'flycheck-mode))) 847 map)))))) 848 (add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck) 849 (add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck) 850 851 (doom-modeline-add-variable-watcher 852 'doom-modeline-icon 853 (lambda (_sym val op _where) 854 (when (eq op 'set) 855 (setq doom-modeline-icon val) 856 (dolist (buf (buffer-list)) 857 (with-current-buffer buf 858 (when (bound-and-true-p flycheck-mode) 859 (doom-modeline-update-flycheck))))))) 860 861 (doom-modeline-add-variable-watcher 862 'doom-modeline-check-icon 863 (lambda (_sym val op _where) 864 (when (eq op 'set) 865 (setq doom-modeline-check-icon val) 866 (dolist (buf (buffer-list)) 867 (with-current-buffer buf 868 (when (bound-and-true-p flycheck-mode) 869 (doom-modeline-update-flycheck))))))) 870 871 (doom-modeline-add-variable-watcher 872 'doom-modeline-unicode-fallback 873 (lambda (_sym val op _where) 874 (when (eq op 'set) 875 (setq doom-modeline-unicode-fallback val) 876 (dolist (buf (buffer-list)) 877 (with-current-buffer buf 878 (when (bound-and-true-p flycheck-mode) 879 (doom-modeline-update-flycheck))))))) 880 881 (doom-modeline-add-variable-watcher 882 'doom-modeline-check-simple-format 883 (lambda (_sym val op _where) 884 (when (eq op 'set) 885 (setq doom-modeline-check-simple-format val) 886 (dolist (buf (buffer-list)) 887 (with-current-buffer buf 888 (when (bound-and-true-p flycheck-mode) 889 (doom-modeline-update-flycheck))))))) 890 891 ;; Flymake 892 893 ;; Compatibility 894 ;; @see https://github.com/emacs-mirror/emacs/commit/6e100869012da9244679696634cab6b9cac96303. 895 (with-eval-after-load 'flymake 896 (unless (boundp 'flymake--state) 897 (defvaralias 'flymake--state 'flymake--backend-state)) 898 (unless (fboundp 'flymake--state-diags) 899 (defalias 'flymake--state-diags 'flymake--backend-state-diags))) 900 901 (defun doom-modeline--flymake-count-errors () 902 "Count the number of ERRORS, grouped by level." 903 (let ((warning-level (warning-numeric-level :warning)) 904 (note-level (warning-numeric-level :debug)) 905 (note 0) (warning 0) (error 0)) 906 (maphash (lambda (_b state) 907 (cl-loop 908 with diags = (flymake--state-diags state) 909 for diag in diags do 910 (let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity 911 (warning-numeric-level :error)))) 912 (cond ((> severity warning-level) (cl-incf error)) 913 ((> severity note-level) (cl-incf warning)) 914 (t (cl-incf note)))))) 915 flymake--state) 916 `((note . ,note) (warning . ,warning) (error . ,error)))) 917 918 (defvar-local doom-modeline--flymake nil) 919 (defun doom-modeline-update-flymake (&rest _) 920 "Update flymake." 921 (setq doom-modeline--flymake 922 (let* ((known (hash-table-keys flymake--state)) 923 (running (flymake-running-backends)) 924 (disabled (flymake-disabled-backends)) 925 (reported (flymake-reporting-backends)) 926 (all-disabled (and disabled (null running))) 927 (some-waiting (cl-set-difference running reported))) 928 (let-alist (doom-modeline--flymake-count-errors) 929 (let* ((vsep (doom-modeline-vspc)) 930 (seg (if doom-modeline-check-simple-format 931 (let ((count (+ .error .warning .note))) 932 (cond 933 (some-waiting (concat 934 (doom-modeline-check-icon "nf-md-timer_sand" "âŗ" "*" 'doom-modeline-debug) 935 (when (> count 0) 936 (concat 937 vsep 938 (doom-modeline-check-text (number-to-string count) 'doom-modeline-debug))))) 939 ((null known) (doom-modeline-check-icon "nf-md-alert_box_outline" "â " "!" 'doom-modeline-urgent)) 940 (all-disabled (doom-modeline-check-icon "nf-md-alert_box_outline" "â " "!" 'doom-modeline-warning)) 941 (t (if (> count 0) 942 (let ((face (if (> .error 0) 'doom-modeline-urgent 'doom-modeline-warning))) 943 (concat 944 (doom-modeline-check-icon "nf-md-alert_circle_outline" "â " "!" face) 945 vsep 946 (doom-modeline-check-text (number-to-string count) face))) 947 (doom-modeline-check-icon "nf-md-check_circle_outline" "â" "" 'doom-modeline-info))))) 948 (concat (doom-modeline-check-icon "nf-md-close_circle_outline" "⎞" "!" 'doom-modeline-urgent) 949 vsep 950 (doom-modeline-check-text (number-to-string .error) 'doom-modeline-urgent) 951 vsep 952 (doom-modeline-check-icon "nf-md-alert_outline" "â " "!" 'doom-modeline-warning) 953 vsep 954 (doom-modeline-check-text (number-to-string .warning) 'doom-modeline-warning) 955 vsep 956 (doom-modeline-check-icon "nf-md-information_outline" "đ" "!" 'doom-modeline-info) 957 vsep 958 (doom-modeline-check-text (number-to-string .note) 'doom-modeline-info))))) 959 (propertize 960 seg 961 'help-echo (concat "Flymake\n" 962 (cond 963 (some-waiting "Checking...") 964 ((null known) "No Checker") 965 (all-disabled "All Checkers Disabled") 966 (t (format "%d/%d backends running\nerror: %d, warning: %d, note: %d" 967 (length running) (length known) .error .warning .note))) 968 "\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode") 969 'mouse-face 'doom-modeline-highlight 970 'local-map (let ((map (make-sparse-keymap))) 971 (define-key map [mode-line down-mouse-1] 972 flymake-menu) 973 (define-key map [mode-line mouse-2] 974 (lambda () 975 (interactive) 976 (describe-function 'flymake-mode))) 977 map))))))) 978 (advice-add #'flymake--handle-report :after #'doom-modeline-update-flymake) 979 980 (doom-modeline-add-variable-watcher 981 'doom-modeline-icon 982 (lambda (_sym val op _where) 983 (when (eq op 'set) 984 (setq doom-modeline-icon val) 985 (dolist (buf (buffer-list)) 986 (with-current-buffer buf 987 (when (bound-and-true-p flymake-mode) 988 (doom-modeline-update-flymake))))))) 989 990 (doom-modeline-add-variable-watcher 991 'doom-modeline-check-icon 992 (lambda (_sym val op _where) 993 (when (eq op 'set) 994 (setq doom-modeline-check-icon val) 995 (dolist (buf (buffer-list)) 996 (with-current-buffer buf 997 (when (bound-and-true-p flymake-mode) 998 (doom-modeline-update-flymake))))))) 999 1000 (doom-modeline-add-variable-watcher 1001 'doom-modeline-unicode-fallback 1002 (lambda (_sym val op _where) 1003 (when (eq op 'set) 1004 (setq doom-modeline-unicode-fallback val) 1005 (dolist (buf (buffer-list)) 1006 (with-current-buffer buf 1007 (when (bound-and-true-p flymake-mode) 1008 (doom-modeline-update-flymake))))))) 1009 1010 (doom-modeline-add-variable-watcher 1011 'doom-modeline-check-simple-format 1012 (lambda (_sym val op _where) 1013 (when (eq op 'set) 1014 (setq doom-modeline-check-simple-format val) 1015 (dolist (buf (buffer-list)) 1016 (with-current-buffer buf 1017 (when (bound-and-true-p flymake-mode) 1018 (doom-modeline-update-flymake))))))) 1019 1020 (doom-modeline-def-segment check 1021 "Displays color-coded error status in the current buffer with pretty icons." 1022 (when-let ((sep (doom-modeline-spc)) 1023 (vsep (doom-modeline-vspc)) 1024 (seg (cond 1025 ((and (bound-and-true-p flymake-mode) 1026 (bound-and-true-p flymake--state)) ; only support 26+ 1027 doom-modeline--flymake) 1028 ((and (bound-and-true-p flycheck-mode) 1029 (bound-and-true-p flycheck--automatically-enabled-checkers)) 1030 doom-modeline--flycheck)))) 1031 (concat 1032 sep 1033 (let ((str)) 1034 (dolist (s (split-string seg " ")) 1035 (setq str 1036 (concat str 1037 (if (string-match-p "^[0-9]+$" s) 1038 (concat vsep 1039 (doom-modeline-display-text s) 1040 vsep) 1041 (doom-modeline-display-icon s))))) 1042 (propertize str 1043 'help-echo (get-text-property 1 'help-echo seg) 1044 'mouse-face 'doom-modeline-highlight 1045 'local-map (get-text-property 1 'local-map seg))) 1046 sep))) 1047 1048 1049 ;; 1050 ;; Word Count 1051 ;; 1052 1053 (doom-modeline-def-segment word-count 1054 "The buffer word count. 1055 Displayed when in a major mode in `doom-modeline-continuous-word-count-modes'. 1056 Respects `doom-modeline-enable-word-count'." 1057 (when (and doom-modeline-enable-word-count 1058 (member major-mode doom-modeline-continuous-word-count-modes)) 1059 (propertize (format " %dW" (count-words (point-min) (point-max))) 1060 'face (doom-modeline-face)))) 1061 1062 1063 ;; 1064 ;; Selection 1065 ;; 1066 1067 (defsubst doom-modeline-column (pos) 1068 "Get the column of the position `POS'." 1069 (save-excursion (goto-char pos) 1070 (current-column))) 1071 1072 (doom-modeline-def-segment selection-info 1073 "Information about the current selection. 1074 1075 Such as how many characters and lines are selected, or the NxM dimensions of a 1076 block selection." 1077 (when (and (or mark-active (and (bound-and-true-p evil-local-mode) 1078 (eq evil-state 'visual))) 1079 (doom-modeline--active)) 1080 (cl-destructuring-bind (beg . end) 1081 (if (and (bound-and-true-p evil-local-mode) (eq evil-state 'visual)) 1082 (cons evil-visual-beginning evil-visual-end) 1083 (cons (region-beginning) (region-end))) 1084 (propertize 1085 (let ((lines (count-lines beg (min end (point-max))))) 1086 (concat 1087 " " 1088 (cond ((or (bound-and-true-p rectangle-mark-mode) 1089 (and (bound-and-true-p evil-visual-selection) 1090 (eq 'block evil-visual-selection))) 1091 (let ((cols (abs (- (doom-modeline-column end) 1092 (doom-modeline-column beg))))) 1093 (format "%dx%dB" lines cols))) 1094 ((and (bound-and-true-p evil-visual-selection) 1095 (eq evil-visual-selection 'line)) 1096 (format "%dL" lines)) 1097 ((> lines 1) 1098 (format "%dC %dL" (- end beg) lines)) 1099 (t 1100 (format "%dC" (- end beg)))) 1101 (when doom-modeline-enable-word-count 1102 (format " %dW" (count-words beg end))) 1103 " ")) 1104 'face 'doom-modeline-emphasis)))) 1105 1106 1107 ;; 1108 ;; Matches (macro, anzu, evil-substitute, iedit, symbol-overlay and multi-cursors) 1109 ;; 1110 1111 (defsubst doom-modeline--macro-recording () 1112 "Display current Emacs or evil macro being recorded." 1113 (when (and (doom-modeline--active) 1114 (or defining-kbd-macro executing-kbd-macro)) 1115 (let ((sep (propertize " " 'face 'doom-modeline-panel)) 1116 (vsep (propertize " " 'face 1117 '(:inherit (doom-modeline-panel variable-pitch)))) 1118 (macro-name (if (bound-and-true-p evil-this-macro) 1119 (format " @%s " 1120 (char-to-string evil-this-macro)) 1121 "Macro"))) 1122 (concat 1123 sep 1124 (if doom-modeline-always-show-macro-register 1125 (propertize macro-name 'face 'doom-modeline-panel) 1126 (concat 1127 (doom-modeline-icon 'mdicon "nf-md-record" "â" 1128 macro-name 1129 :face '(:inherit (doom-modeline-urgent doom-modeline-panel)) 1130 :v-adjust 0.15) 1131 vsep 1132 (doom-modeline-icon 'mdicon "nf-md-menu_right" "âļ" ">" 1133 :face 'doom-modeline-panel 1134 :v-adjust 0.15))) 1135 sep)))) 1136 1137 ;; `anzu' and `evil-anzu' expose current/total state that can be displayed in the 1138 ;; mode-line. 1139 (defun doom-modeline-fix-anzu-count (positions here) 1140 "Calulate anzu count via POSITIONS and HERE." 1141 (cl-loop for (start . end) in positions 1142 collect t into before 1143 when (and (>= here start) (<= here end)) 1144 return (length before) 1145 finally return 0)) 1146 1147 (advice-add #'anzu--where-is-here :override #'doom-modeline-fix-anzu-count) 1148 1149 (setq anzu-cons-mode-line-p nil) ; manage modeline segment ourselves 1150 ;; Ensure anzu state is cleared when searches & iedit are done 1151 (with-eval-after-load 'anzu 1152 (add-hook 'isearch-mode-end-hook #'anzu--reset-status t) 1153 (add-hook 'iedit-mode-end-hook #'anzu--reset-status) 1154 (advice-add #'evil-force-normal-state :after #'anzu--reset-status) 1155 ;; Fix matches segment mirroring across all buffers 1156 (mapc #'make-variable-buffer-local 1157 '(anzu--total-matched 1158 anzu--current-position anzu--state anzu--cached-count 1159 anzu--cached-positions anzu--last-command 1160 anzu--last-isearch-string anzu--overflow-p))) 1161 1162 (defsubst doom-modeline--anzu () 1163 "Show the match index and total number thereof. 1164 Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with 1165 `evil-search'." 1166 (when (and (bound-and-true-p anzu--state) 1167 (not (bound-and-true-p iedit-mode))) 1168 (propertize 1169 (let ((here anzu--current-position) 1170 (total anzu--total-matched)) 1171 (cond ((eq anzu--state 'replace-query) 1172 (format " %d replace " anzu--cached-count)) 1173 ((eq anzu--state 'replace) 1174 (format " %d/%d " here total)) 1175 (anzu--overflow-p 1176 (format " %s+ " total)) 1177 (t 1178 (format " %s/%d " here total)))) 1179 'face (doom-modeline-face 'doom-modeline-panel)))) 1180 1181 (defsubst doom-modeline--evil-substitute () 1182 "Show number of matches for `evil-ex' in real time. 1183 The number of matches contains substitutions and highlightings." 1184 (when (and (bound-and-true-p evil-local-mode) 1185 (or (assq 'evil-ex-substitute evil-ex-active-highlights-alist) 1186 (assq 'evil-ex-global-match evil-ex-active-highlights-alist) 1187 (assq 'evil-ex-buffer-match evil-ex-active-highlights-alist))) 1188 (propertize 1189 (let ((range (if evil-ex-range 1190 (cons (car evil-ex-range) (cadr evil-ex-range)) 1191 (cons (line-beginning-position) (line-end-position)))) 1192 (pattern (car-safe (evil-delimited-arguments evil-ex-argument 2)))) 1193 (if pattern 1194 (format " %s matches " (how-many pattern (car range) (cdr range))) 1195 " - ")) 1196 'face (doom-modeline-face 'doom-modeline-panel)))) 1197 1198 (defun doom-modeline-themes--overlay-sort (a b) 1199 "Sort overlay A and B." 1200 (< (overlay-start a) (overlay-start b))) 1201 1202 (defsubst doom-modeline--iedit () 1203 "Show the number of iedit regions matches + what match you're on." 1204 (when (and (bound-and-true-p iedit-mode) 1205 (bound-and-true-p iedit-occurrences-overlays)) 1206 (propertize 1207 (let ((this-oc (or (let ((inhibit-message t)) 1208 (iedit-find-current-occurrence-overlay)) 1209 (save-excursion (iedit-prev-occurrence) 1210 (iedit-find-current-occurrence-overlay)))) 1211 (length (length iedit-occurrences-overlays))) 1212 (format " %s/%d " 1213 (if this-oc 1214 (- length 1215 (length (memq this-oc (sort (append iedit-occurrences-overlays nil) 1216 #'doom-modeline-themes--overlay-sort))) 1217 -1) 1218 "-") 1219 length)) 1220 'face (doom-modeline-face 'doom-modeline-panel)))) 1221 1222 (defsubst doom-modeline--symbol-overlay () 1223 "Show the number of matches for symbol overlay." 1224 (when (and (doom-modeline--active) 1225 (bound-and-true-p symbol-overlay-keywords-alist) 1226 (not (bound-and-true-p symbol-overlay-temp-symbol)) 1227 (not (bound-and-true-p iedit-mode))) 1228 (let* ((keyword (symbol-overlay-assoc (symbol-overlay-get-symbol t))) 1229 (symbol (car keyword)) 1230 (before (symbol-overlay-get-list -1 symbol)) 1231 (after (symbol-overlay-get-list 1 symbol)) 1232 (count (length before))) 1233 (if (symbol-overlay-assoc symbol) 1234 (propertize 1235 (format (concat " %d/%d " (and (cadr keyword) "in scope ")) 1236 (+ count 1) 1237 (+ count (length after))) 1238 'face (doom-modeline-face 'doom-modeline-panel)))))) 1239 1240 (defsubst doom-modeline--multiple-cursors () 1241 "Show the number of multiple cursors." 1242 (cl-destructuring-bind (count . face) 1243 (cond ((bound-and-true-p multiple-cursors-mode) 1244 (cons (mc/num-cursors) 1245 (doom-modeline-face 'doom-modeline-panel))) 1246 ((bound-and-true-p evil-mc-cursor-list) 1247 (cons (length evil-mc-cursor-list) 1248 (doom-modeline-face (if evil-mc-frozen 1249 'doom-modeline-bar 1250 'doom-modeline-panel)))) 1251 ((cons nil nil))) 1252 (when count 1253 (concat (propertize " " 'face face) 1254 (if (doom-modeline-icon-displayable-p) 1255 (doom-modeline-icon 'faicon "nf-fa-i_cursor" "" "" :face face) 1256 (propertize "I" 1257 'face `(:inherit ,face :height 1.4 :weight normal) 1258 'display '(raise -0.1))) 1259 (propertize " " 1260 'face `(:inherit (variable-pitch ,face))) 1261 (propertize (format "%d " count) 1262 'face face))))) 1263 1264 (defsubst doom-modeline--phi-search () 1265 "Show the number of matches for `phi-search' and `phi-replace'." 1266 (when (and (doom-modeline--active) 1267 (bound-and-true-p phi-search--overlays)) 1268 (let ((total (length phi-search--overlays)) 1269 (selection phi-search--selection)) 1270 (when selection 1271 (propertize 1272 (format " %d/%d " (1+ selection) total) 1273 'face (doom-modeline-face 'doom-modeline-panel)))))) 1274 1275 (defun doom-modeline--override-phi-search (orig-fun &rest args) 1276 "Override the mode-line of `phi-search' and `phi-replace'. 1277 Apply ORIG-FUN with ARGS." 1278 (if (bound-and-true-p doom-modeline-mode) 1279 (apply orig-fun mode-line-format (cdr args)) 1280 (apply orig-fun args))) 1281 (advice-add #'phi-search--initialize :around #'doom-modeline--override-phi-search) 1282 1283 (defsubst doom-modeline--buffer-size () 1284 "Show buffer size." 1285 (when size-indication-mode 1286 (let ((sep (doom-modeline-spc))) 1287 (concat sep 1288 (propertize "%I" 1289 'face (doom-modeline-face) 1290 'help-echo "Buffer size 1291 mouse-1: Display Line and Column Mode Menu" 1292 'mouse-face 'doom-modeline-highlight 1293 'local-map mode-line-column-line-number-mode-map) 1294 sep)))) 1295 1296 (doom-modeline-def-segment matches 1297 "Displays matches. 1298 1299 Including: 1300 1. the currently recording macro, 2. A current/total for the 1301 current search term (with `anzu'), 3. The number of substitutions being 1302 conducted with `evil-ex-substitute', and/or 4. The number of active `iedit' 1303 regions, 5. The current/total for the highlight term (with `symbol-overlay'), 1304 6. The number of active `multiple-cursors'." 1305 (let ((meta (concat (doom-modeline--macro-recording) 1306 (doom-modeline--anzu) 1307 (doom-modeline--phi-search) 1308 (doom-modeline--evil-substitute) 1309 (doom-modeline--iedit) 1310 (doom-modeline--symbol-overlay) 1311 (doom-modeline--multiple-cursors)))) 1312 (or (and (not (string-empty-p meta)) meta) 1313 (doom-modeline--buffer-size)))) 1314 1315 (doom-modeline-def-segment buffer-size 1316 "Display buffer size." 1317 (doom-modeline--buffer-size)) 1318 1319 ;; 1320 ;; Media 1321 ;; 1322 1323 (doom-modeline-def-segment media-info 1324 "Metadata regarding the current file, such as dimensions for images." 1325 ;; TODO: Include other information 1326 (cond ((eq major-mode 'image-mode) 1327 (cl-destructuring-bind (width . height) 1328 (when (fboundp 'image-size) 1329 (image-size (image-get-display-property) :pixels)) 1330 (format " %dx%d " width height))))) 1331 1332 1333 ;; 1334 ;; Bars 1335 ;; 1336 1337 (defvar doom-modeline--bar-active nil) 1338 (defvar doom-modeline--bar-inactive nil) 1339 1340 (defsubst doom-modeline--bar () 1341 "The default bar regulates the height of the mode-line in GUI." 1342 (unless (and doom-modeline--bar-active doom-modeline--bar-inactive) 1343 (let ((width doom-modeline-bar-width) 1344 (height (max doom-modeline-height (doom-modeline--font-height)))) 1345 (setq doom-modeline--bar-active 1346 (doom-modeline--create-bar-image 'doom-modeline-bar width height) 1347 doom-modeline--bar-inactive 1348 (doom-modeline--create-bar-image 1349 'doom-modeline-bar-inactive width height)))) 1350 (if (doom-modeline--active) 1351 doom-modeline--bar-active 1352 doom-modeline--bar-inactive)) 1353 1354 (defun doom-modeline-refresh-bars () 1355 "Refresh mode-line bars on next redraw." 1356 (setq doom-modeline--bar-active nil 1357 doom-modeline--bar-inactive nil)) 1358 1359 (cl-defstruct doom-modeline--hud-cache active inactive top-margin bottom-margin) 1360 1361 (defsubst doom-modeline--hud () 1362 "Powerline's hud segment reimplemented in the style of Doom's bar segment." 1363 (let* ((ws (window-start)) 1364 (we (window-end)) 1365 (bs (buffer-size)) 1366 (height (max doom-modeline-height (doom-modeline--font-height))) 1367 (top-margin (if (zerop bs) 1368 0 1369 (/ (* height (1- ws)) bs))) 1370 (bottom-margin (if (zerop bs) 1371 0 1372 (max 0 (/ (* height (- bs we 1)) bs)))) 1373 (cache (or (window-parameter nil 'doom-modeline--hud-cache) 1374 (set-window-parameter 1375 nil 1376 'doom-modeline--hud-cache 1377 (make-doom-modeline--hud-cache))))) 1378 (unless (and (doom-modeline--hud-cache-active cache) 1379 (doom-modeline--hud-cache-inactive cache) 1380 (= top-margin (doom-modeline--hud-cache-top-margin cache)) 1381 (= bottom-margin 1382 (doom-modeline--hud-cache-bottom-margin cache))) 1383 (setf (doom-modeline--hud-cache-active cache) 1384 (doom-modeline--create-hud-image 1385 'doom-modeline-bar 'default doom-modeline-bar-width 1386 height top-margin bottom-margin) 1387 (doom-modeline--hud-cache-inactive cache) 1388 (doom-modeline--create-hud-image 1389 'doom-modeline-bar-inactive 'default doom-modeline-bar-width 1390 height top-margin bottom-margin) 1391 (doom-modeline--hud-cache-top-margin cache) top-margin 1392 (doom-modeline--hud-cache-bottom-margin cache) bottom-margin)) 1393 (if (doom-modeline--active) 1394 (doom-modeline--hud-cache-active cache) 1395 (doom-modeline--hud-cache-inactive cache)))) 1396 1397 (defun doom-modeline-invalidate-huds () 1398 "Invalidate all cached hud images." 1399 (dolist (frame (frame-list)) 1400 (dolist (window (window-list frame)) 1401 (set-window-parameter window 'doom-modeline--hud-cache nil)))) 1402 1403 (doom-modeline-add-variable-watcher 1404 'doom-modeline-height 1405 (lambda (_sym val op _where) 1406 (when (and (eq op 'set) (integerp val)) 1407 (doom-modeline-refresh-bars) 1408 (doom-modeline-invalidate-huds)))) 1409 1410 (doom-modeline-add-variable-watcher 1411 'doom-modeline-bar-width 1412 (lambda (_sym val op _where) 1413 (when (and (eq op 'set) (integerp val)) 1414 (doom-modeline-refresh-bars) 1415 (doom-modeline-invalidate-huds)))) 1416 1417 (doom-modeline-add-variable-watcher 1418 'doom-modeline-icon 1419 (lambda (_sym _val op _where) 1420 (when (eq op 'set) 1421 (doom-modeline-refresh-bars) 1422 (doom-modeline-invalidate-huds)))) 1423 1424 (doom-modeline-add-variable-watcher 1425 'doom-modeline-unicode-fallback 1426 (lambda (_sym _val op _where) 1427 (when (eq op 'set) 1428 (doom-modeline-refresh-bars) 1429 (doom-modeline-invalidate-huds)))) 1430 1431 (add-hook 'window-configuration-change-hook #'doom-modeline-refresh-bars) 1432 (add-hook 'window-configuration-change-hook #'doom-modeline-invalidate-huds) 1433 1434 (doom-modeline-def-segment bar 1435 "The bar regulates the height of the `doom-modeline' in GUI." 1436 (when (display-graphic-p) 1437 (concat 1438 (if doom-modeline-hud 1439 (doom-modeline--hud) 1440 (doom-modeline--bar)) 1441 (doom-modeline-spc)))) 1442 1443 (doom-modeline-def-segment hud 1444 "Powerline's hud segment reimplemented in the style of bar segment." 1445 (when (display-graphic-p) 1446 (concat 1447 (doom-modeline--hud) 1448 (doom-modeline-spc)))) 1449 1450 1451 ;; 1452 ;; Window number 1453 ;; 1454 1455 ;; HACK: `ace-window-display-mode' should respect the ignore buffers. 1456 (defun doom-modeline-aw-update () 1457 "Update ace-window-path window parameter for all windows. 1458 Ensure all windows are labeled so the user can select a specific 1459 one. The ignored buffers are excluded unless `aw-ignore-on' is nil." 1460 (let ((ignore-window-parameters t)) 1461 (avy-traverse 1462 (avy-tree (aw-window-list) aw-keys) 1463 (lambda (path leaf) 1464 (set-window-parameter 1465 leaf 'ace-window-path 1466 (propertize 1467 (apply #'string (reverse path)) 1468 'face 'aw-mode-line-face)))))) 1469 (advice-add #'aw-update :override #'doom-modeline-aw-update) 1470 1471 ;; Remove original window number of `ace-window-display-mode'. 1472 (add-hook 'ace-window-display-mode-hook 1473 (lambda () 1474 (setq-default mode-line-format 1475 (assq-delete-all 'ace-window-display-mode 1476 (default-value 'mode-line-format))))) 1477 1478 (advice-add #'window-numbering-install-mode-line :override #'ignore) 1479 (advice-add #'window-numbering-clear-mode-line :override #'ignore) 1480 (advice-add #'winum--install-mode-line :override #'ignore) 1481 (advice-add #'winum--clear-mode-line :override #'ignore) 1482 1483 (doom-modeline-def-segment window-number 1484 "The current window number." 1485 (let ((num (cond 1486 ((bound-and-true-p ace-window-display-mode) 1487 (aw-update) 1488 (window-parameter (selected-window) 'ace-window-path)) 1489 ((bound-and-true-p winum-mode) 1490 (setq winum-auto-setup-mode-line nil) 1491 (winum-get-number-string)) 1492 ((bound-and-true-p window-numbering-mode) 1493 (window-numbering-get-number-string)) 1494 (t "")))) 1495 (when (and (length> num 0) 1496 (length> (cl-mapcan 1497 (lambda (frame) 1498 ;; Exclude minibuffer, tooltip and child frames 1499 (unless (or (and (fboundp 'frame-parent) (frame-parent frame)) 1500 (string= (frame-parameter frame 'name) 1501 (alist-get 'name (bound-and-true-p tooltip-frame-parameters)))) 1502 (window-list frame 'never))) 1503 (visible-frame-list)) 1504 1)) 1505 (propertize (format " %s " num) 1506 'face (doom-modeline-face 'doom-modeline-buffer-major-mode))))) 1507 1508 1509 ;; 1510 ;; Workspace 1511 ;; 1512 1513 (doom-modeline-def-segment workspace-name 1514 "The current workspace name or number. 1515 Requires `eyebrowse-mode' to be enabled or `tab-bar-mode' tabs to be created." 1516 (when doom-modeline-workspace-name 1517 (when-let 1518 ((name (cond 1519 ((and (bound-and-true-p eyebrowse-mode) 1520 (length> (eyebrowse--get 'window-configs) 1)) 1521 (setq mode-line-misc-info 1522 (assq-delete-all 'eyebrowse-mode mode-line-misc-info)) 1523 (when-let* 1524 ((num (eyebrowse--get 'current-slot)) 1525 (tag (nth 2 (assoc num (eyebrowse--get 'window-configs))))) 1526 (if (length> tag 0) tag (int-to-string num)))) 1527 ((and (fboundp 'tab-bar-mode) 1528 (length> (frame-parameter nil 'tabs) 1)) 1529 (let* ((current-tab (tab-bar--current-tab)) 1530 (tab-index (tab-bar--current-tab-index)) 1531 (explicit-name (alist-get 'explicit-name current-tab)) 1532 (tab-name (alist-get 'name current-tab))) 1533 (if explicit-name tab-name (+ 1 tab-index))))))) 1534 (propertize (format " %s " name) 1535 'face (doom-modeline-face 'doom-modeline-buffer-major-mode))))) 1536 1537 1538 ;; 1539 ;; Perspective 1540 ;; 1541 1542 (defvar-local doom-modeline--persp-name nil) 1543 (defun doom-modeline-update-persp-name (&rest _) 1544 "Update perspective name in mode-line." 1545 (setq doom-modeline--persp-name 1546 ;; Support `persp-mode', while not support `perspective' 1547 (when (and doom-modeline-persp-name 1548 (bound-and-true-p persp-mode) 1549 (fboundp 'safe-persp-name) 1550 (fboundp 'get-current-persp)) 1551 (let* ((persp (get-current-persp)) 1552 (name (safe-persp-name persp)) 1553 (face (if (and persp 1554 (not (persp-contain-buffer-p (current-buffer) persp))) 1555 'doom-modeline-persp-buffer-not-in-persp 1556 'doom-modeline-persp-name)) 1557 (icon (doom-modeline-icon 'octicon "nf-oct-repo" "đŋ" "#" 1558 :face `(:inherit ,face :slant normal)))) 1559 (when (or doom-modeline-display-default-persp-name 1560 (not (string-equal persp-nil-name name))) 1561 (concat " " 1562 (propertize (concat (and doom-modeline-persp-icon 1563 (concat icon 1564 (propertize 1565 " " 1566 'display '((space :relative-width 0.5))))) 1567 (propertize name 'face face)) 1568 'help-echo "mouse-1: Switch perspective 1569 mouse-2: Show help for minor mode" 1570 'mouse-face 'doom-modeline-highlight 1571 'local-map (let ((map (make-sparse-keymap))) 1572 (define-key map [mode-line mouse-1] 1573 #'persp-switch) 1574 (define-key map [mode-line mouse-2] 1575 (lambda () 1576 (interactive) 1577 (describe-function 'persp-mode))) 1578 map)) 1579 " ")))))) 1580 1581 (add-hook 'buffer-list-update-hook #'doom-modeline-update-persp-name) 1582 (add-hook 'find-file-hook #'doom-modeline-update-persp-name) 1583 (add-hook 'persp-activated-functions #'doom-modeline-update-persp-name) 1584 (add-hook 'persp-renamed-functions #'doom-modeline-update-persp-name) 1585 (advice-add #'lv-message :after #'doom-modeline-update-persp-name) 1586 1587 (doom-modeline-def-segment persp-name 1588 "The current perspective name." 1589 (when (doom-modeline--segment-visible 'persp-name) 1590 doom-modeline--persp-name)) 1591 1592 1593 ;; 1594 ;; Misc info 1595 ;; 1596 1597 (doom-modeline-def-segment misc-info 1598 "Mode line construct for miscellaneous information. 1599 By default, this shows the information specified by `global-mode-string'." 1600 (when (and (doom-modeline--segment-visible 'misc-info) 1601 (or doom-modeline-display-misc-in-all-mode-lines 1602 (doom-modeline--active))) 1603 (doom-modeline-display-text 1604 (format-mode-line mode-line-misc-info)))) 1605 1606 1607 ;; 1608 ;; Position 1609 ;; 1610 1611 (doom-modeline-def-segment buffer-position 1612 "The buffer position information." 1613 (let ((visible (doom-modeline--segment-visible 'buffer-position)) 1614 (sep (doom-modeline-spc)) 1615 (wsep (doom-modeline-wspc)) 1616 (face (doom-modeline-face)) 1617 (help-echo "Buffer percentage\n\ 1618 mouse-1: Display Line and Column Mode Menu") 1619 (mouse-face 'doom-modeline-highlight) 1620 (local-map mode-line-column-line-number-mode-map)) 1621 `(,wsep 1622 1623 ;; Line and column 1624 (:propertize 1625 ((line-number-mode 1626 (column-number-mode 1627 (doom-modeline-column-zero-based 1628 doom-modeline-position-column-line-format 1629 ,(string-replace 1630 "%c" "%C" (car doom-modeline-position-column-line-format))) 1631 doom-modeline-position-line-format) 1632 (column-number-mode 1633 (doom-modeline-column-zero-based 1634 doom-modeline-position-column-format 1635 ,(string-replace 1636 "%c" "%C" (car doom-modeline-position-column-format))))) 1637 (doom-modeline-total-line-number 1638 ,(format "/%d" (line-number-at-pos (point-max))))) 1639 face ,face 1640 help-echo ,help-echo 1641 mouse-face ,mouse-face 1642 local-map ,local-map) 1643 1644 ((or line-number-mode column-number-mode) 1645 ,sep) 1646 1647 ;; Position 1648 (,visible 1649 ,(cond 1650 ((and (bound-and-true-p nyan-mode) 1651 (>= (window-width) nyan-minimum-window-width)) 1652 (concat sep (nyan-create) sep)) 1653 ((and (bound-and-true-p poke-line-mode) 1654 (>= (window-width) poke-line-minimum-window-width)) 1655 (concat sep (poke-line-create) sep)) 1656 ((and (bound-and-true-p mlscroll-mode) 1657 (>= (window-width) mlscroll-minimum-current-width)) 1658 (concat 1659 sep 1660 (let ((mlscroll-right-align nil)) 1661 (format-mode-line (mlscroll-mode-line))) 1662 sep)) 1663 ((and (bound-and-true-p sml-modeline-mode) 1664 (>= (window-width) sml-modeline-len)) 1665 (concat sep (sml-modeline-create) sep)) 1666 (t ""))) 1667 1668 ;; Percent position 1669 (doom-modeline-percent-position 1670 ((:propertize ("" doom-modeline-percent-position) 1671 face ,face 1672 help-echo ,help-echo 1673 mouse-face ,mouse-face 1674 local-map ,local-map) 1675 ,sep))))) 1676 1677 ;; 1678 ;; Party parrot 1679 ;; 1680 (doom-modeline-def-segment parrot 1681 "The party parrot animated icon. Requires `parrot-mode' to be enabled." 1682 (when (and (doom-modeline--segment-visible 'parrot) 1683 (bound-and-true-p parrot-mode)) 1684 (concat (doom-modeline-wspc) 1685 (parrot-create) 1686 (doom-modeline-spc)))) 1687 1688 ;; 1689 ;; Modals (evil, overwrite, god, ryo and xah-fly-keys, etc.) 1690 ;; 1691 1692 (defun doom-modeline--modal-icon (text face help-echo &optional icon unicode) 1693 "Display the model icon with FACE and HELP-ECHO. 1694 TEXT is alternative if icon is not available." 1695 (propertize (doom-modeline-icon 1696 'mdicon 1697 (and doom-modeline-modal-icon 1698 (or (and doom-modeline-modal-modern-icon icon) 1699 "nf-md-record")) 1700 (or (and doom-modeline-modal-modern-icon unicode) "â") 1701 text 1702 :face (doom-modeline-face face)) 1703 'help-echo help-echo)) 1704 1705 (defsubst doom-modeline--evil () 1706 "The current evil state. Requires `evil-mode' to be enabled." 1707 (when (bound-and-true-p evil-local-mode) 1708 (doom-modeline--modal-icon 1709 (let ((tag (evil-state-property evil-state :tag t))) 1710 (if (stringp tag) tag (funcall tag))) 1711 (cond 1712 ((evil-normal-state-p) 'doom-modeline-evil-normal-state) 1713 ((evil-emacs-state-p) 'doom-modeline-evil-emacs-state) 1714 ((evil-insert-state-p) 'doom-modeline-evil-insert-state) 1715 ((evil-motion-state-p) 'doom-modeline-evil-motion-state) 1716 ((evil-visual-state-p) 'doom-modeline-evil-visual-state) 1717 ((evil-operator-state-p) 'doom-modeline-evil-operator-state) 1718 ((evil-replace-state-p) 'doom-modeline-evil-replace-state) 1719 (t 'doom-modeline-evil-normal-state)) 1720 (evil-state-property evil-state :name t) 1721 (cond 1722 ((evil-normal-state-p) "nf-md-alpha_n_circle") 1723 ((evil-emacs-state-p) "nf-md-alpha_e_circle") 1724 ((evil-insert-state-p) "nf-md-alpha_i_circle") 1725 ((evil-motion-state-p) "nf-md-alpha_m_circle") 1726 ((evil-visual-state-p) "nf-md-alpha_v_circle") 1727 ((evil-operator-state-p) "nf-md-alpha_o_circle") 1728 ((evil-replace-state-p) "nf-md-alpha_r_circle") 1729 (t "nf-md-alpha_n_circle")) 1730 (cond 1731 ((evil-normal-state-p) "đ ") 1732 ((evil-emacs-state-p) "đ ") 1733 ((evil-insert-state-p) "đ ") 1734 ((evil-motion-state-p) "đ ") 1735 ((evil-visual-state-p) "đ Ĩ") 1736 ((evil-operator-state-p) "đ ") 1737 ((evil-replace-state-p) "đ Ą") 1738 (t "đ "))))) 1739 1740 (defsubst doom-modeline--overwrite () 1741 "The current overwrite state which is enabled by command `overwrite-mode'." 1742 (when (and (bound-and-true-p overwrite-mode) 1743 (not (bound-and-true-p evil-local-mode))) 1744 (doom-modeline--modal-icon 1745 "<W>" 'doom-modeline-overwrite "Overwrite mode" 1746 "nf-md-marker" "đ Ļ"))) 1747 1748 (defsubst doom-modeline--god () 1749 "The current god state which is enabled by the command `god-mode'." 1750 (when (bound-and-true-p god-local-mode) 1751 (doom-modeline--modal-icon 1752 "<G>" 'doom-modeline-god "God mode" 1753 "nf-md-account_circle" "đ "))) 1754 1755 (defsubst doom-modeline--ryo () 1756 "The current ryo-modal state which is enabled by the command `ryo-modal-mode'." 1757 (when (bound-and-true-p ryo-modal-mode) 1758 (doom-modeline--modal-icon 1759 "<R>" 'doom-modeline-ryo "Ryo modal" 1760 "nf-md-star_circle" "âĒ"))) 1761 1762 (defsubst doom-modeline--xah-fly-keys () 1763 "The current `xah-fly-keys' state." 1764 (when (bound-and-true-p xah-fly-keys) 1765 (if xah-fly-insert-state-p 1766 (doom-modeline--modal-icon 1767 "<I>" 'doom-modeline-fly-insert-state "Xah-fly insert mode" 1768 "nf-md-airplane_edit" "đ§") 1769 (doom-modeline--modal-icon 1770 "<C>" 'doom-modeline-fly-normal-state "Xah-fly command mode" 1771 "nf-md-airplane_cog" "đ§")))) 1772 1773 (defsubst doom-modeline--boon () 1774 "The current Boon state. Requires `boon-mode' to be enabled." 1775 (when (bound-and-true-p boon-local-mode) 1776 (doom-modeline--modal-icon 1777 (boon-state-string) 1778 (cond 1779 (boon-command-state 'doom-modeline-boon-command-state) 1780 (boon-insert-state 'doom-modeline-boon-insert-state) 1781 (boon-special-state 'doom-modeline-boon-special-state) 1782 (boon-off-state 'doom-modeline-boon-off-state) 1783 (t 'doom-modeline-boon-off-state)) 1784 (boon-modeline-string) 1785 "nf-md-coffee" "đĩ"))) 1786 1787 (defsubst doom-modeline--meow () 1788 "The current Meow state. Requires `meow-mode' to be enabled." 1789 (when (bound-and-true-p meow-mode) 1790 (doom-modeline--modal-icon 1791 (symbol-name (meow--current-state)) 1792 (cond 1793 ((meow-normal-mode-p) 'doom-modeline-evil-normal-state) 1794 ((meow-insert-mode-p) 'doom-modeline-evil-insert-state) 1795 ((meow-beacon-mode-p) 'doom-modeline-evil-visual-state) 1796 ((meow-motion-mode-p) 'doom-modeline-evil-motion-state) 1797 ((meow-keypad-mode-p) 'doom-modeline-evil-operator-state) 1798 (t 'doom-modeline-evil-normal-state)) 1799 (symbol-name (meow--current-state)) 1800 (cond 1801 ((meow-normal-mode-p) "nf-md-alpha_n_circle") 1802 ((meow-insert-mode-p) "nf-md-alpha_i_circle") 1803 ((meow-beacon-mode-p) "nf-md-alpha_b_circle") 1804 ((meow-motion-mode-p) "nf-md-alpha_m_circle") 1805 ((meow-keypad-mode-p) "nf-md-alpha_k_circle") 1806 (t "nf-md-alpha_n_circle")) 1807 (cond 1808 ((meow-normal-mode-p) "đ ") 1809 ((meow-insert-mode-p) "đ ") 1810 ((meow-beacon-mode-p) "đ ") 1811 ((meow-motion-mode-p) "đ ") 1812 ((meow-keypad-mode-p) "đ ") 1813 (t "đ "))))) 1814 1815 (doom-modeline-def-segment modals 1816 "Displays modal editing states. 1817 1818 Including `evil', `overwrite', `god', `ryo' and `xha-fly-kyes', etc." 1819 (when doom-modeline-modal 1820 (let* ((evil (doom-modeline--evil)) 1821 (ow (doom-modeline--overwrite)) 1822 (god (doom-modeline--god)) 1823 (ryo (doom-modeline--ryo)) 1824 (xf (doom-modeline--xah-fly-keys)) 1825 (boon (doom-modeline--boon)) 1826 (vsep (doom-modeline-vspc)) 1827 (meow (doom-modeline--meow)) 1828 (sep (and (or evil ow god ryo xf boon) (doom-modeline-spc)))) 1829 (concat sep 1830 (and evil (concat evil (and (or ow god ryo xf boon meow) vsep))) 1831 (and ow (concat ow (and (or god ryo xf boon meow) vsep))) 1832 (and god (concat god (and (or ryo xf boon meow) vsep))) 1833 (and ryo (concat ryo (and (or xf boon meow) vsep))) 1834 (and xf (concat xf (and (or boon meow) vsep))) 1835 (and boon (concat boon (and meow vsep))) 1836 meow 1837 sep)))) 1838 1839 ;; 1840 ;; Objed state 1841 ;; 1842 1843 (defvar doom-modeline--objed-active nil) 1844 1845 (defun doom-modeline-update-objed (_ &optional reset) 1846 "Update `objed' status, inactive when RESET is true." 1847 (setq doom-modeline--objed-active (not reset))) 1848 1849 (setq objed-modeline-setup-func #'doom-modeline-update-objed) 1850 1851 (doom-modeline-def-segment objed-state () 1852 "The current objed state." 1853 (when (and doom-modeline--objed-active 1854 (doom-modeline--active)) 1855 (propertize (format " %s(%s) " 1856 (symbol-name objed--object) 1857 (char-to-string (aref (symbol-name objed--obj-state) 0))) 1858 'face 'doom-modeline-evil-emacs-state 1859 'help-echo (format "Objed object: %s (%s)" 1860 (symbol-name objed--object) 1861 (symbol-name objed--obj-state))))) 1862 1863 1864 ;; 1865 ;; Input method 1866 ;; 1867 1868 (doom-modeline-def-segment input-method 1869 "The current input method." 1870 (when-let ((im (cond 1871 (current-input-method 1872 current-input-method-title) 1873 ((and (bound-and-true-p evil-local-mode) 1874 (bound-and-true-p evil-input-method)) 1875 (nth 3 (assoc default-input-method input-method-alist))) 1876 (t nil))) 1877 (sep (doom-modeline-spc))) 1878 (concat 1879 sep 1880 (propertize im 1881 'face (doom-modeline-face 1882 (if (and (bound-and-true-p rime-mode) 1883 (equal current-input-method "rime")) 1884 (if (and (rime--should-enable-p) 1885 (not (rime--should-inline-ascii-p))) 1886 'doom-modeline-input-method 1887 'doom-modeline-input-method-alt) 1888 'doom-modeline-input-method)) 1889 'help-echo (concat 1890 "Current input method: " 1891 current-input-method 1892 "\n\ 1893 mouse-2: Disable input method\n\ 1894 mouse-3: Describe current input method") 1895 'mouse-face 'doom-modeline-highlight 1896 'local-map mode-line-input-method-map) 1897 sep))) 1898 1899 1900 ;; 1901 ;; Info 1902 ;; 1903 1904 (doom-modeline-def-segment info-nodes 1905 "The topic and nodes in the Info buffer." 1906 (concat 1907 " (" 1908 ;; topic 1909 (propertize (if (stringp Info-current-file) 1910 (replace-regexp-in-string 1911 "%" "%%" 1912 (file-name-sans-extension 1913 (file-name-nondirectory Info-current-file))) 1914 (format "*%S*" Info-current-file)) 1915 'face (doom-modeline-face 'doom-modeline-info)) 1916 ") " 1917 ;; node 1918 (when Info-current-node 1919 (propertize (replace-regexp-in-string 1920 "%" "%%" Info-current-node) 1921 'face (doom-modeline-face 'doom-modeline-buffer-path) 1922 'help-echo 1923 "mouse-1: scroll forward, mouse-3: scroll back" 1924 'mouse-face 'doom-modeline-highlight 1925 'local-map Info-mode-line-node-keymap)))) 1926 1927 1928 ;; 1929 ;; REPL 1930 ;; 1931 1932 (defun doom-modeline-repl-icon (text face) 1933 "Display REPL icon (or TEXT in terminal) with FACE." 1934 (doom-modeline-icon 'faicon "nf-fa-terminal" "$" text :face face)) 1935 1936 (defvar doom-modeline--cider nil) 1937 1938 (defun doom-modeline-update-cider () 1939 "Update cider repl state." 1940 (setq doom-modeline--cider 1941 (let* ((connected (cider-connected-p)) 1942 (face (if connected 'doom-modeline-repl-success 'doom-modeline-repl-warning)) 1943 (repl-buffer (cider-current-repl nil nil)) 1944 (cider-info (when repl-buffer 1945 (cider--connection-info repl-buffer t))) 1946 (icon (doom-modeline-repl-icon "REPL" face))) 1947 (propertize icon 1948 'help-echo 1949 (if connected 1950 (format "CIDER Connected %s\nmouse-2: CIDER quit" cider-info) 1951 "CIDER Disconnected\nmouse-1: CIDER jack-in") 1952 'mouse-face 'doom-modeline-highlight 1953 'local-map (let ((map (make-sparse-keymap))) 1954 (if connected 1955 (define-key map [mode-line mouse-2] 1956 #'cider-quit) 1957 (define-key map [mode-line mouse-1] 1958 #'cider-jack-in)) 1959 map))))) 1960 1961 (add-hook 'cider-connected-hook #'doom-modeline-update-cider) 1962 (add-hook 'cider-disconnected-hook #'doom-modeline-update-cider) 1963 (add-hook 'cider-mode-hook #'doom-modeline-update-cider) 1964 1965 (doom-modeline-def-segment repl 1966 "The REPL state." 1967 (when doom-modeline-repl 1968 (when-let ((icon (when (bound-and-true-p cider-mode) 1969 doom-modeline--cider)) 1970 (sep (doom-modeline-spc))) 1971 (concat 1972 sep 1973 (doom-modeline-display-icon icon) 1974 sep)))) 1975 1976 1977 ;; 1978 ;; LSP 1979 ;; 1980 1981 (defun doom-modeline-lsp-icon (text face) 1982 "Display LSP icon (or TEXT in terminal) with FACE." 1983 (if doom-modeline-lsp-icon 1984 (doom-modeline-icon 'octicon "nf-oct-rocket" "đ" text :face face) 1985 (propertize text 'face face))) 1986 1987 (defvar-local doom-modeline--lsp nil) 1988 (defun doom-modeline-update-lsp (&rest _) 1989 "Update `lsp-mode' state." 1990 (setq doom-modeline--lsp 1991 (let* ((workspaces (lsp-workspaces)) 1992 (face (if workspaces 'doom-modeline-lsp-success 'doom-modeline-lsp-warning)) 1993 (icon (doom-modeline-lsp-icon "LSP" face))) 1994 (propertize icon 1995 'help-echo 1996 (if workspaces 1997 (concat "LSP Connected " 1998 (string-join 1999 (mapcar (lambda (w) 2000 (format "[%s]\n" (lsp--workspace-print w))) 2001 workspaces)) 2002 "C-mouse-1: Switch to another workspace folder 2003 mouse-1: Describe current session 2004 mouse-2: Quit server 2005 mouse-3: Reconnect to server") 2006 "LSP Disconnected 2007 mouse-1: Reload to start server") 2008 'mouse-face 'doom-modeline-highlight 2009 'local-map (let ((map (make-sparse-keymap))) 2010 (if workspaces 2011 (progn 2012 (define-key map [mode-line C-mouse-1] 2013 #'lsp-workspace-folders-open) 2014 (define-key map [mode-line mouse-1] 2015 #'lsp-describe-session) 2016 (define-key map [mode-line mouse-2] 2017 #'lsp-workspace-shutdown) 2018 (define-key map [mode-line mouse-3] 2019 #'lsp-workspace-restart)) 2020 (progn 2021 (define-key map [mode-line mouse-1] 2022 (lambda () 2023 (interactive) 2024 (ignore-errors (revert-buffer t t)))))) 2025 map))))) 2026 (add-hook 'lsp-before-initialize-hook #'doom-modeline-update-lsp) 2027 (add-hook 'lsp-after-initialize-hook #'doom-modeline-update-lsp) 2028 (add-hook 'lsp-after-uninitialized-functions #'doom-modeline-update-lsp) 2029 (add-hook 'lsp-before-open-hook #'doom-modeline-update-lsp) 2030 (add-hook 'lsp-after-open-hook #'doom-modeline-update-lsp) 2031 2032 (defun doom-modeline--eglot-pending-count (server) 2033 "Get count of pending eglot requests to SERVER." 2034 (if (fboundp 'jsonrpc-continuation-count) 2035 (jsonrpc-continuation-count server) 2036 (hash-table-count (jsonrpc--request-continuations server)))) 2037 2038 (defvar-local doom-modeline--eglot nil) 2039 (defun doom-modeline-update-eglot () 2040 "Update `eglot' state." 2041 (setq doom-modeline--eglot 2042 (pcase-let* ((server (and (eglot-managed-p) (eglot-current-server))) 2043 (nick (and server (eglot--project-nickname server))) 2044 (pending (and server (doom-modeline--eglot-pending-count server))) 2045 (last-error (and server (jsonrpc-last-error server))) 2046 (face (cond (last-error 'doom-modeline-lsp-error) 2047 ((and pending (cl-plusp pending)) 'doom-modeline-lsp-warning) 2048 (nick 'doom-modeline-lsp-success) 2049 (t 'doom-modeline-lsp-warning))) 2050 (icon (doom-modeline-lsp-icon "EGLOT" face))) 2051 (propertize icon 2052 'help-echo (cond 2053 (last-error 2054 (format "EGLOT\nAn error occured: %s 2055 mouse-3: Clear this status" (plist-get last-error :message))) 2056 ((and pending (cl-plusp pending)) 2057 (format "EGLOT\n%d outstanding requests" pending)) 2058 (nick (format "EGLOT Connected (%s/%s) 2059 C-mouse-1: Go to server errors 2060 mouse-1: Go to server events 2061 mouse-2: Quit server 2062 mouse-3: Reconnect to server" nick (eglot--major-modes server))) 2063 (t "EGLOT Disconnected 2064 mouse-1: Start server")) 2065 'mouse-face 'doom-modeline-highlight 2066 'local-map (let ((map (make-sparse-keymap))) 2067 (cond (last-error 2068 (define-key map [mode-line mouse-3] 2069 #'eglot-clear-status)) 2070 ((and pending (cl-plusp pending)) 2071 (define-key map [mode-line mouse-3] 2072 #'eglot-forget-pending-continuations)) 2073 (nick 2074 (define-key map [mode-line C-mouse-1] 2075 #'eglot-stderr-buffer) 2076 (define-key map [mode-line mouse-1] 2077 #'eglot-events-buffer) 2078 (define-key map [mode-line mouse-2] 2079 #'eglot-shutdown) 2080 (define-key map [mode-line mouse-3] 2081 #'eglot-reconnect)) 2082 (t (define-key map [mode-line mouse-1] 2083 #'eglot))) 2084 map))))) 2085 (add-hook 'eglot-managed-mode-hook #'doom-modeline-update-eglot) 2086 2087 (defvar-local doom-modeline--tags nil) 2088 (defun doom-modeline-update-tags () 2089 "Update tags state." 2090 (setq doom-modeline--tags 2091 (propertize 2092 (doom-modeline-lsp-icon "TAGS" 'doom-modeline-lsp-success) 2093 'help-echo "TAGS: Citre mode 2094 mouse-1: Toggle citre mode" 2095 'mouse-face 'doom-modeline-highlight 2096 'local-map (make-mode-line-mouse-map 'mouse-1 #'citre-mode)))) 2097 (add-hook 'citre-mode-hook #'doom-modeline-update-tags) 2098 2099 (defun doom-modeline-update-lsp-icon () 2100 "Update lsp icon." 2101 (cond ((bound-and-true-p lsp-mode) 2102 (doom-modeline-update-lsp)) 2103 ((bound-and-true-p eglot--managed-mode) 2104 (doom-modeline-update-eglot)) 2105 ((bound-and-true-p citre-mode) 2106 (doom-modeline-update-tags)))) 2107 2108 (doom-modeline-add-variable-watcher 2109 'doom-modeline-lsp-icon 2110 (lambda (_sym val op _where) 2111 (when (eq op 'set) 2112 (setq doom-modeline-lsp-icon val) 2113 (dolist (buf (buffer-list)) 2114 (with-current-buffer buf 2115 (doom-modeline-update-lsp-icon)))))) 2116 2117 (doom-modeline-add-variable-watcher 2118 'doom-modeline-icon 2119 (lambda (_sym val op _where) 2120 (when (eq op 'set) 2121 (setq doom-modeline-icon val) 2122 (dolist (buf (buffer-list)) 2123 (with-current-buffer buf 2124 (doom-modeline-update-lsp-icon)))))) 2125 2126 (doom-modeline-add-variable-watcher 2127 'doom-modeline-unicode-fallback 2128 (lambda (_sym val op _where) 2129 (when (eq op 'set) 2130 (setq doom-modeline-unicode-fallback val) 2131 (dolist (buf (buffer-list)) 2132 (with-current-buffer buf 2133 (doom-modeline-update-lsp-icon)))))) 2134 2135 (doom-modeline-def-segment lsp 2136 "The LSP server state." 2137 (when doom-modeline-lsp 2138 (when-let ((icon (cond ((bound-and-true-p lsp-mode) 2139 doom-modeline--lsp) 2140 ((bound-and-true-p eglot--managed-mode) 2141 doom-modeline--eglot) 2142 ((bound-and-true-p citre-mode) 2143 doom-modeline--tags))) 2144 (sep (doom-modeline-spc))) 2145 (concat 2146 sep 2147 (doom-modeline-display-icon icon) 2148 sep)))) 2149 2150 (defun doom-modeline-override-eglot () 2151 "Override `eglot' mode-line." 2152 (if (and doom-modeline-lsp 2153 (bound-and-true-p doom-modeline-mode)) 2154 (setq mode-line-misc-info 2155 (delq (assq 'eglot--managed-mode mode-line-misc-info) mode-line-misc-info)) 2156 (add-to-list 'mode-line-misc-info 2157 `(eglot--managed-mode (" [" eglot--mode-line-format "] "))))) 2158 (add-hook 'eglot-managed-mode-hook #'doom-modeline-override-eglot) 2159 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-eglot) 2160 2161 (doom-modeline-add-variable-watcher 2162 'doom-modeline-battery 2163 (lambda (_sym val op _where) 2164 (when (eq op 'set) 2165 (setq doom-modeline-lsp val) 2166 (doom-modeline-override-eglot)))) 2167 2168 2169 ;; 2170 ;; GitHub 2171 ;; 2172 2173 (defvar doom-modeline--github-notification-number 0) 2174 (defvar doom-modeline-before-github-fetch-notification-hook nil 2175 "Hooks before fetching GitHub notifications. 2176 Example: 2177 (add-hook \\='doom-modeline-before-github-fetch-notification-hook 2178 #\\='auth-source-pass-enable)") 2179 2180 (defvar doom-modeline-after-github-fetch-notification-hook nil 2181 "Hooks after fetching GitHub notifications.") 2182 2183 (defun doom-modeline--github-fetch-notifications () 2184 "Fetch GitHub notifications." 2185 (when (and doom-modeline-github 2186 (require 'async nil t)) 2187 (async-start 2188 `(lambda () 2189 ,(async-inject-variables 2190 "\\`\\(load-path\\|auth-sources\\|doom-modeline-before-github-fetch-notification-hook\\)\\'") 2191 (run-hooks 'doom-modeline-before-github-fetch-notification-hook) 2192 (when (require 'ghub nil t) 2193 (with-timeout (10) 2194 (ignore-errors 2195 (when-let* ((username (ghub--username ghub-default-host)) 2196 (token (or (ghub--token ghub-default-host username 'forge t) 2197 (ghub--token ghub-default-host username 'ghub t)))) 2198 (ghub-get "/notifications" 2199 '((notifications . t)) 2200 :host ghub-default-host 2201 :username username 2202 :auth token 2203 :unpaginate t 2204 :noerror t)))))) 2205 (lambda (result) 2206 (message "") ; suppress message 2207 (setq doom-modeline--github-notification-number (length result)) 2208 (run-hooks 'doom-modeline-after-github-fetch-notification-hook))))) 2209 2210 (defvar doom-modeline--github-timer nil) 2211 (defun doom-modeline-github-timer () 2212 "Start/Stop the timer for GitHub fetching." 2213 (if (timerp doom-modeline--github-timer) 2214 (cancel-timer doom-modeline--github-timer)) 2215 (setq doom-modeline--github-timer 2216 (and doom-modeline-github 2217 (run-with-idle-timer 30 2218 doom-modeline-github-interval 2219 #'doom-modeline--github-fetch-notifications)))) 2220 2221 (doom-modeline-add-variable-watcher 2222 'doom-modeline-github 2223 (lambda (_sym val op _where) 2224 (when (eq op 'set) 2225 (setq doom-modeline-github val) 2226 (doom-modeline-github-timer)))) 2227 2228 (doom-modeline-github-timer) 2229 2230 (doom-modeline-def-segment github 2231 "The GitHub notifications." 2232 (when (and doom-modeline-github 2233 (doom-modeline--segment-visible 'github) 2234 (numberp doom-modeline--github-notification-number)) 2235 (let ((sep (doom-modeline-spc))) 2236 (concat 2237 sep 2238 (propertize 2239 (concat 2240 (doom-modeline-icon 'octicon "nf-oct-mark_github" "đ" "&" 2241 :face 'doom-modeline-notification) 2242 (and (> doom-modeline--github-notification-number 0) (doom-modeline-vspc)) 2243 (propertize 2244 (cond 2245 ((<= doom-modeline--github-notification-number 0) "") 2246 ((> doom-modeline--github-notification-number 99) "99+") 2247 (t (number-to-string doom-modeline--github-notification-number))) 2248 'face '(:inherit 2249 (doom-modeline-unread-number doom-modeline-notification)))) 2250 'help-echo "Github Notifications 2251 mouse-1: Show notifications 2252 mouse-3: Fetch notifications" 2253 'mouse-face 'doom-modeline-highlight 2254 'local-map (let ((map (make-sparse-keymap))) 2255 (define-key map [mode-line mouse-1] 2256 (lambda () 2257 "Open GitHub notifications page." 2258 (interactive) 2259 (run-with-idle-timer 300 nil #'doom-modeline--github-fetch-notifications) 2260 (browse-url "https://github.com/notifications"))) 2261 (define-key map [mode-line mouse-3] 2262 (lambda () 2263 "Fetching GitHub notifications." 2264 (interactive) 2265 (message "Fetching GitHub notifications...") 2266 (doom-modeline--github-fetch-notifications))) 2267 map)) 2268 sep)))) 2269 2270 2271 ;; 2272 ;; Debug states 2273 ;; 2274 2275 ;; Highlight the doom-modeline while debugging. 2276 (defvar-local doom-modeline--debug-cookie nil) 2277 (defun doom-modeline--debug-visual (&rest _) 2278 "Update the face of mode-line for debugging." 2279 (mapc (lambda (buffer) 2280 (with-current-buffer buffer 2281 (setq doom-modeline--debug-cookie 2282 (face-remap-add-relative 'doom-modeline 'doom-modeline-debug-visual)) 2283 (force-mode-line-update))) 2284 (buffer-list))) 2285 2286 (defun doom-modeline--normal-visual (&rest _) 2287 "Restore the face of mode-line." 2288 (mapc (lambda (buffer) 2289 (with-current-buffer buffer 2290 (when doom-modeline--debug-cookie 2291 (face-remap-remove-relative doom-modeline--debug-cookie) 2292 (force-mode-line-update)))) 2293 (buffer-list))) 2294 2295 (add-hook 'dap-session-created-hook #'doom-modeline--debug-visual) 2296 (add-hook 'dap-terminated-hook #'doom-modeline--normal-visual) 2297 2298 (defun doom-modeline-debug-icon (face) 2299 "Display debug icon with FACE and ARGS." 2300 (doom-modeline-icon 'codicon "nf-cod-debug" "đ" "!" :face face)) 2301 2302 (defun doom-modeline--debug-dap () 2303 "The current `dap-mode' state." 2304 (when (and (bound-and-true-p dap-mode) 2305 (bound-and-true-p lsp-mode)) 2306 (when-let ((session (dap--cur-session))) 2307 (when (dap--session-running session) 2308 (propertize (doom-modeline-debug-icon 'doom-modeline-info) 2309 'help-echo (format "DAP (%s - %s) 2310 mouse-1: Display debug hydra 2311 mouse-2: Display recent configurations 2312 mouse-3: Disconnect session" 2313 (dap--debug-session-name session) 2314 (dap--debug-session-state session)) 2315 'mouse-face 'doom-modeline-highlight 2316 'local-map (let ((map (make-sparse-keymap))) 2317 (define-key map [mode-line mouse-1] 2318 #'dap-hydra) 2319 (define-key map [mode-line mouse-2] 2320 #'dap-debug-recent) 2321 (define-key map [mode-line mouse-3] 2322 #'dap-disconnect) 2323 map)))))) 2324 2325 (defvar-local doom-modeline--debug-dap nil) 2326 (defun doom-modeline-update-debug-dap (&rest _) 2327 "Update dap debug state." 2328 (setq doom-modeline--debug-dap (doom-modeline--debug-dap))) 2329 2330 (add-hook 'dap-session-created-hook #'doom-modeline-update-debug-dap) 2331 (add-hook 'dap-session-changed-hook #'doom-modeline-update-debug-dap) 2332 (add-hook 'dap-terminated-hook #'doom-modeline-update-debug-dap) 2333 2334 (defsubst doom-modeline--debug-edebug () 2335 "The current `edebug' state." 2336 (when (bound-and-true-p edebug-mode) 2337 (propertize (doom-modeline-debug-icon 'doom-modeline-info) 2338 'help-echo (format "EDebug (%s) 2339 mouse-1: Show help 2340 mouse-2: Next 2341 mouse-3: Stop debugging" 2342 edebug-execution-mode) 2343 'mouse-face 'doom-modeline-highlight 2344 'local-map (let ((map (make-sparse-keymap))) 2345 (define-key map [mode-line mouse-1] 2346 #'edebug-help) 2347 (define-key map [mode-line mouse-2] 2348 #'edebug-next-mode) 2349 (define-key map [mode-line mouse-3] 2350 #'edebug-stop) 2351 map)))) 2352 2353 (defsubst doom-modeline--debug-on-error () 2354 "The current `debug-on-error' state." 2355 (when debug-on-error 2356 (propertize (doom-modeline-debug-icon 'doom-modeline-urgent) 2357 'help-echo "Debug on Error 2358 mouse-1: Toggle Debug on Error" 2359 'mouse-face 'doom-modeline-highlight 2360 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-error)))) 2361 2362 (defsubst doom-modeline--debug-on-quit () 2363 "The current `debug-on-quit' state." 2364 (when debug-on-quit 2365 (propertize (doom-modeline-debug-icon 'doom-modeline-warning) 2366 'help-echo "Debug on Quit 2367 mouse-1: Toggle Debug on Quit" 2368 'mouse-face 'doom-modeline-highlight 2369 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-quit)))) 2370 2371 (doom-modeline-def-segment debug 2372 "The current debug state." 2373 (when (doom-modeline--segment-visible 'debug) 2374 (let* ((dap doom-modeline--debug-dap) 2375 (edebug (doom-modeline--debug-edebug)) 2376 (on-error (doom-modeline--debug-on-error)) 2377 (on-quit (doom-modeline--debug-on-quit)) 2378 (vsep (doom-modeline-vspc)) 2379 (sep (and (or dap edebug on-error on-quit) (doom-modeline-spc)))) 2380 (concat sep 2381 (and dap (concat dap (and (or edebug on-error on-quit) vsep))) 2382 (and edebug (concat edebug (and (or on-error on-quit) vsep))) 2383 (and on-error (concat on-error (and on-quit vsep))) 2384 on-quit 2385 sep)))) 2386 2387 2388 ;; 2389 ;; PDF pages 2390 ;; 2391 2392 (defvar-local doom-modeline--pdf-pages nil) 2393 (defun doom-modeline-update-pdf-pages () 2394 "Update PDF pages." 2395 (setq doom-modeline--pdf-pages 2396 (format " P%d/%d " 2397 (or (eval `(pdf-view-current-page)) 0) 2398 (pdf-cache-number-of-pages)))) 2399 (add-hook 'pdf-view-change-page-hook #'doom-modeline-update-pdf-pages) 2400 2401 (doom-modeline-def-segment pdf-pages 2402 "Display PDF pages." 2403 doom-modeline--pdf-pages) 2404 2405 2406 ;; 2407 ;; `mu4e' notifications 2408 ;; 2409 2410 (doom-modeline-def-segment mu4e 2411 "Show notifications of any unread emails in `mu4e'." 2412 (when (and doom-modeline-mu4e 2413 (doom-modeline--segment-visible 'mu4e)) 2414 (let ((sep (doom-modeline-spc)) 2415 (vsep (doom-modeline-vspc)) 2416 (icon (doom-modeline-icon 'mdicon "nf-md-email" "đ§" "#" 2417 :face 'doom-modeline-notification))) 2418 (cond ((and (bound-and-true-p mu4e-alert-mode-line) 2419 (numberp mu4e-alert-mode-line) 2420 ;; don't display if the unread mails count is zero 2421 (> mu4e-alert-mode-line 0)) 2422 (concat 2423 sep 2424 (propertize 2425 (concat 2426 icon 2427 vsep 2428 (propertize 2429 (if (> mu4e-alert-mode-line doom-modeline-number-limit) 2430 (format "%d+" doom-modeline-number-limit) 2431 (number-to-string mu4e-alert-mode-line)) 2432 'face '(:inherit 2433 (doom-modeline-unread-number doom-modeline-notification)))) 2434 'mouse-face 'doom-modeline-highlight 2435 'keymap '(mode-line keymap 2436 (mouse-1 . mu4e-alert-view-unread-mails) 2437 (mouse-2 . mu4e-alert-view-unread-mails) 2438 (mouse-3 . mu4e-alert-view-unread-mails)) 2439 'help-echo (concat (if (= mu4e-alert-mode-line 1) 2440 "You have an unread email" 2441 (format "You have %s unread emails" mu4e-alert-mode-line)) 2442 "\nClick here to view " 2443 (if (= mu4e-alert-mode-line 1) "it" "them"))) 2444 sep)) 2445 ((bound-and-true-p mu4e-modeline-mode) 2446 (concat sep icon vsep 2447 (propertize (mu4e--modeline-string) 2448 'face 'doom-modeline-notification) 2449 sep)))))) 2450 2451 (defun doom-modeline-override-mu4e-alert (&rest _) 2452 "Delete `mu4e-alert-mode-line' from global modeline string." 2453 (when (and (featurep 'mu4e-alert) 2454 (bound-and-true-p mu4e-alert-mode-line)) 2455 (if (and doom-modeline-mu4e 2456 (bound-and-true-p doom-modeline-mode)) 2457 ;; Delete original modeline 2458 (progn 2459 (setq global-mode-string 2460 (delete '(:eval mu4e-alert-mode-line) global-mode-string)) 2461 (setq mu4e-alert-modeline-formatter #'identity)) 2462 ;; Recover default settings 2463 (setq mu4e-alert-modeline-formatter #'mu4e-alert-default-mode-line-formatter)))) 2464 (advice-add #'mu4e-alert-enable-mode-line-display 2465 :after #'doom-modeline-override-mu4e-alert) 2466 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-alert) 2467 2468 (defun doom-modeline-override-mu4e-modeline (&rest _) 2469 "Delete `mu4e-alert-mode-line' from global modeline string." 2470 (when (bound-and-true-p mu4e-modeline-mode) 2471 (if (and doom-modeline-mu4e 2472 (bound-and-true-p doom-modeline-mode)) 2473 ;; Delete original modeline 2474 (setq global-mode-string 2475 (delete mu4e--modeline-item global-mode-string)) 2476 ;; Recover default settings 2477 (add-to-list 'global-mode-string mu4e--modeline-item)))) 2478 (add-hook 'mu4e-modeline-mode-hook #'doom-modeline-override-mu4e-modeline) 2479 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-modeline) 2480 2481 (doom-modeline-add-variable-watcher 2482 'doom-modeline-mu4e 2483 (lambda (_sym val op _where) 2484 (when (eq op 'set) 2485 (setq doom-modeline-mu4e val) 2486 (doom-modeline-override-mu4e-alert) 2487 (doom-modeline-override-mu4e-modeline)))) 2488 2489 2490 ;; 2491 ;; `gnus' notifications 2492 ;; 2493 2494 (defvar doom-modeline--gnus-unread-mail 0) 2495 (defvar doom-modeline--gnus-started nil 2496 "Used to determine if gnus has started.") 2497 (defun doom-modeline-update-gnus-status (&rest _) 2498 "Get the total number of unread news of gnus group." 2499 (setq doom-modeline--gnus-unread-mail 2500 (when (and doom-modeline-gnus 2501 doom-modeline--gnus-started) 2502 (let ((total-unread-news-number 0)) 2503 (mapc (lambda (g) 2504 (let* ((group (car g)) 2505 (unread (eval `(gnus-group-unread ,group)))) 2506 (when (and (not (seq-contains-p doom-modeline-gnus-excluded-groups group)) 2507 (numberp unread) 2508 (> unread 0)) 2509 (setq total-unread-news-number (+ total-unread-news-number unread))))) 2510 gnus-newsrc-alist) 2511 total-unread-news-number)))) 2512 2513 ;; Update the modeline after changes have been made 2514 (add-hook 'gnus-group-update-hook #'doom-modeline-update-gnus-status) 2515 (add-hook 'gnus-summary-update-hook #'doom-modeline-update-gnus-status) 2516 (add-hook 'gnus-group-update-group-hook #'doom-modeline-update-gnus-status) 2517 (add-hook 'gnus-after-getting-new-news-hook #'doom-modeline-update-gnus-status) 2518 2519 ;; Only start to listen to gnus when gnus is actually running 2520 (defun doom-modeline-start-gnus-listener () 2521 "Start GNUS listener." 2522 (when (and doom-modeline-gnus 2523 (not doom-modeline--gnus-started)) 2524 (setq doom-modeline--gnus-started t) 2525 ;; Scan gnus in the background if the timer is higher than 0 2526 (doom-modeline-update-gnus-status) 2527 (if (> doom-modeline-gnus-timer 0) 2528 (gnus-demon-add-handler 'gnus-demon-scan-news doom-modeline-gnus-timer doom-modeline-gnus-idle)))) 2529 (add-hook 'gnus-started-hook #'doom-modeline-start-gnus-listener) 2530 2531 ;; Stop the listener if gnus isn't running 2532 (defun doom-modeline-stop-gnus-listener () 2533 "Stop GNUS listener." 2534 (setq doom-modeline--gnus-started nil)) 2535 (add-hook 'gnus-exit-gnus-hook #'doom-modeline-stop-gnus-listener) 2536 2537 (doom-modeline-def-segment gnus 2538 "Show notifications of any unread emails in `gnus'." 2539 (when (and (doom-modeline--segment-visible 'gnus) 2540 doom-modeline-gnus 2541 doom-modeline--gnus-started 2542 ;; Don't display if the unread mails count is zero 2543 (numberp doom-modeline--gnus-unread-mail) 2544 (> doom-modeline--gnus-unread-mail 0)) 2545 (let ((sep (doom-modeline-spc)) 2546 (vsep (doom-modeline-vspc))) 2547 (concat 2548 sep 2549 (propertize 2550 (concat 2551 (doom-modeline-icon 'mdicon "nf-md-email" "đ§" "#" 2552 :face 'doom-modeline-notification) 2553 vsep 2554 (propertize 2555 (if (> doom-modeline--gnus-unread-mail doom-modeline-number-limit) 2556 (format "%d+" doom-modeline-number-limit) 2557 (number-to-string doom-modeline--gnus-unread-mail)) 2558 'face '(:inherit 2559 (doom-modeline-unread-number doom-modeline-notification)))) 2560 'mouse-face 'doom-modeline-highlight 2561 'help-echo (if (= doom-modeline--gnus-unread-mail 1) 2562 "You have an unread email" 2563 (format "You have %s unread emails" doom-modeline--gnus-unread-mail))) 2564 sep)))) 2565 2566 2567 ;; 2568 ;; IRC notifications 2569 ;; 2570 2571 (defun doom-modeline--shorten-irc (name) 2572 "Wrapper for `tracking-shorten' and `erc-track-shorten-function' with NAME. 2573 2574 One key difference is that when `tracking-shorten' and 2575 `erc-track-shorten-function' returns nil we will instead return the original 2576 value of name. This is necessary in cases where the user has stylized the name 2577 to be an icon and we don't want to remove that so we just return the original." 2578 (or (and (boundp 'tracking-shorten) 2579 (car (tracking-shorten (list name)))) 2580 (and (boundp 'erc-track-shorten-function) 2581 (functionp erc-track-shorten-function) 2582 (car (funcall erc-track-shorten-function (list name)))) 2583 (and (boundp 'rcirc-short-buffer-name) 2584 (rcirc-short-buffer-name name)) 2585 name)) 2586 2587 (defun doom-modeline--tracking-buffers (buffers) 2588 "Logic to convert some irc BUFFERS to their font-awesome icon." 2589 (mapconcat 2590 (lambda (b) 2591 (propertize 2592 (doom-modeline--shorten-irc (funcall doom-modeline-irc-stylize b)) 2593 'face '(:inherit (doom-modeline-unread-number doom-modeline-notification)) 2594 'help-echo (format "IRC Notification: %s\nmouse-1: Switch to buffer" b) 2595 'mouse-face 'doom-modeline-highlight 2596 'local-map (make-mode-line-mouse-map 2597 'mouse-1 2598 (lambda () 2599 (interactive) 2600 (when (buffer-live-p (get-buffer b)) 2601 (switch-to-buffer b)))))) 2602 buffers 2603 (doom-modeline-vspc))) 2604 2605 (defun doom-modeline--circe-p () 2606 "Check if `circe' is in use." 2607 (boundp 'tracking-mode-line-buffers)) 2608 2609 (defun doom-modeline--erc-p () 2610 "Check if `erc' is in use." 2611 (boundp 'erc-modified-channels-alist)) 2612 2613 (defun doom-modeline--rcirc-p () 2614 "Check if `rcirc' is in use." 2615 (bound-and-true-p rcirc-track-minor-mode)) 2616 2617 (defun doom-modeline--get-buffers () 2618 "Gets the buffers that have activity." 2619 (cond 2620 ((doom-modeline--circe-p) 2621 tracking-buffers) 2622 ((doom-modeline--erc-p) 2623 (mapcar (lambda (l) 2624 (buffer-name (car l))) 2625 erc-modified-channels-alist)) 2626 ((doom-modeline--rcirc-p) 2627 (mapcar (lambda (b) 2628 (buffer-name b)) 2629 rcirc-activity)))) 2630 2631 ;; Create a modeline segment that contains all the irc tracked buffers 2632 (doom-modeline-def-segment irc-buffers 2633 "The list of shortened, unread irc buffers." 2634 (when (and doom-modeline-irc 2635 (doom-modeline--segment-visible 'irc-buffers)) 2636 (let* ((buffers (doom-modeline--get-buffers)) 2637 (number (length buffers)) 2638 (sep (doom-modeline-spc))) 2639 (when (> number 0) 2640 (concat 2641 sep 2642 (doom-modeline--tracking-buffers buffers) 2643 sep))))) 2644 2645 (doom-modeline-def-segment irc 2646 "A notification icon for any unread irc buffer." 2647 (when (and doom-modeline-irc 2648 (doom-modeline--segment-visible 'irc)) 2649 (let* ((buffers (doom-modeline--get-buffers)) 2650 (number (length buffers)) 2651 (sep (doom-modeline-spc)) 2652 (vsep (doom-modeline-vspc))) 2653 (when (> number 0) 2654 (concat 2655 sep 2656 2657 (propertize (concat 2658 (doom-modeline-icon 'mdicon "nf-md-message_processing" "đ" "#" 2659 :face 'doom-modeline-notification) 2660 vsep 2661 ;; Display the number of unread buffers 2662 (propertize (number-to-string number) 2663 'face '(:inherit 2664 (doom-modeline-unread-number 2665 doom-modeline-notification)))) 2666 'help-echo (format "IRC Notifications: %s\n%s" 2667 (mapconcat 2668 (lambda (b) (funcall doom-modeline-irc-stylize b)) 2669 buffers 2670 ", ") 2671 (cond 2672 ((doom-modeline--circe-p) 2673 "mouse-1: Switch to previous unread buffer 2674 mouse-3: Switch to next unread buffer") 2675 ((doom-modeline--erc-p) 2676 "mouse-1: Switch to buffer 2677 mouse-3: Switch to next unread buffer") 2678 ((doom-modeline--rcirc-p) 2679 "mouse-1: Switch to server buffer 2680 mouse-3: Switch to next unread buffer"))) 2681 'mouse-face 'doom-modeline-highlight 2682 'local-map (let ((map (make-sparse-keymap))) 2683 (cond 2684 ((doom-modeline--circe-p) 2685 (define-key map [mode-line mouse-1] 2686 #'tracking-previous-buffer) 2687 (define-key map [mode-line mouse-3] 2688 #'tracking-next-buffer)) 2689 ((doom-modeline--erc-p) 2690 (define-key map [mode-line mouse-1] 2691 #'erc-switch-to-buffer) 2692 (define-key map [mode-line mouse-3] 2693 #'erc-track-switch-buffer)) 2694 ((doom-modeline--rcirc-p) 2695 (define-key map [mode-line mouse-1] 2696 #'rcirc-switch-to-server-buffer) 2697 (define-key map [mode-line mouse-3] 2698 #'rcirc-next-active-buffer))) 2699 map)) 2700 2701 ;; Display the unread irc buffers as well 2702 (when doom-modeline-irc-buffers 2703 (concat sep (doom-modeline--tracking-buffers buffers))) 2704 2705 sep))))) 2706 2707 (defun doom-modeline-override-rcirc () 2708 "Override default `rcirc' mode-line." 2709 (if (and doom-modeline-irc 2710 (bound-and-true-p doom-modeline-mode)) 2711 (setq global-mode-string 2712 (delq 'rcirc-activity-string global-mode-string)) 2713 (when (and rcirc-track-minor-mode 2714 (not (memq 'rcirc-activity-string global-mode-string))) 2715 (setq global-mode-string 2716 (append global-mode-string '(rcirc-activity-string)))))) 2717 (add-hook 'rcirc-track-minor-mode-hook #'doom-modeline-override-rcirc) 2718 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-rcirc) 2719 2720 (doom-modeline-add-variable-watcher 2721 'doom-modeline-irc 2722 (lambda (_sym val op _where) 2723 (when (eq op 'set) 2724 (setq doom-modeline-irc val) 2725 (doom-modeline-override-rcirc)))) 2726 2727 2728 ;; 2729 ;; Battery status 2730 ;; 2731 2732 (defun doom-modeline-battery-icon (icon unicode text face) 2733 "Displays the battery ICON with FACE. 2734 2735 UNICODE and TEXT are fallbacks. 2736 Uses `nerd-icons-mdicon' to fetch the icon." 2737 (doom-modeline-icon 'mdicon icon unicode text :face face)) 2738 2739 (defvar doom-modeline--battery-status nil) 2740 (defun doom-modeline-update-battery-status () 2741 "Update battery status." 2742 (setq doom-modeline--battery-status 2743 (when (and doom-modeline-battery 2744 (bound-and-true-p display-battery-mode)) 2745 (let* ((data (and battery-status-function 2746 (functionp battery-status-function) 2747 (funcall battery-status-function))) 2748 (status (cdr (assoc ?L data))) 2749 (charging? (or (string-equal "AC" status) 2750 (string-equal "on-line" status))) 2751 (percentage (car (read-from-string (or (cdr (assq ?p data)) "ERR")))) 2752 (valid-percentage? (and (numberp percentage) 2753 (>= percentage 0) 2754 (<= percentage battery-mode-line-limit))) 2755 (face (if valid-percentage? 2756 (cond (charging? 'doom-modeline-battery-charging) 2757 ((< percentage battery-load-critical) 'doom-modeline-battery-critical) 2758 ((< percentage 25) 'doom-modeline-battery-warning) 2759 ((< percentage 95) 'doom-modeline-battery-normal) 2760 (t 'doom-modeline-battery-full)) 2761 'doom-modeline-battery-error)) 2762 (icon (if valid-percentage? 2763 (cond 2764 ((>= percentage 100) 2765 (doom-modeline-battery-icon (if charging? 2766 "nf-md-battery_charging_100" 2767 "nf-md-battery") 2768 "đ" "-" face)) 2769 ((>= percentage 90) 2770 (doom-modeline-battery-icon (if charging? 2771 "nf-md-battery_charging_90" 2772 "nf-md-battery_90") 2773 "đ" "-" face)) 2774 ((>= percentage 80) 2775 (doom-modeline-battery-icon (if charging? 2776 "nf-md-battery_charging_80" 2777 "nf-md-battery_80") 2778 "đ" "-" face)) 2779 ((>= percentage 70) 2780 (doom-modeline-battery-icon (if charging? 2781 "nf-md-battery_charging_70" 2782 "nf-md-battery_70") 2783 "đ" "-" face)) 2784 ((>= percentage 60) 2785 (doom-modeline-battery-icon (if charging? 2786 "nf-md-battery_charging_60" 2787 "nf-md-battery_60") 2788 "đ" "-" face)) 2789 ((>= percentage 50) 2790 (doom-modeline-battery-icon (if charging? 2791 "nf-md-battery_charging_50" 2792 "nf-md-battery_50") 2793 "đ" "-" face)) 2794 ((>= percentage 40) 2795 (doom-modeline-battery-icon (if charging? 2796 "nf-md-battery_charging_40" 2797 "nf-md-battery_40") 2798 "đ" "-" face)) 2799 ((>= percentage 30) 2800 (doom-modeline-battery-icon (if charging? 2801 "nf-md-battery_charging_30" 2802 "nf-md-battery_30") 2803 "đ" "-" face)) 2804 ((>= percentage 20) 2805 (doom-modeline-battery-icon (if charging? 2806 "nf-md-battery_charging_20" 2807 "nf-md-battery_20") 2808 "đ" "-" face)) 2809 ((>= percentage 10) 2810 (doom-modeline-battery-icon (if charging? 2811 "nf-md-battery_charging_10" 2812 "nf-md-battery_10") 2813 "đĒĢ" "-" face)) 2814 (t (doom-modeline-battery-icon (if charging? 2815 "nf-md-battery_charging_outline" 2816 "nf-md-battery_outline") 2817 "đĒĢ" "!" face))) 2818 (doom-modeline-battery-icon "nf-md-battery_alert" "â " "N/A" face))) 2819 (text (if valid-percentage? (format "%d%s" percentage "%%") "")) 2820 (help-echo (if (and battery-echo-area-format data valid-percentage?) 2821 (battery-format battery-echo-area-format data) 2822 "Battery status not available"))) 2823 (cons (propertize icon 'help-echo help-echo) 2824 (propertize text 'face face 'help-echo help-echo)))))) 2825 2826 (doom-modeline-add-variable-watcher 2827 'doom-modeline-icon 2828 (lambda (_sym val op _where) 2829 (when (eq op 'set) 2830 (setq doom-modeline-icon val) 2831 (doom-modeline-update-battery-status)))) 2832 2833 (doom-modeline-add-variable-watcher 2834 'doom-modeline-unicode-fallback 2835 (lambda (_sym val op _where) 2836 (when (eq op 'set) 2837 (setq doom-modeline-unicode-fallback val) 2838 (doom-modeline-update-battery-status)))) 2839 2840 (doom-modeline-def-segment battery 2841 "Display battery status." 2842 (when (and doom-modeline-battery 2843 (bound-and-true-p display-battery-mode) 2844 (doom-modeline--segment-visible 'battery)) 2845 (let ((sep (doom-modeline-spc)) 2846 (vsep (doom-modeline-vspc))) 2847 (concat sep 2848 (car doom-modeline--battery-status) 2849 vsep 2850 (cdr doom-modeline--battery-status) 2851 sep)))) 2852 2853 (defun doom-modeline-override-battery () 2854 "Override default battery mode-line." 2855 (if (and doom-modeline-battery 2856 (bound-and-true-p doom-modeline-mode)) 2857 (progn 2858 (advice-add #'battery-update :override #'doom-modeline-update-battery-status) 2859 (setq global-mode-string 2860 (delq 'battery-mode-line-string global-mode-string)) 2861 (and (bound-and-true-p display-battery-mode) (battery-update))) 2862 (progn 2863 (advice-remove #'battery-update #'doom-modeline-update-battery-status) 2864 (when (and display-battery-mode battery-status-function battery-mode-line-format 2865 (not (memq 'battery-mode-line-string global-mode-string))) 2866 (setq global-mode-string 2867 (append global-mode-string '(battery-mode-line-string))))))) 2868 (add-hook 'display-battery-mode-hook #'doom-modeline-override-battery) 2869 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-battery) 2870 2871 (doom-modeline-add-variable-watcher 2872 'doom-modeline-battery 2873 (lambda (_sym val op _where) 2874 (when (eq op 'set) 2875 (setq doom-modeline-battery val) 2876 (doom-modeline-override-battery)))) 2877 2878 2879 ;; 2880 ;; Package information 2881 ;; 2882 2883 (doom-modeline-def-segment package 2884 "Show package information via `paradox'." 2885 (concat 2886 (doom-modeline-display-text 2887 (format-mode-line 'mode-line-front-space)) 2888 2889 (when (and doom-modeline-icon doom-modeline-major-mode-icon) 2890 (concat 2891 (doom-modeline-spc) 2892 (doom-modeline-icon 'faicon "nf-fa-archive" nil nil 2893 :face (doom-modeline-face 2894 (if doom-modeline-major-mode-color-icon 2895 'nerd-icons-silver 2896 'mode-line))))) 2897 (doom-modeline-display-text 2898 (format-mode-line 'mode-line-buffer-identification)))) 2899 2900 2901 ;; 2902 ;; Helm 2903 ;; 2904 2905 (defvar doom-modeline--helm-buffer-ids 2906 '(("*helm*" . "HELM") 2907 ("*helm M-x*" . "HELM M-x") 2908 ("*swiper*" . "SWIPER") 2909 ("*Projectile Perspectives*" . "HELM Projectile Perspectives") 2910 ("*Projectile Layouts*" . "HELM Projectile Layouts") 2911 ("*helm-ag*" . (lambda () 2912 (format "HELM Ag: Using %s" 2913 (car (split-string helm-ag-base-command)))))) 2914 "Alist of custom helm buffer names to use. 2915 The cdr can also be a function that returns a name to use.") 2916 2917 (doom-modeline-def-segment helm-buffer-id 2918 "Helm session identifier." 2919 (when (bound-and-true-p helm-alive-p) 2920 (let ((sep (doom-modeline-spc))) 2921 (concat 2922 sep 2923 (when doom-modeline-icon 2924 (concat 2925 (doom-modeline-icon 'sucicon "nf-custom-emacs" nil nil 2926 :face (doom-modeline-face 2927 (and doom-modeline-major-mode-color-icon 2928 'nerd-icons-blue))) 2929 sep)) 2930 (propertize 2931 (let ((custom (cdr (assoc (buffer-name) doom-modeline--helm-buffer-ids))) 2932 (case-fold-search t) 2933 (name (replace-regexp-in-string "-" " " (buffer-name)))) 2934 (cond ((stringp custom) custom) 2935 ((functionp custom) (funcall custom)) 2936 (t 2937 (string-match "\\*helm:? \\(mode \\)?\\([^\\*]+\\)\\*" name) 2938 (concat "HELM " (capitalize (match-string 2 name)))))) 2939 'face (doom-modeline-face 'doom-modeline-buffer-file)) 2940 sep)))) 2941 2942 (doom-modeline-def-segment helm-number 2943 "Number of helm candidates." 2944 (when (bound-and-true-p helm-alive-p) 2945 (concat 2946 (propertize (format " %d/%d" 2947 (helm-candidate-number-at-point) 2948 (helm-get-candidate-number t)) 2949 'face (doom-modeline-face 'doom-modeline-buffer-path)) 2950 (propertize (format " (%d total) " (helm-get-candidate-number)) 2951 'face (doom-modeline-face 'doom-modeline-info))))) 2952 2953 (doom-modeline-def-segment helm-help 2954 "Helm keybindings help." 2955 (when (bound-and-true-p helm-alive-p) 2956 (mapcar 2957 (lambda (s) 2958 (if (string-prefix-p "\\<" s) 2959 (propertize (substitute-command-keys s) 2960 'face (doom-modeline-face 2961 'doom-modeline-buffer-file)) 2962 s)) 2963 '("\\<helm-map>\\[helm-help]" "(help) " 2964 "\\<helm-map>\\[helm-select-action]" "(actions) " 2965 "\\<helm-map>\\[helm-maybe-exit-minibuffer]/F1/F2..." "(action) ")))) 2966 2967 (doom-modeline-def-segment helm-prefix-argument 2968 "Helm prefix argument." 2969 (when (and (bound-and-true-p helm-alive-p) 2970 helm--mode-line-display-prefarg) 2971 (let ((arg (prefix-numeric-value (or prefix-arg current-prefix-arg)))) 2972 (unless (= arg 1) 2973 (propertize (format "C-u %s" arg) 2974 'face (doom-modeline-face 'doom-modeline-info)))))) 2975 2976 (defvar doom-modeline--helm-current-source nil 2977 "The currently active helm source.") 2978 (doom-modeline-def-segment helm-follow 2979 "Helm follow indicator." 2980 (and (bound-and-true-p helm-alive-p) 2981 doom-modeline--helm-current-source 2982 (eq 1 (cdr (assq 'follow doom-modeline--helm-current-source))) 2983 "HF")) 2984 2985 ;; 2986 ;; Git timemachine 2987 ;; 2988 2989 (doom-modeline-def-segment git-timemachine 2990 (concat 2991 (doom-modeline-spc) 2992 (doom-modeline--buffer-mode-icon) 2993 (doom-modeline--buffer-state-icon) 2994 (propertize 2995 "*%b*" 2996 'face (doom-modeline-face 'doom-modeline-buffer-timemachine)))) 2997 2998 ;; 2999 ;; Markdown/Org preview 3000 ;; 3001 3002 (doom-modeline-def-segment grip 3003 (when (bound-and-true-p grip-mode) 3004 (let ((sep (doom-modeline-spc))) 3005 (concat 3006 sep 3007 (let ((face (doom-modeline-face 3008 (if grip--process 3009 (pcase (process-status grip--process) 3010 ('run 'doom-modeline-info) 3011 ('exit 'doom-modeline-warning) 3012 (_ 'doom-modeline-urgent)) 3013 'doom-modeline-urgent)))) 3014 (propertize 3015 (doom-modeline-icon 'codicon "nf-cod-open_preview" "đ" "@" :face face) 3016 'help-echo (format "Preview on %s 3017 mouse-1: Preview in browser 3018 mouse-2: Stop preview 3019 mouse-3: Restart preview" 3020 (grip--preview-url)) 3021 'mouse-face 'doom-modeline-highlight 3022 'local-map (let ((map (make-sparse-keymap))) 3023 (define-key map [mode-line mouse-1] 3024 #'grip-browse-preview) 3025 (define-key map [mode-line mouse-2] 3026 #'grip-stop-preview) 3027 (define-key map [mode-line mouse-3] 3028 #'grip-restart-preview) 3029 map))) 3030 sep)))) 3031 3032 ;; 3033 ;; Follow mode 3034 ;; 3035 3036 (doom-modeline-def-segment follow 3037 (when (bound-and-true-p follow-mode) 3038 (let* ((windows (follow-all-followers)) 3039 (nwindows (length windows)) 3040 (nfollowing (- (length (memq (selected-window) windows)) 1))) 3041 (concat 3042 (doom-modeline-spc) 3043 (propertize (format "Follow %d/%d" (- nwindows nfollowing) nwindows) 3044 'face 'doom-modeline-buffer-minor-mode))))) 3045 3046 ;; 3047 ;; Display time 3048 ;; 3049 3050 (defconst doom-modeline--clock-hour-hand-ratio 0.45 3051 "Length of the hour hand as a proportion of the radius.") 3052 3053 (defconst doom-modeline--clock-minute-hand-ratio 0.7 3054 "Length of the minute hand as a proportion of the radius.") 3055 3056 (defun doom-modeline--create-clock-svg (hour minute radius color) 3057 "Construct an SVG clock showing the time HOUR:MINUTE. 3058 The clock will be of the specified RADIUS and COLOR." 3059 (let ((thickness-factor (image-compute-scaling-factor 'auto)) 3060 (hour-x (* radius (sin (* (- 6 hour (/ minute 60.0)) (/ float-pi 6))) 3061 doom-modeline--clock-hour-hand-ratio)) 3062 (hour-y (* radius (cos (* (- 6 hour (/ minute 60.0)) (/ float-pi 6))) 3063 doom-modeline--clock-hour-hand-ratio)) 3064 (minute-x (* radius (sin (* (- 30 minute) (/ float-pi 30))) 3065 doom-modeline--clock-minute-hand-ratio)) 3066 (minute-y (* radius (cos (* (- 30 minute) (/ float-pi 30))) 3067 doom-modeline--clock-minute-hand-ratio)) 3068 (svg (svg-create (* 2 radius) (* 2 radius) :stroke color))) 3069 (svg-circle svg radius radius (- radius thickness-factor) 3070 :fill "none" :stroke-width (* 2 thickness-factor)) 3071 (svg-circle svg radius radius thickness-factor 3072 :fill color :stroke "none") 3073 (svg-line svg radius radius (+ radius hour-x) (+ radius hour-y) 3074 :stroke-width (* 2 thickness-factor)) 3075 (svg-line svg radius radius (+ radius minute-x) (+ radius minute-y) 3076 :stroke-width (* 1.5 thickness-factor)) 3077 svg)) 3078 3079 (defvar doom-modeline--clock-cache nil 3080 "The last result of `doom-modeline--generate-clock'.") 3081 3082 (defun doom-modeline--generate-clock () 3083 "Return a string containing the current time as an analogue clock svg. 3084 When the svg library is not available, return nil." 3085 (cdr 3086 (or (and (equal (truncate (float-time) 3087 (* doom-modeline-time-clock-minute-resolution 60)) 3088 (car doom-modeline--clock-cache)) 3089 doom-modeline--clock-cache) 3090 (and (require 'svg nil t) 3091 (setq doom-modeline--clock-cache 3092 (cons (truncate (float-time) 3093 (* doom-modeline-time-clock-minute-resolution 60)) 3094 (propertize 3095 " " 3096 'display 3097 (svg-image 3098 (doom-modeline--create-clock-svg 3099 (string-to-number (format-time-string "%-I")) ; hour 3100 (* (truncate (string-to-number (format-time-string "%-M")) 3101 doom-modeline-time-clock-minute-resolution) 3102 doom-modeline-time-clock-minute-resolution) ; minute 3103 (if (integerp doom-modeline-time-clock-size) ; radius 3104 doom-modeline-time-clock-size 3105 (* doom-modeline-height 0.5 doom-modeline-time-clock-size)) 3106 "currentColor") 3107 :scale 1 :ascent 'center) 3108 'face 'doom-modeline-time 3109 'help-echo (lambda (_window _object _pos) 3110 (format-time-string "%c"))))))))) 3111 3112 (defun doom-modeline-time-icon () 3113 "Displays the time icon." 3114 (or (and doom-modeline-time-live-icon 3115 doom-modeline-time-analogue-clock 3116 (display-graphic-p) 3117 (doom-modeline--generate-clock)) 3118 (doom-modeline-icon 3119 'mdicon 3120 (if doom-modeline-time-live-icon 3121 (pcase (% (caddr (decode-time)) 12) 3122 (0 "nf-md-clock_time_twelve_outline") 3123 (1 "nf-md-clock_time_one_outline") 3124 (2 "nf-md-clock_time_two_outline") 3125 (3 "nf-md-clock_time_three_outline") 3126 (4 "nf-md-clock_time_four_outline") 3127 (5 "nf-md-clock_time_five_outline") 3128 (6 "nf-md-clock_time_six_outline") 3129 (7 "nf-md-clock_time_seven_outline") 3130 (8 "nf-md-clock_time_eight_outline") 3131 (9 "nf-md-clock_time_nine_outline") 3132 (10 "nf-md-clock_time_ten_outline") 3133 (11 "nf-md-clock_time_eleven_outline")) 3134 "nf-md-clock_outline") 3135 "â°" 3136 "" 3137 :face '(:inherit doom-modeline-time :weight normal)))) 3138 3139 (doom-modeline-def-segment time 3140 (when (and doom-modeline-time 3141 (bound-and-true-p display-time-mode) 3142 (doom-modeline--segment-visible 'time)) 3143 (concat 3144 (doom-modeline-spc) 3145 (when doom-modeline-time-icon 3146 (concat 3147 (doom-modeline-time-icon) 3148 (and (or doom-modeline-icon doom-modeline-unicode-fallback) 3149 (doom-modeline-vspc)))) 3150 (propertize display-time-string 3151 'face (doom-modeline-face 'doom-modeline-time))))) 3152 3153 (defun doom-modeline-override-time () 3154 "Override default `display-time' mode-line." 3155 (or global-mode-string (setq global-mode-string '(""))) 3156 (if (and doom-modeline-time 3157 (bound-and-true-p doom-modeline-mode)) 3158 (setq global-mode-string (delq 'display-time-string global-mode-string)) 3159 (setq global-mode-string (append global-mode-string '(display-time-string))))) 3160 (add-hook 'display-time-mode-hook #'doom-modeline-override-time) 3161 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-time) 3162 3163 (doom-modeline-add-variable-watcher 3164 'doom-modeline-time 3165 (lambda (_sym val op _where) 3166 (when (eq op 'set) 3167 (setq doom-modeline-time val) 3168 (doom-modeline-override-time)))) 3169 3170 ;; 3171 ;; Compilation 3172 ;; 3173 3174 (doom-modeline-def-segment compilation 3175 (and (bound-and-true-p compilation-in-progress) 3176 (propertize "[Compiling] " 3177 'face (doom-modeline-face 'doom-modeline-compilation) 3178 'help-echo "Compiling; mouse-2: Goto Buffer" 3179 'mouse-face 'doom-modeline-highlight 3180 'local-map 3181 (make-mode-line-mouse-map 3182 'mouse-2 3183 #'compilation-goto-in-progress-buffer)))) 3184 3185 ;; 3186 ;; Eldoc 3187 ;; 3188 3189 (doom-modeline-def-segment eldoc 3190 (and (bound-and-true-p eldoc-mode) 3191 '(eldoc-mode-line-string 3192 (" " eldoc-mode-line-string " ")))) 3193 3194 (defun doom-modeline-eldoc-minibuffer-message (format-string &rest args) 3195 "Display message specified by FORMAT-STRING and ARGS on the mode-line as needed. 3196 This function displays the message produced by formatting ARGS 3197 with FORMAT-STRING on the mode line when the current buffer is a minibuffer. 3198 Otherwise, it displays the message like `message' would." 3199 (if (minibufferp) 3200 (progn 3201 (add-hook 'minibuffer-exit-hook 3202 (lambda () (setq eldoc-mode-line-string nil 3203 ;; https://debbugs.gnu.org/16920 3204 eldoc-last-message nil)) 3205 nil t) 3206 (with-current-buffer 3207 (window-buffer 3208 (or (window-in-direction 'above (minibuffer-window)) 3209 (minibuffer-selected-window) 3210 (get-largest-window))) 3211 (setq eldoc-mode-line-string 3212 (when (stringp format-string) 3213 (apply #'format-message format-string args))) 3214 (force-mode-line-update))) 3215 (apply #'message format-string args))) 3216 3217 ;; 3218 ;; Kubernetes 3219 ;; 3220 3221 (doom-modeline-def-segment k8s 3222 (when (and (bound-and-true-p kele-mode) (doom-modeline--segment-visible 'k8s)) 3223 (let* ((ctx (kele-current-context-name :wait nil)) 3224 (ns (kele-current-namespace :wait nil)) 3225 (icon (doom-modeline-icon 'mdicon "nf-md-kubernetes" "K8s:" "K8s:")) 3226 (sep (doom-modeline-spc)) 3227 (help-msg (let ((msgs (list (format "Current context: %s" ctx)))) 3228 (when ns 3229 (setq msgs (append msgs (list (format "Current namespace: %s" ns))))) 3230 (string-join msgs "\n")))) 3231 (propertize (concat 3232 icon sep ctx 3233 (when (and doom-modeline-k8s-show-namespace ns) (format "(%s)" ns)) 3234 sep) 3235 'local-map (let ((map (make-sparse-keymap))) 3236 (define-key map [mode-line down-mouse-1] kele-menu-map) 3237 map) 3238 'mouse-face 'doom-modeline-highlight 3239 'help-echo help-msg)))) 3240 3241 (provide 'doom-modeline-segments) 3242 3243 ;;; doom-modeline-segments.el ends here