doom-modeline-segments.el (136059B)
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 (or doom-modeline-display-misc-in-all-mode-lines 1612 (doom-modeline--segment-visible 'misc-info)) 1613 (doom-modeline-display-text 1614 (string-replace "%" "%%" (format-mode-line mode-line-misc-info))))) 1615 1616 1617 ;; 1618 ;; Position 1619 ;; 1620 1621 (doom-modeline-def-segment buffer-position 1622 "The buffer position information." 1623 (let ((visible (doom-modeline--segment-visible 'buffer-position)) 1624 (sep (doom-modeline-spc)) 1625 (wsep (doom-modeline-wspc)) 1626 (face (doom-modeline-face)) 1627 (help-echo "Buffer percentage\n\ 1628 mouse-1: Display Line and Column Mode Menu") 1629 (mouse-face 'doom-modeline-highlight) 1630 (local-map mode-line-column-line-number-mode-map)) 1631 `(,wsep 1632 1633 ;; Line and column 1634 (:propertize 1635 ((line-number-mode 1636 (column-number-mode 1637 (doom-modeline-column-zero-based 1638 doom-modeline-position-column-line-format 1639 ,(string-replace 1640 "%c" "%C" (car doom-modeline-position-column-line-format))) 1641 doom-modeline-position-line-format) 1642 (column-number-mode 1643 (doom-modeline-column-zero-based 1644 doom-modeline-position-column-format 1645 ,(string-replace 1646 "%c" "%C" (car doom-modeline-position-column-format))))) 1647 (doom-modeline-total-line-number 1648 ,(and doom-modeline-total-line-number 1649 (format "/%d" (line-number-at-pos (point-max)))))) 1650 face ,face 1651 help-echo ,help-echo 1652 mouse-face ,mouse-face 1653 local-map ,local-map) 1654 1655 ((or line-number-mode column-number-mode) 1656 ,sep) 1657 1658 ;; Position 1659 (,visible 1660 ,(cond 1661 ((bound-and-true-p nyan-mode) 1662 (concat sep (nyan-create) sep)) 1663 ((bound-and-true-p poke-line-mode) 1664 (concat sep (poke-line-create) sep)) 1665 ((bound-and-true-p mlscroll-mode) 1666 (concat sep 1667 (let ((mlscroll-right-align nil)) 1668 (format-mode-line (mlscroll-mode-line))) 1669 sep)) 1670 ((bound-and-true-p sml-modeline-mode) 1671 (concat sep (sml-modeline-create) sep)) 1672 (t ""))) 1673 1674 ;; Percent position 1675 (doom-modeline-percent-position 1676 ((:propertize ("" doom-modeline-percent-position) 1677 face ,face 1678 help-echo ,help-echo 1679 mouse-face ,mouse-face 1680 local-map ,local-map) 1681 ,sep))))) 1682 1683 ;; 1684 ;; Party parrot 1685 ;; 1686 (doom-modeline-def-segment parrot 1687 "The party parrot animated icon. Requires `parrot-mode' to be enabled." 1688 (when (and (doom-modeline--segment-visible 'parrot) 1689 (bound-and-true-p parrot-mode)) 1690 (concat (doom-modeline-wspc) 1691 (parrot-create) 1692 (doom-modeline-spc)))) 1693 1694 ;; 1695 ;; Modals (evil, overwrite, god, ryo and xah-fly-keys, etc.) 1696 ;; 1697 1698 (defun doom-modeline--modal-icon (text face help-echo &optional icon unicode) 1699 "Display the model icon with FACE and HELP-ECHO. 1700 TEXT is alternative if icon is not available." 1701 (propertize (doom-modeline-icon 1702 'mdicon 1703 (and doom-modeline-modal-icon 1704 (or (and doom-modeline-modal-modern-icon icon) 1705 "nf-md-record")) 1706 (or (and doom-modeline-modal-modern-icon unicode) "â") 1707 text 1708 :face (doom-modeline-face face)) 1709 'help-echo help-echo)) 1710 1711 (defsubst doom-modeline--evil () 1712 "The current evil state. Requires `evil-mode' to be enabled." 1713 (when (bound-and-true-p evil-local-mode) 1714 (doom-modeline--modal-icon 1715 (let ((tag (evil-state-property evil-state :tag t))) 1716 (if (stringp tag) tag (funcall tag))) 1717 (cond 1718 ((evil-normal-state-p) 'doom-modeline-evil-normal-state) 1719 ((evil-emacs-state-p) 'doom-modeline-evil-emacs-state) 1720 ((evil-insert-state-p) 'doom-modeline-evil-insert-state) 1721 ((evil-motion-state-p) 'doom-modeline-evil-motion-state) 1722 ((evil-visual-state-p) 'doom-modeline-evil-visual-state) 1723 ((evil-operator-state-p) 'doom-modeline-evil-operator-state) 1724 ((evil-replace-state-p) 'doom-modeline-evil-replace-state) 1725 (t 'doom-modeline-evil-user-state)) 1726 (evil-state-property evil-state :name t) 1727 (cond 1728 ((evil-normal-state-p) "nf-md-alpha_n_circle") 1729 ((evil-emacs-state-p) "nf-md-alpha_e_circle") 1730 ((evil-insert-state-p) "nf-md-alpha_i_circle") 1731 ((evil-motion-state-p) "nf-md-alpha_m_circle") 1732 ((evil-visual-state-p) "nf-md-alpha_v_circle") 1733 ((evil-operator-state-p) "nf-md-alpha_o_circle") 1734 ((evil-replace-state-p) "nf-md-alpha_r_circle") 1735 (t "nf-md-alpha_u_circle")) 1736 (cond 1737 ((evil-normal-state-p) "đ ") 1738 ((evil-emacs-state-p) "đ ") 1739 ((evil-insert-state-p) "đ ") 1740 ((evil-motion-state-p) "đ ") 1741 ((evil-visual-state-p) "đ Ĩ") 1742 ((evil-operator-state-p) "đ ") 1743 ((evil-replace-state-p) "đ Ą") 1744 (t "đ ¤"))))) 1745 1746 (defsubst doom-modeline--overwrite () 1747 "The current overwrite state which is enabled by command `overwrite-mode'." 1748 (when (and (bound-and-true-p overwrite-mode) 1749 (not (bound-and-true-p evil-local-mode))) 1750 (doom-modeline--modal-icon 1751 "<W>" 'doom-modeline-overwrite "Overwrite mode" 1752 "nf-md-marker" "đ Ļ"))) 1753 1754 (defsubst doom-modeline--god () 1755 "The current god state which is enabled by the command `god-mode'." 1756 (when (bound-and-true-p god-local-mode) 1757 (doom-modeline--modal-icon 1758 "<G>" 'doom-modeline-god "God mode" 1759 "nf-md-account_circle" "đ "))) 1760 1761 (defsubst doom-modeline--ryo () 1762 "The current ryo-modal state which is enabled by the command `ryo-modal-mode'." 1763 (when (bound-and-true-p ryo-modal-mode) 1764 (doom-modeline--modal-icon 1765 "<R>" 'doom-modeline-ryo "Ryo modal" 1766 "nf-md-star_circle" "âĒ"))) 1767 1768 (defsubst doom-modeline--xah-fly-keys () 1769 "The current `xah-fly-keys' state." 1770 (when (bound-and-true-p xah-fly-keys) 1771 (if xah-fly-insert-state-p 1772 (doom-modeline--modal-icon 1773 "<I>" 'doom-modeline-fly-insert-state "Xah-fly insert mode" 1774 "nf-md-airplane_edit" "đ§") 1775 (doom-modeline--modal-icon 1776 "<C>" 'doom-modeline-fly-normal-state "Xah-fly command mode" 1777 "nf-md-airplane_cog" "đ§")))) 1778 1779 (defsubst doom-modeline--boon () 1780 "The current Boon state. Requires `boon-mode' to be enabled." 1781 (when (bound-and-true-p boon-local-mode) 1782 (doom-modeline--modal-icon 1783 (boon-state-string) 1784 (cond 1785 (boon-command-state 'doom-modeline-boon-command-state) 1786 (boon-insert-state 'doom-modeline-boon-insert-state) 1787 (boon-special-state 'doom-modeline-boon-special-state) 1788 (boon-off-state 'doom-modeline-boon-off-state) 1789 (t 'doom-modeline-boon-off-state)) 1790 (boon-modeline-string) 1791 "nf-md-coffee" "đĩ"))) 1792 1793 (defsubst doom-modeline--meow () 1794 "The current Meow state. Requires `meow-mode' to be enabled." 1795 (when (bound-and-true-p meow-mode) 1796 (doom-modeline--modal-icon 1797 (substring-no-properties meow--indicator) 1798 (cond 1799 ((meow-normal-mode-p) 'doom-modeline-meow-normal-state) 1800 ((meow-insert-mode-p) 'doom-modeline-meow-insert-state) 1801 ((meow-beacon-mode-p) 'doom-modeline-meow-beacon-state) 1802 ((meow-motion-mode-p) 'doom-modeline-meow-motion-state) 1803 ((meow-keypad-mode-p) 'doom-modeline-meow-keypad-state) 1804 (t 'doom-modeline-meow-normal-state)) 1805 (symbol-name (meow--current-state)) 1806 (cond 1807 ((meow-normal-mode-p) "nf-md-alpha_n_circle") 1808 ((meow-insert-mode-p) "nf-md-alpha_i_circle") 1809 ((meow-beacon-mode-p) "nf-md-alpha_b_circle") 1810 ((meow-motion-mode-p) "nf-md-alpha_m_circle") 1811 ((meow-keypad-mode-p) "nf-md-alpha_k_circle") 1812 (t "nf-md-alpha_n_circle")) 1813 (cond 1814 ((meow-normal-mode-p) "đ ") 1815 ((meow-insert-mode-p) "đ ") 1816 ((meow-beacon-mode-p) "đ ") 1817 ((meow-motion-mode-p) "đ ") 1818 ((meow-keypad-mode-p) "đ ") 1819 (t "đ "))))) 1820 1821 (doom-modeline-def-segment modals 1822 "Displays modal editing states. 1823 1824 Including `evil', `overwrite', `god', `ryo' and `xha-fly-kyes', etc." 1825 (when doom-modeline-modal 1826 (let* ((evil (doom-modeline--evil)) 1827 (ow (doom-modeline--overwrite)) 1828 (god (doom-modeline--god)) 1829 (ryo (doom-modeline--ryo)) 1830 (xf (doom-modeline--xah-fly-keys)) 1831 (boon (doom-modeline--boon)) 1832 (vsep (doom-modeline-vspc)) 1833 (meow (doom-modeline--meow)) 1834 (sep (and (or evil ow god ryo xf boon) (doom-modeline-spc)))) 1835 (concat sep 1836 (and evil (concat evil (and (or ow god ryo xf boon meow) vsep))) 1837 (and ow (concat ow (and (or god ryo xf boon meow) vsep))) 1838 (and god (concat god (and (or ryo xf boon meow) vsep))) 1839 (and ryo (concat ryo (and (or xf boon meow) vsep))) 1840 (and xf (concat xf (and (or boon meow) vsep))) 1841 (and boon (concat boon (and meow vsep))) 1842 meow 1843 sep)))) 1844 1845 ;; 1846 ;; Objed state 1847 ;; 1848 1849 (defvar doom-modeline--objed-active nil) 1850 1851 (defun doom-modeline-update-objed (_ &optional reset) 1852 "Update `objed' status, inactive when RESET is true." 1853 (setq doom-modeline--objed-active (not reset))) 1854 1855 (setq objed-modeline-setup-func #'doom-modeline-update-objed) 1856 1857 (doom-modeline-def-segment objed-state () 1858 "The current objed state." 1859 (when (and doom-modeline--objed-active 1860 (doom-modeline--active)) 1861 (propertize (format " %s(%s) " 1862 (symbol-name objed--object) 1863 (char-to-string (aref (symbol-name objed--obj-state) 0))) 1864 'face 'doom-modeline-evil-emacs-state 1865 'help-echo (format "Objed object: %s (%s)" 1866 (symbol-name objed--object) 1867 (symbol-name objed--obj-state))))) 1868 1869 1870 ;; 1871 ;; Input method 1872 ;; 1873 1874 (doom-modeline-def-segment input-method 1875 "The current input method." 1876 (when-let* ((im (cond 1877 (current-input-method 1878 current-input-method-title) 1879 ((and (bound-and-true-p evil-local-mode) 1880 (bound-and-true-p evil-input-method)) 1881 (nth 3 (assoc default-input-method input-method-alist))) 1882 (t nil))) 1883 (sep (doom-modeline-spc))) 1884 (concat 1885 sep 1886 (propertize im 1887 'face (doom-modeline-face 1888 (if (and (bound-and-true-p rime-mode) 1889 (equal current-input-method "rime")) 1890 (if (and (rime--should-enable-p) 1891 (not (rime--should-inline-ascii-p))) 1892 'doom-modeline-input-method 1893 'doom-modeline-input-method-alt) 1894 'doom-modeline-input-method)) 1895 'help-echo (concat 1896 "Current input method: " 1897 current-input-method 1898 "\n\ 1899 mouse-2: Disable input method\n\ 1900 mouse-3: Describe current input method") 1901 'mouse-face 'doom-modeline-highlight 1902 'local-map mode-line-input-method-map) 1903 sep))) 1904 1905 1906 ;; 1907 ;; Info 1908 ;; 1909 1910 (doom-modeline-def-segment info-nodes 1911 "The topic and nodes in the Info buffer." 1912 (concat 1913 " (" 1914 ;; topic 1915 (propertize (if (stringp Info-current-file) 1916 (replace-regexp-in-string 1917 "%" "%%" 1918 (file-name-sans-extension 1919 (file-name-nondirectory Info-current-file))) 1920 (format "*%S*" Info-current-file)) 1921 'face (doom-modeline-face 'doom-modeline-info)) 1922 ") " 1923 ;; node 1924 (when Info-current-node 1925 (propertize (replace-regexp-in-string 1926 "%" "%%" Info-current-node) 1927 'face (doom-modeline-face 'doom-modeline-buffer-path) 1928 'help-echo 1929 "mouse-1: scroll forward, mouse-3: scroll back" 1930 'mouse-face 'doom-modeline-highlight 1931 'local-map Info-mode-line-node-keymap)))) 1932 1933 1934 ;; 1935 ;; REPL 1936 ;; 1937 1938 (defun doom-modeline-repl-icon (text face) 1939 "Display REPL icon (or TEXT in terminal) with FACE." 1940 (doom-modeline-icon 'faicon "nf-fa-terminal" "$" text :face face)) 1941 1942 (defvar doom-modeline--cider nil) 1943 1944 (defun doom-modeline-update-cider () 1945 "Update cider repl state." 1946 (setq doom-modeline--cider 1947 (let* ((connected (cider-connected-p)) 1948 (face (if connected 'doom-modeline-repl-success 'doom-modeline-repl-warning)) 1949 (repl-buffer (cider-current-repl nil nil)) 1950 (cider-info (when repl-buffer 1951 (cider--connection-info repl-buffer t))) 1952 (icon (doom-modeline-repl-icon "REPL" face))) 1953 (propertize icon 1954 'help-echo 1955 (if connected 1956 (format "CIDER Connected %s\nmouse-2: CIDER quit" cider-info) 1957 "CIDER Disconnected\nmouse-1: CIDER jack-in") 1958 'mouse-face 'doom-modeline-highlight 1959 'local-map (let ((map (make-sparse-keymap))) 1960 (if connected 1961 (define-key map [mode-line mouse-2] 1962 #'cider-quit) 1963 (define-key map [mode-line mouse-1] 1964 #'cider-jack-in)) 1965 map))))) 1966 1967 (add-hook 'cider-connected-hook #'doom-modeline-update-cider) 1968 (add-hook 'cider-disconnected-hook #'doom-modeline-update-cider) 1969 (add-hook 'cider-mode-hook #'doom-modeline-update-cider) 1970 1971 (doom-modeline-def-segment repl 1972 "The REPL state." 1973 (when doom-modeline-repl 1974 (when-let* ((icon (when (bound-and-true-p cider-mode) 1975 doom-modeline--cider)) 1976 (sep (doom-modeline-spc))) 1977 (concat 1978 sep 1979 (doom-modeline-display-icon icon) 1980 sep)))) 1981 1982 1983 ;; 1984 ;; LSP 1985 ;; 1986 1987 (defun doom-modeline-lsp-icon (text face) 1988 "Display LSP icon (or TEXT in terminal) with FACE." 1989 (if doom-modeline-lsp-icon 1990 (doom-modeline-icon 'octicon "nf-oct-rocket" "đ" text :face face) 1991 (propertize text 'face face))) 1992 1993 (defvar-local doom-modeline--lsp nil) 1994 (defun doom-modeline-update-lsp (&rest _) 1995 "Update `lsp-mode' state." 1996 (setq doom-modeline--lsp 1997 (let* ((workspaces (lsp-workspaces)) 1998 (face (if workspaces 'doom-modeline-lsp-success 'doom-modeline-lsp-warning)) 1999 (icon (doom-modeline-lsp-icon "LSP" face))) 2000 (propertize icon 2001 'help-echo 2002 (if workspaces 2003 (concat "LSP connected " 2004 (string-join 2005 (mapcar (lambda (w) 2006 (format "[%s]\n" (lsp--workspace-print w))) 2007 workspaces)) 2008 "C-mouse-1: Switch to another workspace folder 2009 mouse-1: Describe current session 2010 mouse-2: Quit server 2011 mouse-3: Reconnect to server") 2012 "LSP Disconnected 2013 mouse-1: Reload to start server") 2014 'mouse-face 'doom-modeline-highlight 2015 'local-map (let ((map (make-sparse-keymap))) 2016 (if workspaces 2017 (progn 2018 (define-key map [mode-line C-mouse-1] 2019 #'lsp-workspace-folders-open) 2020 (define-key map [mode-line mouse-1] 2021 #'lsp-describe-session) 2022 (define-key map [mode-line mouse-2] 2023 #'lsp-workspace-shutdown) 2024 (define-key map [mode-line mouse-3] 2025 #'lsp-workspace-restart)) 2026 (progn 2027 (define-key map [mode-line mouse-1] 2028 (lambda () 2029 (interactive) 2030 (ignore-errors (revert-buffer t t)))))) 2031 map))))) 2032 (add-hook 'lsp-before-initialize-hook #'doom-modeline-update-lsp) 2033 (add-hook 'lsp-after-initialize-hook #'doom-modeline-update-lsp) 2034 (add-hook 'lsp-after-uninitialized-functions #'doom-modeline-update-lsp) 2035 (add-hook 'lsp-before-open-hook #'doom-modeline-update-lsp) 2036 (add-hook 'lsp-after-open-hook #'doom-modeline-update-lsp) 2037 2038 (defun doom-modeline--eglot-pending-count (server) 2039 "Get count of pending eglot requests to SERVER." 2040 (if (fboundp 'jsonrpc-continuation-count) 2041 (jsonrpc-continuation-count server) 2042 (hash-table-count (jsonrpc--request-continuations server)))) 2043 2044 (defvar-local doom-modeline--eglot nil) 2045 (defun doom-modeline-update-eglot () 2046 "Update eglot state." 2047 (setq doom-modeline--eglot 2048 (let* ((server (and (eglot-managed-p) (eglot-current-server))) 2049 (nick (and server (eglot-project-nickname server))) 2050 (pending (and server (doom-modeline--eglot-pending-count server))) 2051 (last-error (and server (jsonrpc-last-error server))) 2052 (face (cond (last-error 'doom-modeline-lsp-error) 2053 ((and pending (cl-plusp pending)) 'doom-modeline-lsp-warning) 2054 (nick 'doom-modeline-lsp-success) 2055 (t 'doom-modeline-lsp-warning))) 2056 (server-info (and server (eglot--server-info server))) 2057 (server-name (or (plist-get server-info :name) 2058 (and server (jsonrpc-name server)) "")) 2059 (major-modes (or (and server (eglot--major-modes server)) "")) 2060 (icon (doom-modeline-lsp-icon eglot-menu-string face))) 2061 (propertize icon 2062 'help-echo (format "Eglot connected [%s]\n%s %s 2063 mouse-1: Display minor mode menu 2064 mouse-3: LSP server control menu" 2065 nick server-name major-modes) 2066 'mouse-face 'doom-modeline-highlight 2067 'local-map (let ((map (make-sparse-keymap))) 2068 (define-key map [mode-line mouse-1] eglot-menu) 2069 (define-key map [mode-line mouse-3] eglot-server-menu) 2070 map))))) 2071 (add-hook 'eglot-managed-mode-hook #'doom-modeline-update-eglot) 2072 2073 (defvar-local doom-modeline--tags nil) 2074 (defun doom-modeline-update-tags () 2075 "Update tags state." 2076 (setq doom-modeline--tags 2077 (propertize 2078 (doom-modeline-lsp-icon "Tags" 'doom-modeline-lsp-success) 2079 'help-echo "Tags: Citre mode 2080 mouse-1: Toggle citre mode" 2081 'mouse-face 'doom-modeline-highlight 2082 'local-map (make-mode-line-mouse-map 'mouse-1 #'citre-mode)))) 2083 (add-hook 'citre-mode-hook #'doom-modeline-update-tags) 2084 2085 (defun doom-modeline-update-lsp-icon () 2086 "Update lsp icon." 2087 (cond ((bound-and-true-p lsp-mode) 2088 (doom-modeline-update-lsp)) 2089 ((bound-and-true-p eglot--managed-mode) 2090 (doom-modeline-update-eglot)) 2091 ((bound-and-true-p citre-mode) 2092 (doom-modeline-update-tags)))) 2093 2094 (doom-modeline-add-variable-watcher 2095 'doom-modeline-lsp-icon 2096 (lambda (_sym val op _where) 2097 (when (eq op 'set) 2098 (setq doom-modeline-lsp-icon val) 2099 (dolist (buf (buffer-list)) 2100 (with-current-buffer buf 2101 (doom-modeline-update-lsp-icon)))))) 2102 2103 (doom-modeline-add-variable-watcher 2104 'doom-modeline-icon 2105 (lambda (_sym val op _where) 2106 (when (eq op 'set) 2107 (setq doom-modeline-icon val) 2108 (dolist (buf (buffer-list)) 2109 (with-current-buffer buf 2110 (doom-modeline-update-lsp-icon)))))) 2111 2112 (doom-modeline-add-variable-watcher 2113 'doom-modeline-unicode-fallback 2114 (lambda (_sym val op _where) 2115 (when (eq op 'set) 2116 (setq doom-modeline-unicode-fallback val) 2117 (dolist (buf (buffer-list)) 2118 (with-current-buffer buf 2119 (doom-modeline-update-lsp-icon)))))) 2120 2121 (doom-modeline-def-segment lsp 2122 "The LSP server state." 2123 (when doom-modeline-lsp 2124 (when-let* ((icon (cond ((bound-and-true-p lsp-mode) 2125 doom-modeline--lsp) 2126 ((bound-and-true-p eglot--managed-mode) 2127 doom-modeline--eglot) 2128 ((bound-and-true-p citre-mode) 2129 doom-modeline--tags))) 2130 (sep (doom-modeline-spc))) 2131 (concat 2132 sep 2133 (doom-modeline-display-icon icon) 2134 sep)))) 2135 2136 (defun doom-modeline-override-eglot () 2137 "Override `eglot' mode-line." 2138 (if (and doom-modeline-lsp 2139 (bound-and-true-p doom-modeline-mode)) 2140 (setq mode-line-misc-info 2141 (delq (assq 'eglot--managed-mode mode-line-misc-info) mode-line-misc-info)) 2142 (add-to-list 'mode-line-misc-info 2143 `(eglot--managed-mode (" [" eglot--mode-line-format "] "))))) 2144 (add-hook 'eglot-managed-mode-hook #'doom-modeline-override-eglot) 2145 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-eglot) 2146 2147 (doom-modeline-add-variable-watcher 2148 'doom-modeline-battery 2149 (lambda (_sym val op _where) 2150 (when (eq op 'set) 2151 (setq doom-modeline-lsp val) 2152 (doom-modeline-override-eglot)))) 2153 2154 2155 ;; 2156 ;; GitHub 2157 ;; 2158 2159 (defvar doom-modeline--github-notification-number 0) 2160 (defvar doom-modeline-before-github-fetch-notification-hook nil 2161 "Hooks before fetching GitHub notifications. 2162 Example: 2163 (add-hook \\='doom-modeline-before-github-fetch-notification-hook 2164 #\\='auth-source-pass-enable)") 2165 2166 (defvar doom-modeline-after-github-fetch-notification-hook nil 2167 "Hooks after fetching GitHub notifications.") 2168 2169 (defun doom-modeline--github-fetch-notifications () 2170 "Fetch GitHub notifications." 2171 (when (and doom-modeline-github 2172 (require 'async nil t)) 2173 (async-start 2174 `(lambda () 2175 ,(async-inject-variables 2176 "\\`\\(load-path\\|auth-sources\\|doom-modeline-before-github-fetch-notification-hook\\)\\'") 2177 (run-hooks 'doom-modeline-before-github-fetch-notification-hook) 2178 (when (require 'ghub nil t) 2179 (with-timeout (10) 2180 (ignore-errors 2181 (when-let* ((username (ghub--username ghub-default-host)) 2182 (token (or (ghub--token ghub-default-host username 'forge t) 2183 (ghub--token ghub-default-host username 'ghub t)))) 2184 (ghub-get "/notifications" 2185 '((notifications . t)) 2186 :host ghub-default-host 2187 :username username 2188 :auth token 2189 :unpaginate t 2190 :noerror t)))))) 2191 (lambda (result) 2192 (message "") ; suppress message 2193 (setq doom-modeline--github-notification-number (length result)) 2194 (run-hooks 'doom-modeline-after-github-fetch-notification-hook))))) 2195 2196 (defvar doom-modeline--github-timer nil) 2197 (defun doom-modeline-github-timer () 2198 "Start/Stop the timer for GitHub fetching." 2199 (if (timerp doom-modeline--github-timer) 2200 (cancel-timer doom-modeline--github-timer)) 2201 (setq doom-modeline--github-timer 2202 (and doom-modeline-github 2203 (run-with-idle-timer 30 2204 doom-modeline-github-interval 2205 #'doom-modeline--github-fetch-notifications)))) 2206 2207 (doom-modeline-add-variable-watcher 2208 'doom-modeline-github 2209 (lambda (_sym val op _where) 2210 (when (eq op 'set) 2211 (setq doom-modeline-github val) 2212 (doom-modeline-github-timer)))) 2213 2214 (doom-modeline-github-timer) 2215 2216 (doom-modeline-def-segment github 2217 "The GitHub notifications." 2218 (when (and doom-modeline-github 2219 (doom-modeline--segment-visible 'github) 2220 (numberp doom-modeline--github-notification-number)) 2221 (let ((sep (doom-modeline-spc))) 2222 (concat 2223 sep 2224 (propertize 2225 (concat 2226 (doom-modeline-icon 'octicon "nf-oct-mark_github" "đ" "&" 2227 :face 'doom-modeline-notification) 2228 (and (> doom-modeline--github-notification-number 0) (doom-modeline-vspc)) 2229 (propertize 2230 (cond 2231 ((<= doom-modeline--github-notification-number 0) "") 2232 ((> doom-modeline--github-notification-number 99) "99+") 2233 (t (number-to-string doom-modeline--github-notification-number))) 2234 'face '(:inherit 2235 (doom-modeline-unread-number doom-modeline-notification)))) 2236 'help-echo "Github Notifications 2237 mouse-1: Show notifications 2238 mouse-3: Fetch notifications" 2239 'mouse-face 'doom-modeline-highlight 2240 'local-map (let ((map (make-sparse-keymap))) 2241 (define-key map [mode-line mouse-1] 2242 (lambda () 2243 "Open GitHub notifications page." 2244 (interactive) 2245 (run-with-idle-timer 300 nil #'doom-modeline--github-fetch-notifications) 2246 (browse-url "https://github.com/notifications"))) 2247 (define-key map [mode-line mouse-3] 2248 (lambda () 2249 "Fetching GitHub notifications." 2250 (interactive) 2251 (message "Fetching GitHub notifications...") 2252 (doom-modeline--github-fetch-notifications))) 2253 map)) 2254 sep)))) 2255 2256 2257 ;; 2258 ;; Debug states 2259 ;; 2260 2261 ;; Highlight the doom-modeline while debugging. 2262 (defvar-local doom-modeline--debug-cookie nil) 2263 (defun doom-modeline--debug-visual (&rest _) 2264 "Update the face of mode-line for debugging." 2265 (mapc (lambda (buffer) 2266 (with-current-buffer buffer 2267 (setq doom-modeline--debug-cookie 2268 (face-remap-add-relative 'doom-modeline 'doom-modeline-debug-visual)) 2269 (force-mode-line-update))) 2270 (buffer-list))) 2271 2272 (defun doom-modeline--normal-visual (&rest _) 2273 "Restore the face of mode-line." 2274 (mapc (lambda (buffer) 2275 (with-current-buffer buffer 2276 (when doom-modeline--debug-cookie 2277 (face-remap-remove-relative doom-modeline--debug-cookie) 2278 (force-mode-line-update)))) 2279 (buffer-list))) 2280 2281 (add-hook 'dap-session-created-hook #'doom-modeline--debug-visual) 2282 (add-hook 'dap-terminated-hook #'doom-modeline--normal-visual) 2283 2284 (defun doom-modeline-debug-icon (face) 2285 "Display debug icon with FACE and ARGS." 2286 (doom-modeline-icon 'codicon "nf-cod-debug" "đ" "!" :face face)) 2287 2288 (defun doom-modeline--debug-dap () 2289 "The current `dap-mode' state." 2290 (when (and (bound-and-true-p dap-mode) 2291 (bound-and-true-p lsp-mode)) 2292 (when-let* ((session (dap--cur-session))) 2293 (when (dap--session-running session) 2294 (propertize (doom-modeline-debug-icon 'doom-modeline-info) 2295 'help-echo (format "DAP (%s - %s) 2296 mouse-1: Display debug hydra 2297 mouse-2: Display recent configurations 2298 mouse-3: Disconnect session" 2299 (dap--debug-session-name session) 2300 (dap--debug-session-state session)) 2301 'mouse-face 'doom-modeline-highlight 2302 'local-map (let ((map (make-sparse-keymap))) 2303 (define-key map [mode-line mouse-1] 2304 #'dap-hydra) 2305 (define-key map [mode-line mouse-2] 2306 #'dap-debug-recent) 2307 (define-key map [mode-line mouse-3] 2308 #'dap-disconnect) 2309 map)))))) 2310 2311 (defvar-local doom-modeline--debug-dap nil) 2312 (defun doom-modeline-update-debug-dap (&rest _) 2313 "Update dap debug state." 2314 (setq doom-modeline--debug-dap (doom-modeline--debug-dap))) 2315 2316 (add-hook 'dap-session-created-hook #'doom-modeline-update-debug-dap) 2317 (add-hook 'dap-session-changed-hook #'doom-modeline-update-debug-dap) 2318 (add-hook 'dap-terminated-hook #'doom-modeline-update-debug-dap) 2319 2320 (defsubst doom-modeline--debug-edebug () 2321 "The current `edebug' state." 2322 (when (bound-and-true-p edebug-mode) 2323 (propertize (doom-modeline-debug-icon 'doom-modeline-info) 2324 'help-echo (format "EDebug (%s) 2325 mouse-1: Show help 2326 mouse-2: Next 2327 mouse-3: Stop debugging" 2328 edebug-execution-mode) 2329 'mouse-face 'doom-modeline-highlight 2330 'local-map (let ((map (make-sparse-keymap))) 2331 (define-key map [mode-line mouse-1] 2332 #'edebug-help) 2333 (define-key map [mode-line mouse-2] 2334 #'edebug-next-mode) 2335 (define-key map [mode-line mouse-3] 2336 #'edebug-stop) 2337 map)))) 2338 2339 (defsubst doom-modeline--debug-on-error () 2340 "The current `debug-on-error' state." 2341 (when debug-on-error 2342 (propertize (doom-modeline-debug-icon 'doom-modeline-urgent) 2343 'help-echo "Debug on Error 2344 mouse-1: Toggle Debug on Error" 2345 'mouse-face 'doom-modeline-highlight 2346 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-error)))) 2347 2348 (defsubst doom-modeline--debug-on-quit () 2349 "The current `debug-on-quit' state." 2350 (when debug-on-quit 2351 (propertize (doom-modeline-debug-icon 'doom-modeline-warning) 2352 'help-echo "Debug on Quit 2353 mouse-1: Toggle Debug on Quit" 2354 'mouse-face 'doom-modeline-highlight 2355 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-quit)))) 2356 2357 (doom-modeline-def-segment debug 2358 "The current debug state." 2359 (when (doom-modeline--segment-visible 'debug) 2360 (let* ((dap doom-modeline--debug-dap) 2361 (edebug (doom-modeline--debug-edebug)) 2362 (on-error (doom-modeline--debug-on-error)) 2363 (on-quit (doom-modeline--debug-on-quit)) 2364 (vsep (doom-modeline-vspc)) 2365 (sep (and (or dap edebug on-error on-quit) (doom-modeline-spc)))) 2366 (concat sep 2367 (and dap (concat dap (and (or edebug on-error on-quit) vsep))) 2368 (and edebug (concat edebug (and (or on-error on-quit) vsep))) 2369 (and on-error (concat on-error (and on-quit vsep))) 2370 on-quit 2371 sep)))) 2372 2373 2374 ;; 2375 ;; PDF pages 2376 ;; 2377 2378 (defvar-local doom-modeline--pdf-pages nil) 2379 (defun doom-modeline-update-pdf-pages () 2380 "Update PDF pages." 2381 (setq doom-modeline--pdf-pages 2382 (format " P%d/%d " 2383 (or (eval `(pdf-view-current-page)) 0) 2384 (pdf-cache-number-of-pages)))) 2385 (add-hook 'pdf-view-change-page-hook #'doom-modeline-update-pdf-pages) 2386 2387 (doom-modeline-def-segment pdf-pages 2388 "Display PDF pages." 2389 doom-modeline--pdf-pages) 2390 2391 2392 ;; 2393 ;; `mu4e' notifications 2394 ;; 2395 2396 (doom-modeline-def-segment mu4e 2397 "Show notifications of any unread emails in `mu4e'." 2398 (when (and doom-modeline-mu4e 2399 (doom-modeline--segment-visible 'mu4e)) 2400 (let ((sep (doom-modeline-spc)) 2401 (vsep (doom-modeline-vspc)) 2402 (icon (doom-modeline-icon 'mdicon "nf-md-email" "đ§" "#" 2403 :face 'doom-modeline-notification))) 2404 (cond ((and (bound-and-true-p mu4e-alert-mode-line) 2405 (numberp mu4e-alert-mode-line) 2406 ;; don't display if the unread mails count is zero 2407 (> mu4e-alert-mode-line 0)) 2408 (concat 2409 sep 2410 (propertize 2411 (concat 2412 icon 2413 vsep 2414 (propertize 2415 (if (> mu4e-alert-mode-line doom-modeline-number-limit) 2416 (format "%d+" doom-modeline-number-limit) 2417 (number-to-string mu4e-alert-mode-line)) 2418 'face '(:inherit 2419 (doom-modeline-unread-number doom-modeline-notification)))) 2420 'mouse-face 'doom-modeline-highlight 2421 'keymap '(mode-line keymap 2422 (mouse-1 . mu4e-alert-view-unread-mails) 2423 (mouse-2 . mu4e-alert-view-unread-mails) 2424 (mouse-3 . mu4e-alert-view-unread-mails)) 2425 'help-echo (concat (if (= mu4e-alert-mode-line 1) 2426 "You have an unread email" 2427 (format "You have %s unread emails" mu4e-alert-mode-line)) 2428 "\nClick here to view " 2429 (if (= mu4e-alert-mode-line 1) "it" "them"))) 2430 sep)) 2431 ((bound-and-true-p mu4e-modeline-mode) 2432 (concat sep icon vsep 2433 (propertize (mu4e--modeline-string) 2434 'face 'doom-modeline-notification) 2435 sep)))))) 2436 2437 (defun doom-modeline-override-mu4e-alert (&rest _) 2438 "Delete `mu4e-alert-mode-line' from global modeline string." 2439 (when (and (featurep 'mu4e-alert) 2440 (bound-and-true-p mu4e-alert-mode-line)) 2441 (if (and doom-modeline-mu4e 2442 (bound-and-true-p doom-modeline-mode)) 2443 ;; Delete original modeline 2444 (progn 2445 (setq global-mode-string 2446 (delete '(:eval mu4e-alert-mode-line) global-mode-string)) 2447 (setq mu4e-alert-modeline-formatter #'identity)) 2448 ;; Recover default settings 2449 (setq mu4e-alert-modeline-formatter #'mu4e-alert-default-mode-line-formatter)))) 2450 (advice-add #'mu4e-alert-enable-mode-line-display 2451 :after #'doom-modeline-override-mu4e-alert) 2452 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-alert) 2453 2454 (defun doom-modeline-override-mu4e-modeline (&rest _) 2455 "Delete `mu4e-alert-mode-line' from global modeline string." 2456 (when (bound-and-true-p mu4e-modeline-mode) 2457 (if (and doom-modeline-mu4e 2458 (bound-and-true-p doom-modeline-mode)) 2459 ;; Delete original modeline 2460 (setq global-mode-string 2461 (delete mu4e--modeline-item global-mode-string)) 2462 ;; Recover default settings 2463 (add-to-list 'global-mode-string mu4e--modeline-item)))) 2464 (add-hook 'mu4e-modeline-mode-hook #'doom-modeline-override-mu4e-modeline) 2465 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-modeline) 2466 2467 (doom-modeline-add-variable-watcher 2468 'doom-modeline-mu4e 2469 (lambda (_sym val op _where) 2470 (when (eq op 'set) 2471 (setq doom-modeline-mu4e val) 2472 (doom-modeline-override-mu4e-alert) 2473 (doom-modeline-override-mu4e-modeline)))) 2474 2475 2476 ;; 2477 ;; `gnus' notifications 2478 ;; 2479 2480 (defvar doom-modeline--gnus-unread-mail 0) 2481 (defvar doom-modeline--gnus-started nil 2482 "Used to determine if gnus has started.") 2483 (defun doom-modeline-update-gnus-status (&rest _) 2484 "Get the total number of unread news of gnus group." 2485 (setq doom-modeline--gnus-unread-mail 2486 (when (and doom-modeline-gnus 2487 doom-modeline--gnus-started) 2488 (let ((total-unread-news-number 0)) 2489 (mapc (lambda (g) 2490 (let* ((group (car g)) 2491 (unread (eval `(gnus-group-unread ,group)))) 2492 (when (and (not (seq-contains-p doom-modeline-gnus-excluded-groups group)) 2493 (numberp unread) 2494 (> unread 0)) 2495 (setq total-unread-news-number (+ total-unread-news-number unread))))) 2496 gnus-newsrc-alist) 2497 total-unread-news-number)))) 2498 2499 ;; Update the modeline after changes have been made 2500 (add-hook 'gnus-group-update-hook #'doom-modeline-update-gnus-status) 2501 (add-hook 'gnus-summary-update-hook #'doom-modeline-update-gnus-status) 2502 (add-hook 'gnus-group-update-group-hook #'doom-modeline-update-gnus-status) 2503 (add-hook 'gnus-after-getting-new-news-hook #'doom-modeline-update-gnus-status) 2504 2505 ;; Only start to listen to gnus when gnus is actually running 2506 (defun doom-modeline-start-gnus-listener () 2507 "Start GNUS listener." 2508 (when (and doom-modeline-gnus 2509 (not doom-modeline--gnus-started)) 2510 (setq doom-modeline--gnus-started t) 2511 ;; Scan gnus in the background if the timer is higher than 0 2512 (doom-modeline-update-gnus-status) 2513 (if (> doom-modeline-gnus-timer 0) 2514 (gnus-demon-add-handler 'gnus-demon-scan-news doom-modeline-gnus-timer doom-modeline-gnus-idle)))) 2515 (add-hook 'gnus-started-hook #'doom-modeline-start-gnus-listener) 2516 2517 ;; Stop the listener if gnus isn't running 2518 (defun doom-modeline-stop-gnus-listener () 2519 "Stop GNUS listener." 2520 (setq doom-modeline--gnus-started nil)) 2521 (add-hook 'gnus-exit-gnus-hook #'doom-modeline-stop-gnus-listener) 2522 2523 (doom-modeline-def-segment gnus 2524 "Show notifications of any unread emails in `gnus'." 2525 (when (and (doom-modeline--segment-visible 'gnus) 2526 doom-modeline-gnus 2527 doom-modeline--gnus-started 2528 ;; Don't display if the unread mails count is zero 2529 (numberp doom-modeline--gnus-unread-mail) 2530 (> doom-modeline--gnus-unread-mail 0)) 2531 (let ((sep (doom-modeline-spc)) 2532 (vsep (doom-modeline-vspc))) 2533 (concat 2534 sep 2535 (propertize 2536 (concat 2537 (doom-modeline-icon 'mdicon "nf-md-email" "đ§" "#" 2538 :face 'doom-modeline-notification) 2539 vsep 2540 (propertize 2541 (if (> doom-modeline--gnus-unread-mail doom-modeline-number-limit) 2542 (format "%d+" doom-modeline-number-limit) 2543 (number-to-string doom-modeline--gnus-unread-mail)) 2544 'face '(:inherit 2545 (doom-modeline-unread-number doom-modeline-notification)))) 2546 'mouse-face 'doom-modeline-highlight 2547 'help-echo (if (= doom-modeline--gnus-unread-mail 1) 2548 "You have an unread email" 2549 (format "You have %s unread emails" doom-modeline--gnus-unread-mail))) 2550 sep)))) 2551 2552 2553 ;; 2554 ;; IRC notifications 2555 ;; 2556 2557 (defun doom-modeline-shorten-irc (name) 2558 "Shorten IRC buffer `name' according to IRC mode. 2559 2560 Calls the mode specific function to return the shortened 2561 version of `NAME' if applicable: 2562 - Circe: `tracking-shorten' 2563 - ERC: `erc-track-shorten-function' 2564 - rcirc: `rcirc-shorten-buffer-name' 2565 2566 The specific function will decide how to stylize the buffer name, 2567 read the individual functions documentation for more." 2568 (or (and (fboundp 'tracking-shorten) 2569 (car (tracking-shorten (list name)))) 2570 (and (boundp 'erc-track-shorten-function) 2571 (functionp erc-track-shorten-function) 2572 (car (funcall erc-track-shorten-function (list name)))) 2573 (and (fboundp 'rcirc-short-buffer-name) 2574 (rcirc-short-buffer-name name)) 2575 name)) 2576 2577 (defun doom-modeline--tracking-buffers (buffers) 2578 "Logic to convert some irc BUFFERS to their font-awesome icon." 2579 (mapconcat 2580 (lambda (b) 2581 (propertize 2582 (funcall doom-modeline-irc-stylize b) 2583 'face '(:inherit (doom-modeline-unread-number doom-modeline-notification)) 2584 'help-echo (format "IRC Notification: %s\nmouse-1: Switch to buffer" b) 2585 'mouse-face 'doom-modeline-highlight 2586 'local-map (make-mode-line-mouse-map 2587 'mouse-1 2588 (lambda () 2589 (interactive) 2590 (when (buffer-live-p (get-buffer b)) 2591 (switch-to-buffer b)))))) 2592 buffers 2593 (doom-modeline-vspc))) 2594 2595 (defun doom-modeline--circe-p () 2596 "Check if `circe' is in use." 2597 (boundp 'tracking-mode-line-buffers)) 2598 2599 (defun doom-modeline--erc-p () 2600 "Check if `erc' is in use." 2601 (boundp 'erc-modified-channels-alist)) 2602 2603 (defun doom-modeline--rcirc-p () 2604 "Check if `rcirc' is in use." 2605 (bound-and-true-p rcirc-track-minor-mode)) 2606 2607 (defun doom-modeline--get-buffers () 2608 "Gets the buffers that have activity." 2609 (cond 2610 ((doom-modeline--circe-p) 2611 tracking-buffers) 2612 ((doom-modeline--erc-p) 2613 (mapcar (lambda (l) 2614 (buffer-name (car l))) 2615 erc-modified-channels-alist)) 2616 ((doom-modeline--rcirc-p) 2617 (mapcar (lambda (b) 2618 (buffer-name b)) 2619 rcirc-activity)))) 2620 2621 ;; Create a modeline segment that contains all the irc tracked buffers 2622 (doom-modeline-def-segment irc-buffers 2623 "The list of shortened, unread irc buffers." 2624 (when (and doom-modeline-irc 2625 (doom-modeline--segment-visible 'irc-buffers)) 2626 (let* ((buffers (doom-modeline--get-buffers)) 2627 (number (length buffers)) 2628 (sep (doom-modeline-spc))) 2629 (when (> number 0) 2630 (concat 2631 sep 2632 (doom-modeline--tracking-buffers buffers) 2633 sep))))) 2634 2635 (doom-modeline-def-segment irc 2636 "A notification icon for any unread irc buffer." 2637 (when (and doom-modeline-irc 2638 (doom-modeline--segment-visible 'irc)) 2639 (let* ((buffers (doom-modeline--get-buffers)) 2640 (number (length buffers)) 2641 (sep (doom-modeline-spc)) 2642 (vsep (doom-modeline-vspc))) 2643 (when (> number 0) 2644 (concat 2645 sep 2646 2647 (propertize (concat 2648 (doom-modeline-icon 'mdicon "nf-md-message_processing" "đ" "#" 2649 :face 'doom-modeline-notification) 2650 vsep 2651 ;; Display the number of unread buffers 2652 (propertize (number-to-string number) 2653 'face '(:inherit 2654 (doom-modeline-unread-number 2655 doom-modeline-notification)))) 2656 'help-echo (format "IRC Notifications: %s\n%s" 2657 (mapconcat 2658 (lambda (b) (funcall doom-modeline-irc-stylize b)) 2659 buffers 2660 ", ") 2661 (cond 2662 ((doom-modeline--circe-p) 2663 "mouse-1: Switch to previous unread buffer 2664 mouse-3: Switch to next unread buffer") 2665 ((doom-modeline--erc-p) 2666 "mouse-1: Switch to buffer 2667 mouse-3: Switch to next unread buffer") 2668 ((doom-modeline--rcirc-p) 2669 "mouse-1: Switch to server buffer 2670 mouse-3: Switch to next unread buffer"))) 2671 'mouse-face 'doom-modeline-highlight 2672 'local-map (let ((map (make-sparse-keymap))) 2673 (cond 2674 ((doom-modeline--circe-p) 2675 (define-key map [mode-line mouse-1] 2676 #'tracking-previous-buffer) 2677 (define-key map [mode-line mouse-3] 2678 #'tracking-next-buffer)) 2679 ((doom-modeline--erc-p) 2680 (define-key map [mode-line mouse-1] 2681 #'erc-switch-to-buffer) 2682 (define-key map [mode-line mouse-3] 2683 #'erc-track-switch-buffer)) 2684 ((doom-modeline--rcirc-p) 2685 (define-key map [mode-line mouse-1] 2686 #'rcirc-switch-to-server-buffer) 2687 (define-key map [mode-line mouse-3] 2688 #'rcirc-next-active-buffer))) 2689 map)) 2690 2691 ;; Display the unread irc buffers as well 2692 (when doom-modeline-irc-buffers 2693 (concat sep (doom-modeline--tracking-buffers buffers))) 2694 2695 sep))))) 2696 2697 (defun doom-modeline-override-rcirc () 2698 "Override default `rcirc' mode-line." 2699 (if (and doom-modeline-irc 2700 (bound-and-true-p doom-modeline-mode)) 2701 (setq global-mode-string 2702 (delq 'rcirc-activity-string global-mode-string)) 2703 (when (and rcirc-track-minor-mode 2704 (not (memq 'rcirc-activity-string global-mode-string))) 2705 (setq global-mode-string 2706 (append global-mode-string '(rcirc-activity-string)))))) 2707 (add-hook 'rcirc-track-minor-mode-hook #'doom-modeline-override-rcirc) 2708 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-rcirc) 2709 2710 (doom-modeline-add-variable-watcher 2711 'doom-modeline-irc 2712 (lambda (_sym val op _where) 2713 (when (eq op 'set) 2714 (setq doom-modeline-irc val) 2715 (doom-modeline-override-rcirc)))) 2716 2717 2718 ;; 2719 ;; Battery status 2720 ;; 2721 2722 (defun doom-modeline-battery-icon (icon unicode text face) 2723 "Displays the battery ICON with FACE. 2724 2725 UNICODE and TEXT are fallbacks. 2726 Uses `nerd-icons-mdicon' to fetch the icon." 2727 (doom-modeline-icon 'mdicon icon unicode text :face face)) 2728 2729 (defvar doom-modeline--battery-status nil) 2730 (defun doom-modeline-update-battery-status () 2731 "Update battery status." 2732 (setq doom-modeline--battery-status 2733 (when (and doom-modeline-battery 2734 (bound-and-true-p display-battery-mode)) 2735 (let* ((data (and battery-status-function 2736 (functionp battery-status-function) 2737 (funcall battery-status-function))) 2738 (status (cdr (assoc ?L data))) 2739 (charging? (or (string-equal "AC" status) 2740 (string-equal "on-line" status))) 2741 (percentage (car (read-from-string (or (cdr (assq ?p data)) "ERR")))) 2742 (valid-percentage? (and (numberp percentage) 2743 (>= percentage 0) 2744 (<= percentage battery-mode-line-limit))) 2745 (face (if valid-percentage? 2746 (cond (charging? 'doom-modeline-battery-charging) 2747 ((< percentage battery-load-critical) 'doom-modeline-battery-critical) 2748 ((< percentage 25) 'doom-modeline-battery-warning) 2749 ((< percentage 95) 'doom-modeline-battery-normal) 2750 (t 'doom-modeline-battery-full)) 2751 'doom-modeline-battery-error)) 2752 (icon (if valid-percentage? 2753 (cond 2754 ((>= percentage 100) 2755 (doom-modeline-battery-icon (if charging? 2756 "nf-md-battery_charging_100" 2757 "nf-md-battery") 2758 "đ" "-" face)) 2759 ((>= percentage 90) 2760 (doom-modeline-battery-icon (if charging? 2761 "nf-md-battery_charging_90" 2762 "nf-md-battery_90") 2763 "đ" "-" face)) 2764 ((>= percentage 80) 2765 (doom-modeline-battery-icon (if charging? 2766 "nf-md-battery_charging_80" 2767 "nf-md-battery_80") 2768 "đ" "-" face)) 2769 ((>= percentage 70) 2770 (doom-modeline-battery-icon (if charging? 2771 "nf-md-battery_charging_70" 2772 "nf-md-battery_70") 2773 "đ" "-" face)) 2774 ((>= percentage 60) 2775 (doom-modeline-battery-icon (if charging? 2776 "nf-md-battery_charging_60" 2777 "nf-md-battery_60") 2778 "đ" "-" face)) 2779 ((>= percentage 50) 2780 (doom-modeline-battery-icon (if charging? 2781 "nf-md-battery_charging_50" 2782 "nf-md-battery_50") 2783 "đ" "-" face)) 2784 ((>= percentage 40) 2785 (doom-modeline-battery-icon (if charging? 2786 "nf-md-battery_charging_40" 2787 "nf-md-battery_40") 2788 "đ" "-" face)) 2789 ((>= percentage 30) 2790 (doom-modeline-battery-icon (if charging? 2791 "nf-md-battery_charging_30" 2792 "nf-md-battery_30") 2793 "đ" "-" face)) 2794 ((>= percentage 20) 2795 (doom-modeline-battery-icon (if charging? 2796 "nf-md-battery_charging_20" 2797 "nf-md-battery_20") 2798 "đ" "-" face)) 2799 ((>= percentage 10) 2800 (doom-modeline-battery-icon (if charging? 2801 "nf-md-battery_charging_10" 2802 "nf-md-battery_10") 2803 "đĒĢ" "-" face)) 2804 (t (doom-modeline-battery-icon (if charging? 2805 "nf-md-battery_charging_outline" 2806 "nf-md-battery_outline") 2807 "đĒĢ" "!" face))) 2808 (doom-modeline-battery-icon "nf-md-battery_alert" "â " "N/A" face))) 2809 (text (if valid-percentage? (format "%d%s" percentage "%%") "")) 2810 (help-echo (if (and battery-echo-area-format data valid-percentage?) 2811 (battery-format battery-echo-area-format data) 2812 "Battery status not available"))) 2813 (cons (propertize icon 'help-echo help-echo) 2814 (propertize text 'face face 'help-echo help-echo)))))) 2815 2816 (doom-modeline-add-variable-watcher 2817 'doom-modeline-icon 2818 (lambda (_sym val op _where) 2819 (when (eq op 'set) 2820 (setq doom-modeline-icon val) 2821 (doom-modeline-update-battery-status)))) 2822 2823 (doom-modeline-add-variable-watcher 2824 'doom-modeline-unicode-fallback 2825 (lambda (_sym val op _where) 2826 (when (eq op 'set) 2827 (setq doom-modeline-unicode-fallback val) 2828 (doom-modeline-update-battery-status)))) 2829 2830 (doom-modeline-def-segment battery 2831 "Display battery status." 2832 (when (and doom-modeline-battery 2833 (bound-and-true-p display-battery-mode) 2834 (doom-modeline--segment-visible 'battery)) 2835 (let ((sep (doom-modeline-spc)) 2836 (vsep (doom-modeline-vspc))) 2837 (concat sep 2838 (car doom-modeline--battery-status) 2839 vsep 2840 (cdr doom-modeline--battery-status) 2841 sep)))) 2842 2843 (defun doom-modeline-override-battery () 2844 "Override default battery mode-line." 2845 (if (and doom-modeline-battery 2846 (bound-and-true-p doom-modeline-mode)) 2847 (progn 2848 (advice-add #'battery-update :override #'doom-modeline-update-battery-status) 2849 (setq global-mode-string 2850 (delq 'battery-mode-line-string global-mode-string)) 2851 (and (bound-and-true-p display-battery-mode) (battery-update))) 2852 (progn 2853 (advice-remove #'battery-update #'doom-modeline-update-battery-status) 2854 (when (and display-battery-mode battery-status-function battery-mode-line-format 2855 (not (memq 'battery-mode-line-string global-mode-string))) 2856 (setq global-mode-string 2857 (append global-mode-string '(battery-mode-line-string))))))) 2858 (add-hook 'display-battery-mode-hook #'doom-modeline-override-battery) 2859 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-battery) 2860 2861 (doom-modeline-add-variable-watcher 2862 'doom-modeline-battery 2863 (lambda (_sym val op _where) 2864 (when (eq op 'set) 2865 (setq doom-modeline-battery val) 2866 (doom-modeline-override-battery)))) 2867 2868 2869 ;; 2870 ;; Package information 2871 ;; 2872 2873 (doom-modeline-def-segment package 2874 "Show package information via `paradox'." 2875 (concat 2876 (doom-modeline-display-text 2877 (format-mode-line 'mode-line-front-space)) 2878 2879 (when (and doom-modeline-icon doom-modeline-major-mode-icon) 2880 (concat 2881 (doom-modeline-spc) 2882 (doom-modeline-icon 'faicon "nf-fa-archive" nil nil 2883 :face (doom-modeline-face 2884 (if doom-modeline-major-mode-color-icon 2885 'nerd-icons-silver 2886 'mode-line))))) 2887 (doom-modeline-display-text 2888 (format-mode-line 'mode-line-buffer-identification)))) 2889 2890 2891 ;; 2892 ;; Helm 2893 ;; 2894 2895 (defvar doom-modeline--helm-buffer-ids 2896 '(("*helm*" . "HELM") 2897 ("*helm M-x*" . "HELM M-x") 2898 ("*swiper*" . "SWIPER") 2899 ("*Projectile Perspectives*" . "HELM Projectile Perspectives") 2900 ("*Projectile Layouts*" . "HELM Projectile Layouts") 2901 ("*helm-ag*" . (lambda () 2902 (format "HELM Ag: Using %s" 2903 (car (split-string helm-ag-base-command)))))) 2904 "Alist of custom helm buffer names to use. 2905 The cdr can also be a function that returns a name to use.") 2906 2907 (doom-modeline-def-segment helm-buffer-id 2908 "Helm session identifier." 2909 (when (bound-and-true-p helm-alive-p) 2910 (let ((sep (doom-modeline-spc))) 2911 (concat 2912 sep 2913 (when doom-modeline-icon 2914 (concat 2915 (doom-modeline-icon 'sucicon "nf-custom-emacs" nil nil 2916 :face (doom-modeline-face 2917 (and doom-modeline-major-mode-color-icon 2918 'nerd-icons-blue))) 2919 sep)) 2920 (propertize 2921 (let ((custom (cdr (assoc (buffer-name) doom-modeline--helm-buffer-ids))) 2922 (case-fold-search t) 2923 (name (replace-regexp-in-string "-" " " (buffer-name)))) 2924 (cond ((stringp custom) custom) 2925 ((functionp custom) (funcall custom)) 2926 (t 2927 (string-match "\\*helm:? \\(mode \\)?\\([^\\*]+\\)\\*" name) 2928 (concat "HELM " (capitalize (match-string 2 name)))))) 2929 'face (doom-modeline-face 'doom-modeline-buffer-file)) 2930 sep)))) 2931 2932 (doom-modeline-def-segment helm-number 2933 "Number of helm candidates." 2934 (when (bound-and-true-p helm-alive-p) 2935 (concat 2936 (propertize (format " %d/%d" 2937 (helm-candidate-number-at-point) 2938 (helm-get-candidate-number t)) 2939 'face (doom-modeline-face 'doom-modeline-buffer-path)) 2940 (propertize (format " (%d total) " (helm-get-candidate-number)) 2941 'face (doom-modeline-face 'doom-modeline-info))))) 2942 2943 (doom-modeline-def-segment helm-help 2944 "Helm keybindings help." 2945 (when (bound-and-true-p helm-alive-p) 2946 (mapcar 2947 (lambda (s) 2948 (if (string-prefix-p "\\<" s) 2949 (propertize (substitute-command-keys s) 2950 'face (doom-modeline-face 2951 'doom-modeline-buffer-file)) 2952 s)) 2953 '("\\<helm-map>\\[helm-help]" "(help) " 2954 "\\<helm-map>\\[helm-select-action]" "(actions) " 2955 "\\<helm-map>\\[helm-maybe-exit-minibuffer]/F1/F2..." "(action) ")))) 2956 2957 (doom-modeline-def-segment helm-prefix-argument 2958 "Helm prefix argument." 2959 (when (and (bound-and-true-p helm-alive-p) 2960 helm--mode-line-display-prefarg) 2961 (let ((arg (prefix-numeric-value (or prefix-arg current-prefix-arg)))) 2962 (unless (= arg 1) 2963 (propertize (format "C-u %s" arg) 2964 'face (doom-modeline-face 'doom-modeline-info)))))) 2965 2966 (defvar doom-modeline--helm-current-source nil 2967 "The currently active helm source.") 2968 (doom-modeline-def-segment helm-follow 2969 "Helm follow indicator." 2970 (and (bound-and-true-p helm-alive-p) 2971 doom-modeline--helm-current-source 2972 (eq 1 (cdr (assq 'follow doom-modeline--helm-current-source))) 2973 "HF")) 2974 2975 ;; 2976 ;; Git timemachine 2977 ;; 2978 2979 (doom-modeline-def-segment git-timemachine 2980 (concat 2981 (doom-modeline-spc) 2982 (doom-modeline--buffer-mode-icon) 2983 (doom-modeline--buffer-state-icon) 2984 (propertize 2985 "*%b*" 2986 'face (doom-modeline-face 'doom-modeline-buffer-timemachine)))) 2987 2988 ;; 2989 ;; Markdown/Org preview 2990 ;; 2991 2992 (doom-modeline-def-segment grip 2993 (when (bound-and-true-p grip-mode) 2994 (let ((sep (doom-modeline-spc))) 2995 (concat 2996 sep 2997 (let ((face (doom-modeline-face 2998 (if grip--process 2999 (pcase (process-status grip--process) 3000 ('run 'doom-modeline-info) 3001 ('exit 'doom-modeline-warning) 3002 (_ 'doom-modeline-urgent)) 3003 'doom-modeline-urgent)))) 3004 (propertize 3005 (doom-modeline-icon 'codicon "nf-cod-open_preview" "đ" "@" :face face) 3006 'help-echo (format "Preview on %s 3007 mouse-1: Preview in browser 3008 mouse-2: Stop preview 3009 mouse-3: Restart preview" 3010 (grip--preview-url)) 3011 'mouse-face 'doom-modeline-highlight 3012 'local-map (let ((map (make-sparse-keymap))) 3013 (define-key map [mode-line mouse-1] 3014 #'grip-browse-preview) 3015 (define-key map [mode-line mouse-2] 3016 #'grip-stop-preview) 3017 (define-key map [mode-line mouse-3] 3018 #'grip-restart-preview) 3019 map))) 3020 sep)))) 3021 3022 ;; 3023 ;; Follow mode 3024 ;; 3025 3026 (doom-modeline-def-segment follow 3027 (when (bound-and-true-p follow-mode) 3028 (let* ((windows (follow-all-followers)) 3029 (nwindows (length windows)) 3030 (nfollowing (- (length (memq (selected-window) windows)) 1))) 3031 (concat 3032 (doom-modeline-spc) 3033 (propertize (format "Follow %d/%d" (- nwindows nfollowing) nwindows) 3034 'face 'doom-modeline-buffer-minor-mode))))) 3035 3036 ;; 3037 ;; Display time 3038 ;; 3039 3040 (defconst doom-modeline--clock-hour-hand-ratio 0.45 3041 "Length of the hour hand as a proportion of the radius.") 3042 3043 (defconst doom-modeline--clock-minute-hand-ratio 0.7 3044 "Length of the minute hand as a proportion of the radius.") 3045 3046 (defun doom-modeline--create-clock-svg (hour minute radius color) 3047 "Construct an SVG clock showing the time HOUR:MINUTE. 3048 The clock will be of the specified RADIUS and COLOR." 3049 (let ((thickness-factor (image-compute-scaling-factor 'auto)) 3050 (hour-x (* radius (sin (* (- 6 hour (/ minute 60.0)) (/ float-pi 6))) 3051 doom-modeline--clock-hour-hand-ratio)) 3052 (hour-y (* radius (cos (* (- 6 hour (/ minute 60.0)) (/ float-pi 6))) 3053 doom-modeline--clock-hour-hand-ratio)) 3054 (minute-x (* radius (sin (* (- 30 minute) (/ float-pi 30))) 3055 doom-modeline--clock-minute-hand-ratio)) 3056 (minute-y (* radius (cos (* (- 30 minute) (/ float-pi 30))) 3057 doom-modeline--clock-minute-hand-ratio)) 3058 (svg (svg-create (* 2 radius) (* 2 radius) :stroke color))) 3059 (svg-circle svg radius radius (- radius thickness-factor) 3060 :fill "none" :stroke-width (* 2 thickness-factor)) 3061 (svg-circle svg radius radius thickness-factor 3062 :fill color :stroke "none") 3063 (svg-line svg radius radius (+ radius hour-x) (+ radius hour-y) 3064 :stroke-width (* 2 thickness-factor)) 3065 (svg-line svg radius radius (+ radius minute-x) (+ radius minute-y) 3066 :stroke-width (* 1.5 thickness-factor)) 3067 svg)) 3068 3069 (defvar doom-modeline--clock-cache nil 3070 "The last result of `doom-modeline--generate-clock'.") 3071 3072 (defun doom-modeline--generate-clock () 3073 "Return a string containing the current time as an analogue clock svg. 3074 When the svg library is not available, return nil." 3075 (cdr 3076 (or (and (equal (truncate (float-time) 3077 (* doom-modeline-time-clock-minute-resolution 60)) 3078 (car doom-modeline--clock-cache)) 3079 doom-modeline--clock-cache) 3080 (and (require 'svg nil t) 3081 (setq doom-modeline--clock-cache 3082 (cons (truncate (float-time) 3083 (* doom-modeline-time-clock-minute-resolution 60)) 3084 (propertize 3085 " " 3086 'display 3087 (svg-image 3088 (doom-modeline--create-clock-svg 3089 (string-to-number (format-time-string "%-I")) ; hour 3090 (* (truncate (string-to-number (format-time-string "%-M")) 3091 doom-modeline-time-clock-minute-resolution) 3092 doom-modeline-time-clock-minute-resolution) ; minute 3093 (if (integerp doom-modeline-time-clock-size) ; radius 3094 doom-modeline-time-clock-size 3095 (* doom-modeline-height 0.5 doom-modeline-time-clock-size)) 3096 "currentColor") 3097 :scale 1 :ascent 'center) 3098 'face 'doom-modeline-time 3099 'help-echo (lambda (_window _object _pos) 3100 (format-time-string "%c"))))))))) 3101 3102 (defun doom-modeline-time-icon () 3103 "Displays the time icon." 3104 (or (and doom-modeline-time-live-icon 3105 doom-modeline-time-analogue-clock 3106 (display-graphic-p) 3107 (doom-modeline--generate-clock)) 3108 (doom-modeline-icon 3109 'mdicon 3110 (if doom-modeline-time-live-icon 3111 (pcase (% (caddr (decode-time)) 12) 3112 (0 "nf-md-clock_time_twelve_outline") 3113 (1 "nf-md-clock_time_one_outline") 3114 (2 "nf-md-clock_time_two_outline") 3115 (3 "nf-md-clock_time_three_outline") 3116 (4 "nf-md-clock_time_four_outline") 3117 (5 "nf-md-clock_time_five_outline") 3118 (6 "nf-md-clock_time_six_outline") 3119 (7 "nf-md-clock_time_seven_outline") 3120 (8 "nf-md-clock_time_eight_outline") 3121 (9 "nf-md-clock_time_nine_outline") 3122 (10 "nf-md-clock_time_ten_outline") 3123 (11 "nf-md-clock_time_eleven_outline")) 3124 "nf-md-clock_outline") 3125 "â°" 3126 "" 3127 :face '(:inherit doom-modeline-time :weight normal)))) 3128 3129 (doom-modeline-def-segment time 3130 (when (and doom-modeline-time 3131 (bound-and-true-p display-time-mode) 3132 (doom-modeline--segment-visible 'time)) 3133 (concat 3134 (doom-modeline-spc) 3135 (when doom-modeline-time-icon 3136 (concat 3137 (doom-modeline-time-icon) 3138 (and (or doom-modeline-icon doom-modeline-unicode-fallback) 3139 (doom-modeline-vspc)))) 3140 (propertize display-time-string 3141 'face (doom-modeline-face 'doom-modeline-time))))) 3142 3143 (defun doom-modeline-override-time () 3144 "Override default `display-time' mode-line." 3145 (or global-mode-string (setq global-mode-string '(""))) 3146 (if (and doom-modeline-time 3147 (bound-and-true-p doom-modeline-mode)) 3148 (setq global-mode-string (delq 'display-time-string global-mode-string)) 3149 (or (memq 'display-time-string global-mode-string) 3150 (setq global-mode-string 3151 (append global-mode-string '(display-time-string)))))) 3152 (add-hook 'display-time-mode-hook #'doom-modeline-override-time) 3153 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-time) 3154 3155 (doom-modeline-add-variable-watcher 3156 'doom-modeline-time 3157 (lambda (_sym val op _where) 3158 (when (eq op 'set) 3159 (setq doom-modeline-time val) 3160 (doom-modeline-override-time)))) 3161 3162 ;; 3163 ;; Compilation 3164 ;; 3165 3166 (doom-modeline-def-segment compilation 3167 (and (bound-and-true-p compilation-in-progress) 3168 (propertize "[Compiling] " 3169 'face (doom-modeline-face 'doom-modeline-compilation) 3170 'help-echo "Compiling; mouse-2: Goto Buffer" 3171 'mouse-face 'doom-modeline-highlight 3172 'local-map 3173 (make-mode-line-mouse-map 3174 'mouse-2 3175 #'compilation-goto-in-progress-buffer)))) 3176 3177 ;; 3178 ;; Eldoc 3179 ;; 3180 3181 (doom-modeline-def-segment eldoc 3182 (and (bound-and-true-p eldoc-mode) 3183 '(eldoc-mode-line-string 3184 (" " eldoc-mode-line-string " ")))) 3185 3186 (defun doom-modeline-eldoc-minibuffer-message (format-string &rest args) 3187 "Display message specified by FORMAT-STRING and ARGS on the mode-line as needed. 3188 This function displays the message produced by formatting ARGS 3189 with FORMAT-STRING on the mode line when the current buffer is a minibuffer. 3190 Otherwise, it displays the message like `message' would." 3191 (if (minibufferp) 3192 (progn 3193 (add-hook 'minibuffer-exit-hook 3194 (lambda () (setq eldoc-mode-line-string nil 3195 ;; https://debbugs.gnu.org/16920 3196 eldoc-last-message nil)) 3197 nil t) 3198 (with-current-buffer 3199 (window-buffer 3200 (or (window-in-direction 'above (minibuffer-window)) 3201 (minibuffer-selected-window) 3202 (get-largest-window))) 3203 (setq eldoc-mode-line-string 3204 (when (stringp format-string) 3205 (apply #'format-message format-string args))) 3206 (force-mode-line-update))) 3207 (apply #'message format-string args))) 3208 3209 ;; 3210 ;; Kubernetes 3211 ;; 3212 3213 (doom-modeline-def-segment k8s 3214 (when (and (bound-and-true-p kele-mode) (doom-modeline--segment-visible 'k8s)) 3215 (let* ((ctx (kele-current-context-name :wait nil)) 3216 (ns (kele-current-namespace :wait nil)) 3217 (icon (doom-modeline-icon 'mdicon "nf-md-kubernetes" "K8s:" "K8s:")) 3218 (sep (doom-modeline-spc)) 3219 (help-msg (let ((msgs (list (format "Current context: %s" ctx)))) 3220 (when ns 3221 (setq msgs (append msgs (list (format "Current namespace: %s" ns))))) 3222 (string-join msgs "\n")))) 3223 (propertize (concat 3224 icon sep ctx 3225 (when (and doom-modeline-k8s-show-namespace ns) (format "(%s)" ns)) 3226 sep) 3227 'local-map (let ((map (make-sparse-keymap))) 3228 (define-key map [mode-line down-mouse-1] kele-menu-map) 3229 map) 3230 'mouse-face 'doom-modeline-highlight 3231 'help-echo help-msg)))) 3232 3233 (provide 'doom-modeline-segments) 3234 3235 ;;; doom-modeline-segments.el ends here