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