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