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