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