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