doom-modeline-core.el (63223B)
1 ;;; doom-modeline-core.el --- The core libraries 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 core libraries for doom-modeline. 25 ;; 26 27 ;;; Code: 28 29 (require 'compat) 30 (eval-when-compile 31 (require 'cl-lib) 32 (require 'subr-x)) 33 (require 'nerd-icons) 34 (require 'shrink-path) 35 36 37 ;; 38 ;; Compatibility 39 ;; 40 41 (unless (boundp 'mode-line-right-align-edge) 42 (defcustom mode-line-right-align-edge 'window 43 "Where mode-line should align to. 44 Internally, that function uses `:align-to' in a display property, 45 so aligns to the left edge of the given area. See info node 46 `(elisp)Pixel Specification'. 47 48 Must be set to a symbol. Acceptable values are: 49 - `window': align to extreme right of window, regardless of margins 50 or fringes 51 - `right-fringe': align to right-fringe 52 - `right-margin': align to right-margin" 53 :type '(choice (const right-margin) 54 (const right-fringe) 55 (const window)) 56 :group 'mode-line)) 57 58 59 ;; 60 ;; Optimization 61 ;; 62 63 ;; Don’t compact font caches during GC. 64 (when (eq system-type 'windows-nt) 65 (setq inhibit-compacting-font-caches t)) 66 67 68 ;; 69 ;; Customization 70 ;; 71 72 (defgroup doom-modeline nil 73 "A minimal and modern mode-line." 74 :group 'mode-line 75 :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) 76 77 (defcustom doom-modeline-support-imenu nil 78 "If non-nil, cause imenu to see `doom-modeline' declarations. 79 This is done by adjusting `lisp-imenu-generic-expression' to 80 include support for finding `doom-modeline-def-*' forms. 81 82 Must be set before loading `doom-modeline'." 83 :type 'boolean 84 :set (lambda (_sym val) 85 (if val 86 (add-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu) 87 (remove-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu))) 88 :group 'doom-modeline) 89 90 (defcustom doom-modeline-height (+ (frame-char-height) 4) 91 "How tall the mode-line should be. It's only respected in GUI. 92 If the actual char height is larger, it respects the actual char height." 93 :type 'integer 94 :group 'doom-modeline) 95 96 (defcustom doom-modeline-bar-width 4 97 "How wide the mode-line bar should be. It's only respected in GUI." 98 :type 'integer 99 :set (lambda (sym val) 100 (set sym (if (> val 0) val 1))) 101 :group 'doom-modeline) 102 103 (defcustom doom-modeline-hud nil 104 "Whether to use hud instead of default bar. It's only respected in GUI." 105 :type 'boolean 106 :group 'doom-modeline) 107 108 (defcustom doom-modeline-hud-min-height 2 109 "Minimum height in pixels of the \"thumb\" of the hud. 110 Only respected in GUI." 111 :type 'integer 112 :set (lambda (sym val) 113 (set sym (if (> val 1) val 1))) 114 :group 'doom-modeline) 115 116 (defcustom doom-modeline-window-width-limit 85 117 "The limit of the window width. 118 119 If `window-width' is smaller than the limit, some information won't be 120 displayed. It can be an integer or a float number. nil means no limit." 121 :type '(choice integer 122 float 123 (const :tag "Disable" nil)) 124 :group 'doom-modeline) 125 126 (defcustom doom-modeline-project-detection 'auto 127 "How to detect the project root. 128 129 nil means to use `default-directory'. 130 131 The project management packages have some issues on detecting project root. 132 e.g. `projectile' doesn't handle symlink folders well, while `project' is 133 unable to handle sub-projects. 134 Specify another one if you encounter the issue." 135 :type '(choice (const :tag "Auto-detect" auto) 136 (const :tag "Find File in Project" ffip) 137 (const :tag "Projectile" projectile) 138 (const :tag "Built-in Project" project) 139 (const :tag "Disable" nil)) 140 :group 'doom-modeline) 141 142 (defcustom doom-modeline-buffer-file-name-style 'auto 143 "Determines the style used by `doom-modeline-buffer-file-name'. 144 145 Given ~/Projects/FOSS/emacs/lisp/comint.el 146 auto => emacs/l/comint.el (in a project) or comint.el 147 truncate-upto-project => ~/P/F/emacs/lisp/comint.el 148 truncate-from-project => ~/Projects/FOSS/emacs/l/comint.el 149 truncate-with-project => emacs/l/comint.el 150 truncate-except-project => ~/P/F/emacs/l/comint.el 151 truncate-upto-root => ~/P/F/e/lisp/comint.el 152 truncate-all => ~/P/F/e/l/comint.el 153 truncate-nil => ~/Projects/FOSS/emacs/lisp/comint.el 154 relative-from-project => emacs/lisp/comint.el 155 relative-to-project => lisp/comint.el 156 file-name => comint.el 157 file-name-with-project => FOSS|comint.el 158 buffer-name => comint.el<2> (uniquify buffer name)" 159 :type '(choice (const auto) 160 (const truncate-upto-project) 161 (const truncate-from-project) 162 (const truncate-with-project) 163 (const truncate-except-project) 164 (const truncate-upto-root) 165 (const truncate-all) 166 (const truncate-nil) 167 (const relative-from-project) 168 (const relative-to-project) 169 (const file-name) 170 (const file-name-with-project) 171 (const buffer-name)) 172 :group'doom-modeline) 173 174 (defcustom doom-modeline-buffer-file-true-name nil 175 "Use `file-truename' on buffer file name. 176 177 Project detection(projectile.el) may uses `file-truename' on directory path. 178 Turn on this to provide right relative path for buffer file name." 179 :type 'boolean 180 :group'doom-modeline) 181 182 (defcustom doom-modeline-icon t 183 "Whether display the icons in the mode-line. 184 185 While using the server mode in GUI, should set the value explicitly." 186 :type 'boolean 187 :group 'doom-modeline) 188 189 (defcustom doom-modeline-major-mode-icon t 190 "Whether display the icon for `major-mode'. 191 192 It respects option `doom-modeline-icon'." 193 :type 'boolean 194 :group'doom-modeline) 195 196 (defcustom doom-modeline-major-mode-color-icon t 197 "Whether display the colorful icon for `major-mode'. 198 199 It respects option `nerd-icons-color-icons'." 200 :type 'boolean 201 :group'doom-modeline) 202 203 (defcustom doom-modeline-buffer-state-icon t 204 "Whether display the icon for the buffer state. 205 206 It respects option `doom-modeline-icon'." 207 :type 'boolean 208 :group 'doom-modeline) 209 210 (defcustom doom-modeline-buffer-modification-icon t 211 "Whether display the modification icon for the buffer. 212 213 It respects option `doom-modeline-icon' and `doom-modeline-buffer-state-icon'." 214 :type 'boolean 215 :group 'doom-modeline) 216 217 (defcustom doom-modeline-lsp-icon t 218 "Whether display the icon of lsp client. 219 220 It respects option `doom-modeline-icon'." 221 :type 'boolean 222 :group 'doom-modeline) 223 224 (defcustom doom-modeline-time-icon t 225 "Whether display the icon of time. 226 227 It respects option `doom-modeline-icon'." 228 :type 'boolean 229 :group 'doom-modeline) 230 231 (defcustom doom-modeline-time-live-icon t 232 "Whether display the live icons of time. 233 234 It respects option `doom-modeline-icon' and option `doom-modeline-time-icon'." 235 :type 'boolean 236 :group 'doom-modeline) 237 238 (defcustom doom-modeline-time-analogue-clock t 239 "Whether to draw an analogue clock SVG as the live time icon. 240 It respects the option `doom-modeline-icon', option `doom-modeline-time-icon', 241 and option `doom-modeline-time-live-icon'." 242 :type 'boolean 243 :group 'doom-modeline) 244 245 (defcustom doom-modeline-time-clock-minute-resolution 1 246 "The clock will be updated every this many minutes, truncated. 247 See `doom-modeline-time-analogue-clock'." 248 :type 'natnum 249 :group 'doom-modeline) 250 251 (defcustom doom-modeline-time-clock-size 0.7 252 "Size of the analogue clock drawn, either in pixels or as a proportional height. 253 An integer value is used as the diameter of clock in pixels. 254 A floating point value sets the diameter of the clock realtive to 255 `doom-modeline-height'. 256 257 Only relevant when `doom-modeline-time-analogue-clock' is non-nil, which see." 258 :type 'number 259 :group 'doom-modeline) 260 261 (defcustom doom-modeline-unicode-fallback nil 262 "Whether to use unicode as a fallback (instead of ASCII) when not using icons." 263 :type 'boolean 264 :group 'doom-modeline) 265 266 (defcustom doom-modeline-buffer-name t 267 "Whether display the buffer name." 268 :type 'boolean 269 :group 'doom-modeline) 270 271 (defcustom doom-modeline-highlight-modified-buffer-name t 272 "Whether highlight the modified buffer name." 273 :type 'boolean 274 :group 'doom-modeline) 275 276 (defcustom doom-modeline-column-zero-based t 277 "When non-nil, mode line displays column numbers zero-based. 278 See `column-number-indicator-zero-based'." 279 :type 'boolean 280 :group 'doom-modeline) 281 282 (defcustom doom-modeline-percent-position '(-3 "%p") 283 "Specification of \"percentage offset\" of window through buffer. 284 See `mode-line-percent-position'." 285 :type '(radio 286 (const :tag "nil: No offset is displayed" nil) 287 (const :tag "\"%o\": Proportion of \"travel\" of the window through the buffer" 288 (-3 "%o")) 289 (const :tag "\"%p\": Percentage offset of top of window" 290 (-3 "%p")) 291 (const :tag "\"%P\": Percentage offset of bottom of window" 292 (-3 "%P")) 293 (const :tag "\"%q\": Offsets of both top and bottom of window" 294 (6 "%q"))) 295 :group 'doom-modeline) 296 297 (defcustom doom-modeline-position-line-format '("L%l") 298 "Format used to display line numbers in the mode line. 299 See `mode-line-position-line-format'." 300 :type '(list string) 301 :group 'doom-modeline) 302 303 (defcustom doom-modeline-position-column-format '("C%c") 304 "Format used to display column numbers in the mode line. 305 See `mode-line-position-column-format'." 306 :type '(list string) 307 :group 'doom-modeline) 308 309 (defcustom doom-modeline-position-column-line-format '("%l:%c") 310 "Format used to display combined line/column numbers in the mode line. 311 See `mode-line-position-column-line-format'." 312 :type '(list string) 313 :group 'doom-modeline) 314 315 (defcustom doom-modeline-minor-modes nil 316 "Whether display the minor modes in the mode-line." 317 :type 'boolean 318 :group 'doom-modeline) 319 320 (defcustom doom-modeline-enable-word-count nil 321 "If non-nil, a word count will be added to the selection-info modeline segment." 322 :type 'boolean 323 :group 'doom-modeline) 324 325 (defcustom doom-modeline-continuous-word-count-modes 326 '(markdown-mode gfm-mode org-mode) 327 "Major modes in which to display word count continuously. 328 329 It respects `doom-modeline-enable-word-count'." 330 :type '(repeat (symbol :tag "Major-Mode") ) 331 :group 'doom-modeline) 332 333 (defcustom doom-modeline-buffer-encoding t 334 "Whether display the buffer encoding." 335 :type '(choice (const :tag "Always" t) 336 (const :tag "When non-default" nondefault) 337 (const :tag "Never" nil)) 338 :group 'doom-modeline) 339 340 (defcustom doom-modeline-default-coding-system 'utf-8 341 "Default coding system for `doom-modeline-buffer-encoding' `nondefault'." 342 :type 'coding-system 343 :group 'doom-modeline) 344 345 (defcustom doom-modeline-default-eol-type 0 346 "Default EOL type for `doom-modeline-buffer-encoding' `nondefault'." 347 :type '(choice (const :tag "Unix-style LF" 0) 348 (const :tag "DOS-style CRLF" 1) 349 (const :tag "Mac-style CR" 2)) 350 :group 'doom-modeline) 351 352 (defcustom doom-modeline-indent-info nil 353 "Whether display the indentation information." 354 :type 'boolean 355 :group 'doom-modeline) 356 357 (defcustom doom-modeline-total-line-number nil 358 "Whether display the total line number." 359 :type 'boolean 360 :group 'doom-modeline) 361 362 ;; It is based upon `editorconfig-indentation-alist' but is used to read indentation levels instead 363 ;; of setting them. (https://github.com/editorconfig/editorconfig-emacs) 364 (defcustom doom-modeline-indent-alist 365 '((apache-mode apache-indent-level) 366 (awk-mode c-basic-offset) 367 (bpftrace-mode c-basic-offset) 368 (c++-mode c-basic-offset) 369 (c-mode c-basic-offset) 370 (cmake-mode cmake-tab-width) 371 (coffee-mode coffee-tab-width) 372 (cperl-mode cperl-indent-level) 373 (crystal-mode crystal-indent-level) 374 (csharp-mode c-basic-offset) 375 (css-mode css-indent-offset) 376 (d-mode c-basic-offset) 377 (emacs-lisp-mode lisp-indent-offset) 378 (enh-ruby-mode enh-ruby-indent-level) 379 (erlang-mode erlang-indent-level) 380 (ess-mode ess-indent-offset) 381 (f90-mode f90-associate-indent 382 f90-continuation-indent 383 f90-critical-indent 384 f90-do-indent 385 f90-if-indent 386 f90-program-indent 387 f90-type-indent) 388 (feature-mode feature-indent-offset 389 feature-indent-level) 390 (fsharp-mode fsharp-continuation-offset 391 fsharp-indent-level 392 fsharp-indent-offset) 393 (groovy-mode groovy-indent-offset) 394 (haskell-mode haskell-indent-spaces 395 haskell-indent-offset 396 haskell-indentation-layout-offset 397 haskell-indentation-left-offset 398 haskell-indentation-starter-offset 399 haskell-indentation-where-post-offset 400 haskell-indentation-where-pre-offset 401 shm-indent-spaces) 402 (haxor-mode haxor-tab-width) 403 (idl-mode c-basic-offset) 404 (jade-mode jade-tab-width) 405 (java-mode c-basic-offset) 406 (js-mode js-indent-level) 407 (js-jsx-mode js-indent-level 408 sgml-basic-offset) 409 (js2-mode js2-basic-offset) 410 (js2-jsx-mode js2-basic-offset 411 sgml-basic-offset) 412 (js3-mode js3-indent-level) 413 (json-mode js-indent-level) 414 (julia-mode julia-indent-offset) 415 (kotlin-mode kotlin-tab-width) 416 (latex-mode tex-indent-basic) 417 (lisp-mode lisp-indent-offset) 418 (livescript-mode livescript-tab-width) 419 (lua-mode lua-indent-level) 420 (matlab-mode matlab-indent-level) 421 (mips-mode mips-tab-width) 422 (mustache-mode mustache-basic-offset) 423 (nasm-mode nasm-basic-offset) 424 (nginx-mode nginx-indent-level) 425 (nxml-mode nxml-child-indent) 426 (objc-mode c-basic-offset) 427 (octave-mode octave-block-offset) 428 (perl-mode perl-indent-level) 429 (php-mode c-basic-offset) 430 (pike-mode c-basic-offset) 431 (ps-mode ps-mode-tab) 432 (pug-mode pug-tab-width) 433 (puppet-mode puppet-indent-level) 434 (python-mode python-indent-offset) 435 (ruby-mode ruby-indent-level) 436 (rust-mode rust-indent-offset) 437 (rustic-mode rustic-indent-offset) 438 (scala-mode scala-indent:step) 439 (scss-mode css-indent-offset) 440 (sgml-mode sgml-basic-offset) 441 (sh-mode sh-basic-offset 442 sh-indentation) 443 (slim-mode slim-indent-offset) 444 (sml-mode sml-indent-level) 445 (tcl-mode tcl-indent-level 446 tcl-continued-indent-level) 447 (terra-mode terra-indent-level) 448 (typescript-mode typescript-indent-level) 449 (verilog-mode verilog-indent-level 450 verilog-indent-level-behavioral 451 verilog-indent-level-declaration 452 verilog-indent-level-module 453 verilog-cexp-indent 454 verilog-case-indent) 455 (web-mode web-mode-attr-indent-offset 456 web-mode-attr-value-indent-offset 457 web-mode-code-indent-offset 458 web-mode-css-indent-offset 459 web-mode-markup-indent-offset 460 web-mode-sql-indent-offset 461 web-mode-block-padding 462 web-mode-script-padding 463 web-mode-style-padding) 464 (yaml-mode yaml-indent-offset)) 465 "Indentation retrieving variables matched to major modes. 466 467 Which is used when `doom-modeline-indent-info' is non-nil. 468 When multiple variables are specified for a mode, they will be tried resolved 469 in the given order." 470 :type '(alist :key-type symbol :value-type sexp) 471 :group 'doom-modeline) 472 473 (defcustom doom-modeline-vcs-icon t 474 "Whether display the icon of vcs segment. 475 476 It respects option `doom-modeline-icon'." 477 :type 'boolean 478 :group 'doom-modeline) 479 480 (defcustom doom-modeline-vcs-max-length 15 481 "The maximum displayed length of the branch name of version control." 482 :type 'integer 483 :group 'doom-modeline) 484 485 (defcustom doom-modeline-vcs-display-function #'doom-modeline-vcs-name 486 "The function to display the branch name." 487 :type 'function 488 :group 'doom-modeline) 489 490 (defcustom doom-modeline-check-icon t 491 "Whether display the icon of check segment. 492 493 It respects option `doom-modeline-icon'." 494 :type 'boolean 495 :group 'doom-modeline) 496 497 (define-obsolete-variable-alias 498 'doom-modeline-checker-simple-format 499 'doom-modeline-check-simple-format 500 "4.2.0") 501 502 (defcustom doom-modeline-check-simple-format nil 503 "If non-nil, only display one number for check information if applicable." 504 :type 'boolean 505 :group 'doom-modeline) 506 507 (defcustom doom-modeline-number-limit 99 508 "The maximum number displayed for notifications." 509 :type 'integer 510 :group 'doom-modeline) 511 512 (defcustom doom-modeline-project-name (bound-and-true-p project-mode-line) 513 "Whether display the project name. 514 515 Non-nil to display in the mode-line." 516 :type 'boolean 517 :group 'doom-modeline) 518 519 (defcustom doom-modeline-workspace-name t 520 "Whether display the workspace name. 521 522 Non-nil to display in the mode-line." 523 :type 'boolean 524 :group 'doom-modeline) 525 526 (defcustom doom-modeline-persp-name t 527 "Whether display the perspective name. 528 529 Non-nil to display in the mode-line." 530 :type 'boolean 531 :group 'doom-modeline) 532 533 (defcustom doom-modeline-display-default-persp-name nil 534 "If non nil the default perspective name is displayed in the mode-line." 535 :type 'boolean 536 :group 'doom-modeline) 537 538 (defcustom doom-modeline-persp-icon t 539 "If non nil the perspective name is displayed alongside a folder icon." 540 :type 'boolean 541 :group 'doom-modeline) 542 543 (defcustom doom-modeline-repl t 544 "Whether display the `repl' state. 545 546 Non-nil to display in the mode-line." 547 :type 'boolean 548 :group 'doom-modeline) 549 550 (defcustom doom-modeline-lsp t 551 "Whether display the `lsp' state. 552 553 Non-nil to display in the mode-line." 554 :type 'boolean 555 :group 'doom-modeline) 556 557 (defcustom doom-modeline-github nil 558 "Whether display the GitHub notifications. 559 560 It requires `ghub' and `async' packages. Additionally, your GitHub personal 561 access token must have `notifications' permissions. 562 563 If you use `pass' to manage your secrets, you also need to add this hook: 564 (add-hook \\='doom-modeline-before-github-fetch-notification-hook 565 #\\='auth-source-pass-enable)" 566 :type 'boolean 567 :group 'doom-modeline) 568 569 (defcustom doom-modeline-github-interval 1800 ; (* 30 60) 570 "The interval of checking GitHub." 571 :type 'integer 572 :group 'doom-modeline) 573 574 (defcustom doom-modeline-env-version t 575 "Whether display the environment version." 576 :type 'boolean 577 :group 'doom-modeline) 578 579 (defcustom doom-modeline-modal t 580 "Whether display the modal state. 581 582 Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." 583 :type 'boolean 584 :group 'doom-modeline) 585 586 (defcustom doom-modeline-modal-icon t 587 "Whether display the modal state icon. 588 589 Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." 590 :type 'boolean 591 :group 'doom-modeline) 592 593 (defcustom doom-modeline-modal-modern-icon t 594 "Whether display the modern icons for modals." 595 :type 'boolean 596 :group 'doom-modeline) 597 598 (defcustom doom-modeline-always-show-macro-register nil 599 "When non-nil, always show the register name when recording an evil macro." 600 :type 'boolean 601 :group 'doom-modeline) 602 603 (defcustom doom-modeline-mu4e nil 604 "Whether display the mu4e notifications. 605 606 It requires `mu4e-alert' package." 607 :type 'boolean 608 :group 'doom-modeline) 609 610 (defcustom doom-modeline-gnus nil 611 "Whether to display notifications from gnus. 612 613 It requires `gnus' to be setup" 614 :type 'boolean 615 :group 'doom-modeline) 616 617 (defcustom doom-modeline-gnus-timer 2 618 "The wait time in minutes before gnus fetches mail. 619 620 If nil, don't set up a hook." 621 :type 'integer 622 :group 'doom-modeline) 623 624 (defcustom doom-modeline-gnus-idle nil 625 "Whether to wait an idle time to scan for news. 626 627 When t, sets `doom-modeline-gnus-timer' as an idle timer. If a 628 number, Emacs must have been idle this given time, checked after 629 reach the defined timer, to fetch news. The time step can be 630 configured in `gnus-demon-timestep'." 631 :type '(choice 632 (boolean :tag "Set `doom-modeline-gnus-timer' as an idle timer") 633 (number :tag "Set a custom idle timer")) 634 :group 'doom-modeline) 635 636 (defcustom doom-modeline-gnus-excluded-groups nil 637 "A list of groups to be excluded from the unread count. 638 Groups' names list in `gnus-newsrc-alist'`" 639 :type '(repeat string) 640 :group 'doom-modeline) 641 642 (defcustom doom-modeline-irc t 643 "Whether display the irc notifications. 644 645 It requires either `circe' , `erc' or `rcirc' package." 646 :type 'boolean 647 :group 'doom-modeline) 648 649 (defcustom doom-modeline-irc-buffers nil 650 "Whether display the unread irc buffers." 651 :type 'boolean 652 :group 'doom-modeline) 653 654 (defcustom doom-modeline-irc-stylize #'doom-modeline-shorten-irc 655 "Which function to call to stylize IRC buffer names. 656 657 Buffer names are stylized using the selected `function'. 658 By default buffer names are shortened, you may want to disable or call 659 your own function. 660 The function must accept `buffer-name' and return `shortened-name'." 661 :type '(radio (function-item :tag "Shorten" 662 :format "%t: %v\n %h" 663 doom-modeline-shorten-irc) 664 (function-item 665 :tag "Leave unchanged" 666 :format "%t: %v\n" 667 identity) 668 (function 669 :tag "Other function")) 670 :group 'doom-modeline) 671 672 (defcustom doom-modeline-battery t 673 "Whether display the battery status. 674 675 It respects `display-battery-mode'." 676 :type 'boolean 677 :group 'doom-modeline) 678 679 (defcustom doom-modeline-time t 680 "Whether display the time. 681 682 It respects `display-time-mode'." 683 :type 'boolean 684 :group 'doom-modeline) 685 686 (defcustom doom-modeline-display-misc-in-all-mode-lines t 687 "Whether display the misc segment on all mode lines. 688 689 If nil, display only if the mode line is active." 690 :type 'boolean 691 :group 'doom-modeline) 692 693 (defcustom doom-modeline-always-visible-segments nil 694 "A list of segments that should be visible even in inactive windows." 695 :type '(repeat symbol) 696 :group 'doom-modeline) 697 698 (defcustom doom-modeline-buffer-file-name-function #'identity 699 "The function to handle variable `buffer-file-name'." 700 :type 'function 701 :group 'doom-modeline) 702 703 (defcustom doom-modeline-buffer-file-truename-function #'identity 704 "The function to handle `buffer-file-truename'." 705 :type 'function 706 :group 'doom-modeline) 707 708 (defcustom doom-modeline-k8s-show-namespace t 709 "Whether to show the current Kubernetes context's default namespace." 710 :type 'boolean 711 :group 'doom-modeline) 712 713 714 ;; 715 ;; Faces 716 ;; 717 718 (defgroup doom-modeline-faces nil 719 "The faces of `doom-modeline'." 720 :group 'doom-modeline 721 :group 'faces 722 :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) 723 724 (defface doom-modeline 725 '((t ())) 726 "Default face." 727 :group 'doom-modeline-faces) 728 729 (defface doom-modeline-emphasis 730 '((t (:inherit (doom-modeline mode-line-emphasis)))) 731 "Face used for emphasis." 732 :group 'doom-modeline-faces) 733 734 (defface doom-modeline-highlight 735 '((t (:inherit (doom-modeline mode-line-highlight)))) 736 "Face used for highlighting." 737 :group 'doom-modeline-faces) 738 739 (defface doom-modeline-buffer-path 740 '((t (:inherit (doom-modeline-emphasis bold)))) 741 "Face used for the dirname part of the buffer path." 742 :group 'doom-modeline-faces) 743 744 (defface doom-modeline-buffer-file 745 '((t (:inherit (doom-modeline mode-line-buffer-id bold)))) 746 "Face used for the filename part of the mode-line buffer path." 747 :group 'doom-modeline-faces) 748 749 (defface doom-modeline-buffer-modified 750 '((t (:inherit (doom-modeline warning bold) :background unspecified))) 751 "Face used for the \\='unsaved\\=' symbol in the mode-line." 752 :group 'doom-modeline-faces) 753 754 (defface doom-modeline-buffer-major-mode 755 '((t (:inherit (doom-modeline-emphasis bold)))) 756 "Face used for the major-mode segment in the mode-line." 757 :group 'doom-modeline-faces) 758 759 (defface doom-modeline-buffer-minor-mode 760 '((t (:inherit (doom-modeline font-lock-doc-face) :weight normal :slant normal))) 761 "Face used for the minor-modes segment in the mode-line." 762 :group 'doom-modeline-faces) 763 764 (defface doom-modeline-project-parent-dir 765 '((t (:inherit (doom-modeline font-lock-comment-face bold)))) 766 "Face used for the project parent directory of the mode-line buffer path." 767 :group 'doom-modeline-faces) 768 769 (defface doom-modeline-project-dir 770 '((t (:inherit (doom-modeline font-lock-string-face bold)))) 771 "Face used for the project directory of the mode-line buffer path." 772 :group 'doom-modeline-faces) 773 774 (defface doom-modeline-project-root-dir 775 '((t (:inherit (doom-modeline-emphasis bold)))) 776 "Face used for the project part of the mode-line buffer path." 777 :group 'doom-modeline-faces) 778 779 (defface doom-modeline-panel 780 '((t (:inherit doom-modeline-highlight))) 781 "Face for \\='X out of Y\\=' segments. 782 This applies to `anzu', `evil-substitute', `iedit' etc." 783 :group 'doom-modeline-faces) 784 785 (defface doom-modeline-host 786 '((t (:inherit (doom-modeline italic)))) 787 "Face for remote hosts in the mode-line." 788 :group 'doom-modeline-faces) 789 790 (defface doom-modeline-input-method 791 '((t (:inherit (doom-modeline-emphasis)))) 792 "Face for input method in the mode-line." 793 :group 'doom-modeline-faces) 794 795 (defface doom-modeline-input-method-alt 796 '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) 797 "Alternative face for input method in the mode-line." 798 :group 'doom-modeline-faces) 799 800 (defface doom-modeline-debug 801 '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) 802 "Face for debug-level messages in the mode-line. Used by vcs, check, etc." 803 :group 'doom-modeline-faces) 804 805 (defface doom-modeline-info 806 '((t (:inherit (doom-modeline success)))) 807 "Face for info-level messages in the mode-line. Used by vcs, check, etc." 808 :group 'doom-modeline-faces) 809 810 (defface doom-modeline-warning 811 '((t (:inherit (doom-modeline warning)))) 812 "Face for warnings in the mode-line. Used by vcs, check, etc." 813 :group 'doom-modeline-faces) 814 815 (defface doom-modeline-urgent 816 '((t (:inherit (doom-modeline error)))) 817 "Face for errors in the mode-line. Used by vcs, check, etc." 818 :group 'doom-modeline-faces) 819 820 (defface doom-modeline-notification 821 '((t (:inherit doom-modeline-warning))) 822 "Face for notifications in the mode-line. Used by GitHub, mu4e, etc. 823 Also see the face `doom-modeline-unread-number'." 824 :group 'doom-modeline-faces) 825 826 (defface doom-modeline-unread-number 827 '((t (:inherit doom-modeline :slant italic))) 828 "Face for unread number in the mode-line. Used by GitHub, mu4e, etc." 829 :group 'doom-modeline-faces) 830 831 (defface doom-modeline-bar 832 '((t (:inherit doom-modeline-highlight))) 833 "The face used for the left-most bar in the mode-line of an active window." 834 :group 'doom-modeline-faces) 835 836 (defface doom-modeline-bar-inactive 837 `((t (:inherit doom-modeline))) 838 "The face used for the left-most bar in the mode-line of an inactive window." 839 :group 'doom-modeline-faces) 840 841 (defface doom-modeline-debug-visual 842 '((((background light)) :foreground "#D4843E" :inherit doom-modeline) 843 (((background dark)) :foreground "#915B2D" :inherit doom-modeline)) 844 "Face to use for the mode-line while debugging." 845 :group 'doom-modeline-faces) 846 847 (defface doom-modeline-evil-emacs-state 848 '((t (:inherit (doom-modeline font-lock-builtin-face)))) 849 "Face for the Emacs state tag in evil indicator." 850 :group 'doom-modeline-faces) 851 852 (defface doom-modeline-evil-insert-state 853 '((t (:inherit (doom-modeline font-lock-keyword-face)))) 854 "Face for the insert state tag in evil indicator." 855 :group 'doom-modeline-faces) 856 857 (defface doom-modeline-evil-motion-state 858 '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) 859 "Face for the motion state tag in evil indicator." 860 :group 'doom-modeline-faces) 861 862 (defface doom-modeline-evil-normal-state 863 '((t (:inherit doom-modeline-info))) 864 "Face for the normal state tag in evil indicator." 865 :group 'doom-modeline-faces) 866 867 (defface doom-modeline-evil-operator-state 868 '((t (:inherit (doom-modeline mode-line)))) 869 "Face for the operator state tag in evil indicator." 870 :group 'doom-modeline-faces) 871 872 (defface doom-modeline-evil-visual-state 873 '((t (:inherit doom-modeline-warning))) 874 "Face for the visual state tag in evil indicator." 875 :group 'doom-modeline-faces) 876 877 (defface doom-modeline-evil-replace-state 878 '((t (:inherit doom-modeline-urgent))) 879 "Face for the replace state tag in evil indicator." 880 :group 'doom-modeline-faces) 881 882 (defface doom-modeline-evil-user-state 883 '((t (:inherit doom-modeline-warning))) 884 "Face for the replace state tag in evil indicator." 885 :group 'doom-modeline-faces) 886 887 (defface doom-modeline-overwrite 888 '((t (:inherit doom-modeline-urgent))) 889 "Face for overwrite indicator." 890 :group 'doom-modeline-faces) 891 892 (defface doom-modeline-god 893 '((t (:inherit doom-modeline-info))) 894 "Face for god-mode indicator." 895 :group 'doom-modeline-faces) 896 897 (defface doom-modeline-ryo 898 '((t (:inherit doom-modeline-info))) 899 "Face for RYO indicator." 900 :group 'doom-modeline-faces) 901 902 (defface doom-modeline-fly-insert-state 903 '((t (:inherit (doom-modeline font-lock-keyword-face)))) 904 "Face for the insert state in xah-fly-keys indicator." 905 :group 'doom-modeline-faces) 906 907 (defface doom-modeline-fly-normal-state 908 '((t (:inherit doom-modeline-info))) 909 "Face for the normal state in xah-fly-keys indicator." 910 :group 'doom-modeline-faces) 911 912 (defface doom-modeline-boon-command-state 913 '((t (:inherit doom-modeline-info))) 914 "Face for the command state tag in boon indicator." 915 :group 'doom-modeline-faces) 916 917 (defface doom-modeline-boon-insert-state 918 '((t (:inherit (doom-modeline font-lock-keyword-face)))) 919 "Face for the insert state tag in boon indicator." 920 :group 'doom-modeline-faces) 921 922 (defface doom-modeline-boon-special-state 923 '((t (:inherit (doom-modeline font-lock-builtin-face)))) 924 "Face for the special state tag in boon indicator." 925 :group 'doom-modeline-faces) 926 927 (defface doom-modeline-boon-off-state 928 '((t (:inherit (doom-modeline mode-line)))) 929 "Face for the off state tag in boon indicator." 930 :group 'doom-modeline-faces) 931 932 (defface doom-modeline-meow-normal-state 933 '((t (:inherit doom-modeline-evil-normal-state))) 934 "Face for the normal state in meow-edit indicator." 935 :group 'doom-modeline-faces) 936 937 (defface doom-modeline-meow-insert-state 938 '((t (:inherit doom-modeline-evil-insert-state))) 939 "Face for the insert state in meow-edit indicator." 940 :group 'doom-modeline-faces) 941 942 (defface doom-modeline-meow-beacon-state 943 '((t (:inherit doom-modeline-evil-visual-state))) 944 "Face for the beacon state in meow-edit indicator." 945 :group 'doom-modeline-faces) 946 947 (defface doom-modeline-meow-motion-state 948 '((t (:inherit doom-modeline-evil-motion-state))) 949 "Face for the motion state in meow-edit indicator." 950 :group 'doom-modeline-faces) 951 952 (defface doom-modeline-meow-keypad-state 953 '((t (:inherit doom-modeline-evil-operator-state))) 954 "Face for the keypad state in meow-edit indicator." 955 :group 'doom-modeline-faces) 956 957 (defface doom-modeline-project-name 958 '((t (:inherit (doom-modeline font-lock-comment-face italic)))) 959 "Face for the project name." 960 :group 'doom-modeline-faces) 961 962 (defface doom-modeline-workspace-name 963 '((t (:inherit (doom-modeline-emphasis bold)))) 964 "Face for the workspace name." 965 :group 'doom-modeline-faces) 966 967 (defface doom-modeline-persp-name 968 '((t (:inherit (doom-modeline font-lock-comment-face italic)))) 969 "Face for the persp name." 970 :group 'doom-modeline-faces) 971 972 (defface doom-modeline-persp-buffer-not-in-persp 973 '((t (:inherit (doom-modeline font-lock-doc-face italic)))) 974 "Face for the buffers which are not in the persp." 975 :group 'doom-modeline-faces) 976 977 (defface doom-modeline-repl-success 978 '((t (:inherit doom-modeline-info))) 979 "Face for REPL success state." 980 :group 'doom-modeline-faces) 981 982 (defface doom-modeline-repl-warning 983 '((t (:inherit doom-modeline-warning))) 984 "Face for REPL warning state." 985 :group 'doom-modeline-faces) 986 987 (defface doom-modeline-lsp-success 988 '((t (:inherit doom-modeline-info))) 989 "Face for LSP success state." 990 :group 'doom-modeline-faces) 991 992 (defface doom-modeline-lsp-warning 993 '((t (:inherit doom-modeline-warning))) 994 "Face for LSP warning state." 995 :group 'doom-modeline-faces) 996 997 (defface doom-modeline-lsp-error 998 '((t (:inherit doom-modeline-urgent))) 999 "Face for LSP error state." 1000 :group 'doom-modeline-faces) 1001 1002 (defface doom-modeline-lsp-running 1003 '((t (:inherit (doom-modeline compilation-mode-line-run) :weight normal :slant normal))) 1004 "Face for LSP running state." 1005 :group 'doom-modeline-faces) 1006 1007 (defface doom-modeline-battery-charging 1008 '((t (:inherit doom-modeline-info))) 1009 "Face for battery charging status." 1010 :group 'doom-modeline-faces) 1011 1012 (defface doom-modeline-battery-full 1013 '((t (:inherit doom-modeline-info))) 1014 "Face for battery full status." 1015 :group 'doom-modeline-faces) 1016 1017 (defface doom-modeline-battery-normal 1018 '((t (:inherit (doom-modeline mode-line)))) 1019 "Face for battery normal status." 1020 :group 'doom-modeline-faces) 1021 1022 (defface doom-modeline-battery-warning 1023 '((t (:inherit doom-modeline-warning))) 1024 "Face for battery warning status." 1025 :group 'doom-modeline-faces) 1026 1027 (defface doom-modeline-battery-critical 1028 '((t (:inherit doom-modeline-urgent))) 1029 "Face for battery critical status." 1030 :group 'doom-modeline-faces) 1031 1032 (defface doom-modeline-battery-error 1033 '((t (:inherit doom-modeline-urgent))) 1034 "Face for battery error status." 1035 :group 'doom-modeline-faces) 1036 1037 (defface doom-modeline-buffer-timemachine 1038 '((t (:inherit doom-modeline-buffer-file :slant italic))) 1039 "Face for timemachine status." 1040 :group 'doom-modeline-faces) 1041 1042 (defface doom-modeline-time 1043 '((t (:inherit doom-modeline))) 1044 "Face for display time." 1045 :group 'doom-modeline-faces) 1046 1047 (defface doom-modeline-compilation 1048 '((t (:inherit doom-modeline-warning :slant italic :height 0.9))) 1049 "Face for compilation progress." 1050 :group 'doom-modeline-faces) 1051 1052 ;; 1053 ;; Externals 1054 ;; 1055 1056 (defvar mode-line-right-align-edge) 1057 1058 (declare-function doom-modeline-shorten-irc "doom-modeline-segments") 1059 (declare-function face-remap-remove-relative "face-remap") 1060 (declare-function ffip-project-root "ext:find-file-in-project") 1061 (declare-function project-root "project") 1062 (declare-function projectile-project-root "ext:projectile") 1063 1064 1065 ;; 1066 ;; Utilities 1067 ;; 1068 1069 (defun doom-modeline-add-font-lock () 1070 "Fontify `doom-modeline-def-*' statements." 1071 (font-lock-add-keywords 1072 'emacs-lisp-mode 1073 '(("(\\(doom-modeline-def-.+\\)\\_> +\\(.*?\\)\\_>" 1074 (1 font-lock-keyword-face) 1075 (2 font-lock-constant-face))))) 1076 (doom-modeline-add-font-lock) 1077 1078 (defun doom-modeline-add-imenu () 1079 "Add to `imenu' index." 1080 (add-to-list 1081 'imenu-generic-expression 1082 '("Modelines" 1083 "^\\s-*(\\(doom-modeline-def-modeline\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\s'\\|\\\\.\\)+\\)" 1084 2)) 1085 (add-to-list 1086 'imenu-generic-expression 1087 '("Segments" 1088 "^\\s-*(\\(doom-modeline-def-segment\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 1089 2)) 1090 (add-to-list 1091 'imenu-generic-expression 1092 '("Envs" 1093 "^\\s-*(\\(doom-modeline-def-env\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 1094 2))) 1095 1096 1097 ;; 1098 ;; Core helpers 1099 ;; 1100 1101 ;; FIXME #183: Force to calculate mode-line height 1102 ;; @see https://github.com/seagle0128/doom-modeline/issues/183 1103 ;; @see https://github.com/seagle0128/doom-modeline/issues/483 1104 (unless (>= emacs-major-version 29) 1105 (eval-and-compile 1106 (defun doom-modeline-redisplay (&rest _) 1107 "Call `redisplay' to trigger mode-line height calculations. 1108 1109 Certain functions, including e.g. `fit-window-to-buffer', base 1110 their size calculations on values which are incorrect if the 1111 mode-line has a height different from that of the `default' face 1112 and certain other calculations have not yet taken place for the 1113 window in question. 1114 1115 These calculations can be triggered by calling `redisplay' 1116 explicitly at the appropriate time and this functions purpose 1117 is to make it easier to do so. 1118 1119 This function is like `redisplay' with non-nil FORCE argument, 1120 but it will only trigger a redisplay when there is a non nil 1121 `mode-line-format' and the height of the mode-line is different 1122 from that of the `default' face. This function is intended to be 1123 used as an advice to window creation functions." 1124 (when (and (bound-and-true-p doom-modeline-mode) 1125 mode-line-format 1126 (/= (frame-char-height) (window-mode-line-height))) 1127 (redisplay t)))) 1128 (advice-add #'fit-window-to-buffer :before #'doom-modeline-redisplay)) 1129 1130 ;; For `flycheck-color-mode-line' 1131 (with-eval-after-load 'flycheck-color-mode-line 1132 (defvar flycheck-color-mode-line-face-to-color) 1133 (setq flycheck-color-mode-line-face-to-color 'doom-modeline)) 1134 1135 (defun doom-modeline-icon-displayable-p () 1136 "Return non-nil if icons are displayable." 1137 (and doom-modeline-icon (featurep 'nerd-icons))) 1138 1139 (defun doom-modeline-mwheel-available-p () 1140 "Whether mouse wheel is available." 1141 (and (featurep 'mwheel) (bound-and-true-p mouse-wheel-mode))) 1142 1143 ;; Keep `doom-modeline-current-window' up-to-date 1144 (defun doom-modeline--selected-window () 1145 "Get the selected window." 1146 (frame-selected-window)) 1147 1148 (defvar doom-modeline-current-window (doom-modeline--selected-window) 1149 "Current window.") 1150 1151 (defun doom-modeline--active () 1152 "Whether is an active window." 1153 (unless (and (bound-and-true-p mini-frame-frame) 1154 (and (frame-live-p mini-frame-frame) 1155 (frame-visible-p mini-frame-frame))) 1156 (and doom-modeline-current-window 1157 (eq (doom-modeline--selected-window) doom-modeline-current-window)))) 1158 1159 (defvar-local doom-modeline--limited-width-p nil) 1160 1161 (defun doom-modeline--segment-visible (name) 1162 "Whether the segment NAME should be displayed." 1163 (and 1164 (or (doom-modeline--active) 1165 (member name doom-modeline-always-visible-segments)) 1166 (not doom-modeline--limited-width-p))) 1167 1168 (defun doom-modeline-set-selected-window (&rest _) 1169 "Set `doom-modeline-current-window' appropriately." 1170 (let ((win (doom-modeline--selected-window))) 1171 (setq doom-modeline-current-window 1172 (if (minibuffer-window-active-p win) 1173 (minibuffer-selected-window) 1174 win)))) 1175 1176 (defun doom-modeline-unset-selected-window () 1177 "Unset `doom-modeline-current-window' appropriately." 1178 (setq doom-modeline-current-window nil)) 1179 1180 (add-hook 'pre-redisplay-functions #'doom-modeline-set-selected-window) 1181 1182 ;; Ensure modeline is inactive when Emacs is unfocused 1183 (defvar doom-modeline--remap-faces '(mode-line 1184 mode-line-active 1185 mode-line-emphasis 1186 mode-line-highlight 1187 mode-line-buffer-id 1188 doom-modeline 1189 solaire-mode-line-face 1190 solaire-mode-line-active-face 1191 paradox-mode-line-face 1192 flycheck-color-mode-line-error-face 1193 flycheck-color-mode-line-warning-face 1194 flycheck-color-mode-line-info-face 1195 flycheck-color-mode-line-success-face)) 1196 1197 (defvar doom-modeline--remap-face-cookie-alist nil) 1198 (defun doom-modeline-focus () 1199 "Focus mode-line." 1200 (mapc #'face-remap-remove-relative doom-modeline--remap-face-cookie-alist)) 1201 1202 (defun doom-modeline-unfocus () 1203 "Unfocus mode-line." 1204 (dolist (face doom-modeline--remap-faces) 1205 (add-to-list 'doom-modeline--remap-face-cookie-alist 1206 (face-remap-add-relative face 'mode-line-inactive)))) 1207 1208 (with-no-warnings 1209 (if (boundp 'after-focus-change-function) 1210 (progn 1211 (defun doom-modeline-focus-change (&rest _) 1212 (if (frame-focus-state (frame-parent)) 1213 (progn 1214 (doom-modeline-focus) 1215 ;; HACK: pulse after focusing in the frame to refresh the buffer name. 1216 ;; @see https://github.com/seagle0128/doom-modeline/issues/591 1217 (when (fboundp 'pulse-momentary-highlight-region) 1218 (pulse-momentary-highlight-region 0 0))) 1219 (doom-modeline-unfocus))) 1220 (advice-add #'handle-switch-frame :after #'doom-modeline-focus-change) 1221 (add-function :after after-focus-change-function #'doom-modeline-focus-change)) 1222 (progn 1223 (add-hook 'focus-in-hook #'doom-modeline-focus) 1224 (add-hook 'focus-out-hook #'doom-modeline-unfocus)))) 1225 1226 1227 ;; 1228 ;; Core 1229 ;; 1230 1231 (defvar doom-modeline-fn-alist ()) 1232 (defvar doom-modeline-var-alist ()) 1233 1234 (defmacro doom-modeline-def-segment (name &rest body) 1235 "Define a modeline segment NAME with BODY and byte compiles it." 1236 (declare (indent defun) (doc-string 2)) 1237 (let ((sym (intern (format "doom-modeline-segment--%s" name))) 1238 (docstring (if (stringp (car body)) 1239 (pop body) 1240 (format "%s modeline segment" name)))) 1241 (cond ((and (symbolp (car body)) 1242 (not (cdr body))) 1243 `(add-to-list 'doom-modeline-var-alist (cons ',name ',(car body)))) 1244 (t 1245 `(progn 1246 (defun ,sym () ,docstring ,@body) 1247 (add-to-list 'doom-modeline-fn-alist (cons ',name ',sym)) 1248 ,(unless (bound-and-true-p byte-compile-current-file) 1249 `(let (byte-compile-warnings) 1250 (unless (and (fboundp 'subr-native-elisp-p) 1251 (subr-native-elisp-p (symbol-function #',sym))) 1252 (byte-compile #',sym))))))))) 1253 1254 (defun doom-modeline--prepare-segments (segments) 1255 "Prepare mode-line `SEGMENTS'." 1256 (let (forms it) 1257 (dolist (seg segments) 1258 (cond ((stringp seg) 1259 (push seg forms)) 1260 ((symbolp seg) 1261 (cond ((setq it (alist-get seg doom-modeline-fn-alist)) 1262 (push (list :eval (list it)) forms)) 1263 ((setq it (alist-get seg doom-modeline-var-alist)) 1264 (push it forms)) 1265 ((error "%s is not a defined segment" seg)))) 1266 ((error "%s is not a valid segment" seg)))) 1267 (nreverse forms))) 1268 1269 (defun doom-modeline-def-modeline (name lhs &optional rhs) 1270 "Define a modeline format and byte-compiles it. 1271 NAME is a symbol to identify it (used by `doom-modeline' for retrieval). 1272 LHS and RHS are lists of symbols of modeline segments defined with 1273 `doom-modeline-def-segment'. 1274 1275 Example: 1276 (doom-modeline-def-modeline \\='minimal 1277 \\='(bar matches \" \" buffer-info) 1278 \\='(media-info major-mode)) 1279 (doom-modeline-set-modeline \\='minimal t)" 1280 (let ((sym (intern (format "doom-modeline-format--%s" name))) 1281 (lhs-forms (doom-modeline--prepare-segments lhs)) 1282 (rhs-forms (doom-modeline--prepare-segments rhs))) 1283 (defalias sym 1284 (lambda () 1285 (list lhs-forms 1286 (let* ((rhs-str (format-mode-line (cons "" rhs-forms))) 1287 (rhs-width (progn 1288 (add-face-text-property 1289 0 (length rhs-str) 'mode-line t rhs-str) 1290 (doom-modeline-string-pixel-width rhs-str)))) 1291 (propertize 1292 " " 1293 'face (doom-modeline-face) 1294 'display 1295 ;; Backport from `mode-line-right-align-edge' in 30 1296 (if (and (display-graphic-p) 1297 (not (eq mode-line-right-align-edge 'window))) 1298 `(space :align-to (- ,mode-line-right-align-edge 1299 (,rhs-width))) 1300 `(space :align-to (,(- (window-pixel-width) 1301 (window-scroll-bar-width) 1302 (window-right-divider-width) 1303 (* (or (cdr (window-margins)) 1) 1304 (frame-char-width)) 1305 (pcase mode-line-right-align-edge 1306 ('right-margin 1307 (or (cdr (window-margins)) 0)) 1308 ('right-fringe 1309 (or (cadr (window-fringes)) 0)) 1310 (_ 0)) 1311 rhs-width)))))) 1312 rhs-forms)) 1313 (concat "Modeline:\n" 1314 (format " %s\n %s" 1315 (prin1-to-string lhs) 1316 (prin1-to-string rhs)))))) 1317 (put 'doom-modeline-def-modeline 'lisp-indent-function 'defun) 1318 1319 (defun doom-modeline (key) 1320 "Return a mode-line configuration associated with KEY (a symbol). 1321 Throws an error if it doesn't exist." 1322 (let ((fn (intern-soft (format "doom-modeline-format--%s" key)))) 1323 (when (functionp fn) 1324 `(:eval (,fn))))) 1325 1326 (defun doom-modeline-set-modeline (key &optional default) 1327 "Set the modeline format. Does nothing if the modeline KEY doesn't exist. 1328 If DEFAULT is non-nil, set the default mode-line for all buffers." 1329 (when-let* ((modeline (doom-modeline key))) 1330 (setf (if default 1331 (default-value 'mode-line-format) 1332 mode-line-format) 1333 (list "%e" modeline)))) 1334 1335 ;; 1336 ;; Helpers 1337 ;; 1338 1339 (defconst doom-modeline-ellipsis 1340 (if (char-displayable-p ?…) "…" "...") 1341 "Ellipsis.") 1342 1343 (defsubst doom-modeline-spc () 1344 "Whitespace." 1345 (propertize " " 'face (doom-modeline-face))) 1346 1347 (defsubst doom-modeline-wspc () 1348 "Wide Whitespace." 1349 (propertize " " 'face (doom-modeline-face))) 1350 1351 (defsubst doom-modeline-vspc () 1352 "Thin whitespace." 1353 (propertize " " 1354 'face (doom-modeline-face) 1355 'display '((space :relative-width 0.5)))) 1356 1357 (defun doom-modeline-face (&optional face inactive-face) 1358 "Display FACE in active window, and INACTIVE-FACE in inactive window. 1359 IF FACE is nil, `mode-line' face will be used. 1360 If INACTIVE-FACE is nil, `mode-line-inactive' face will be used." 1361 (if (doom-modeline--active) 1362 (or (and (facep face) `(:inherit (doom-modeline ,face))) 1363 (and (facep 'mode-line-active) '(:inherit (doom-modeline mode-line-active))) 1364 '(:inherit (doom-modeline mode-line))) 1365 (or (and (facep inactive-face) `(:inherit (doom-modeline ,inactive-face))) 1366 '(:inherit (doom-modeline mode-line-inactive))))) 1367 1368 (defun doom-modeline-string-pixel-width (str) 1369 "Return the width of STR in pixels." 1370 (if (fboundp 'string-pixel-width) 1371 (string-pixel-width str) 1372 (* (string-width str) (window-font-width nil 'mode-line) 1373 (if (display-graphic-p) 1.05 1.0)))) 1374 1375 (defun doom-modeline--font-height () 1376 "Calculate the actual char height of the mode-line." 1377 (let ((height (face-attribute 'mode-line :height)) 1378 (char-height (window-font-height nil 'mode-line))) 1379 (round 1380 (* 1.0 (cond ((integerp height) (/ height 10)) 1381 ((floatp height) (* height char-height)) 1382 (t char-height)))))) 1383 1384 (defun doom-modeline--original-value (sym) 1385 "Return the original value for SYM, if any. 1386 1387 If SYM has an original value, return it in a list. Return nil 1388 otherwise." 1389 (let* ((orig-val-expr (get sym 'standard-value))) 1390 (when (consp orig-val-expr) 1391 (ignore-errors 1392 (list 1393 (eval (car orig-val-expr))))))) 1394 1395 (defun doom-modeline-add-variable-watcher (symbol watch-function) 1396 "Cause WATCH-FUNCTION to be called when SYMBOL is set if possible. 1397 1398 See docs of `add-variable-watcher'." 1399 (when (fboundp 'add-variable-watcher) 1400 (add-variable-watcher symbol watch-function))) 1401 1402 (defun doom-modeline-propertize-icon (icon &optional face) 1403 "Propertize the ICON with the specified FACE. 1404 1405 The face should be the first attribute, or the font family may be overridden. 1406 So convert the face \":family XXX :height XXX :inherit XXX\" to 1407 \":inherit XXX :family XXX :height XXX\". 1408 See https://github.com/seagle0128/doom-modeline/issues/301." 1409 (when icon 1410 (if (doom-modeline-icon-displayable-p) 1411 (when-let* ((props (get-text-property 0 'face icon))) 1412 (when (listp props) 1413 (cl-destructuring-bind (&key family height inherit &allow-other-keys) props 1414 (propertize icon 'face `(:inherit (doom-modeline ,(or face inherit props)) 1415 :family ,(or family "") 1416 :height ,(or height 1.0)))))) 1417 (propertize icon 'face `(:inherit (doom-modeline ,face)))))) 1418 1419 (defun doom-modeline-icon (icon-set icon-name unicode text &rest args) 1420 "Display icon of ICON-NAME with ARGS in mode-line. 1421 1422 ICON-SET includes `ipsicon', `octicon', `pomicon', `powerline', `faicon', 1423 `wicon', `sucicon', `devicon', `codicon', `flicon' and `mdicon', etc. 1424 UNICODE is the unicode char fallback. TEXT is the ASCII char fallback. 1425 ARGS is same as `nerd-icons-octicon' and others." 1426 (let ((face `(:inherit (doom-modeline 1427 ,(or (plist-get args :face) 'mode-line))))) 1428 (cond 1429 ;; Icon 1430 ((and (doom-modeline-icon-displayable-p) 1431 icon-name 1432 (not (string-empty-p icon-name))) 1433 (if-let* ((func (nerd-icons--function-name icon-set)) 1434 (icon (and (fboundp func) 1435 (apply func icon-name args)))) 1436 (doom-modeline-propertize-icon icon face) 1437 "")) 1438 ;; Unicode fallback 1439 ((and doom-modeline-unicode-fallback 1440 unicode 1441 (not (string-empty-p unicode)) 1442 (char-displayable-p (string-to-char unicode))) 1443 (propertize unicode 'face face)) 1444 ;; ASCII text 1445 (text 1446 (propertize text 'face face)) 1447 ;; Fallback 1448 (t "")))) 1449 1450 (defun doom-modeline-icon-for-buffer () 1451 "Get the formatted icon for the current buffer." 1452 (nerd-icons-icon-for-buffer)) 1453 1454 (defun doom-modeline-display-icon (icon) 1455 "Display ICON in mode-line." 1456 (if (doom-modeline--active) 1457 icon 1458 (doom-modeline-propertize-icon icon 'mode-line-inactive))) 1459 1460 (defun doom-modeline-display-text (text) 1461 "Display TEXT in mode-line." 1462 (if (doom-modeline--active) 1463 text 1464 (propertize text 'face `(:inherit (mode-line-inactive 1465 ,(get-text-property 0 'face text)))))) 1466 1467 (defun doom-modeline-vcs-name () 1468 "Display the vcs name." 1469 (and vc-mode (cadr (split-string (string-trim vc-mode) "^[A-Z]+[-:]+")))) 1470 1471 (defun doom-modeline--create-bar-image (face width height) 1472 "Create the bar image. 1473 1474 Use FACE for the bar, WIDTH and HEIGHT are the image size in pixels." 1475 (when (and (image-type-available-p 'pbm) 1476 (numberp width) (> width 0) 1477 (numberp height) (> height 0)) 1478 (propertize 1479 " " 'display 1480 (let ((color (or (face-background face nil t) "None"))) 1481 (ignore-errors 1482 (create-image 1483 (concat (format "P1\n%i %i\n" width height) 1484 (make-string (* width height) ?1) 1485 "\n") 1486 'pbm t :scale 1 :foreground color :ascent 'center)))))) 1487 1488 (defun doom-modeline--create-hud-image 1489 (face1 face2 width height top-margin bottom-margin) 1490 "Create the hud image. 1491 1492 Use FACE1 for the bar, FACE2 for the background. 1493 WIDTH and HEIGHT are the image size in pixels. 1494 TOP-MARGIN and BOTTOM-MARGIN are the size of the margin above and below the bar, 1495 respectively." 1496 (when (and (display-graphic-p) 1497 (image-type-available-p 'pbm) 1498 (numberp width) (> width 0) 1499 (numberp height) (> height 0)) 1500 (let ((min-height (min height doom-modeline-hud-min-height))) 1501 (unless (> (- height top-margin bottom-margin) min-height) 1502 (let ((margin (- height min-height))) 1503 (setq top-margin (/ (* margin top-margin) (+ top-margin bottom-margin)) 1504 bottom-margin (- margin top-margin))))) 1505 (propertize 1506 " " 'display 1507 (let ((color1 (or (face-background face1 nil t) "None")) 1508 (color2 (or (face-background face2 nil t) "None"))) 1509 (create-image 1510 (concat 1511 (format "P1\n%i %i\n" width height) 1512 (make-string (* top-margin width) ?0) 1513 (make-string (* (- height top-margin bottom-margin) width) ?1) 1514 (make-string (* bottom-margin width) ?0) 1515 "\n") 1516 'pbm t :foreground color1 :background color2 :ascent 'center))))) 1517 1518 ;; Check whether `window-total-width' is smaller than the limit 1519 (defun doom-modeline-window-size-change-function (&rest _) 1520 "Function for `window-size-change-functions'." 1521 (setq doom-modeline--limited-width-p 1522 (cond 1523 ((integerp doom-modeline-window-width-limit) 1524 (<= (window-total-width) doom-modeline-window-width-limit)) 1525 ((floatp doom-modeline-window-width-limit) 1526 (<= (/ (window-total-width) (frame-width) 1.0) 1527 doom-modeline-window-width-limit))))) 1528 1529 (add-hook 'after-revert-hook #'doom-modeline-window-size-change-function) 1530 (add-hook 'buffer-list-update-hook #'doom-modeline-window-size-change-function) 1531 (add-hook 'window-size-change-functions #'doom-modeline-window-size-change-function) 1532 1533 (defvar-local doom-modeline--project-root nil) 1534 (defun doom-modeline--project-root () 1535 "Get the path to the project root. 1536 Return nil if no project was found." 1537 (or doom-modeline--project-root 1538 (setq doom-modeline--project-root 1539 (cond 1540 ((and (memq doom-modeline-project-detection '(auto ffip)) 1541 (fboundp 'ffip-project-root)) 1542 (let ((inhibit-message t)) 1543 (ffip-project-root))) 1544 ((and (memq doom-modeline-project-detection '(auto projectile)) 1545 (bound-and-true-p projectile-mode)) 1546 (projectile-project-root)) 1547 ((and (memq doom-modeline-project-detection '(auto project)) 1548 (fboundp 'project-current)) 1549 (when-let* ((project (project-current))) 1550 (expand-file-name 1551 (if (fboundp 'project-root) 1552 (project-root project) 1553 (car (with-no-warnings 1554 (project-roots project))))))))))) 1555 1556 (doom-modeline-add-variable-watcher 1557 'doom-modeline-project-detection 1558 (lambda (_sym val op _where) 1559 (when (eq op 'set) 1560 (setq doom-modeline-project-detection val) 1561 (dolist (buf (buffer-list)) 1562 (with-current-buffer buf 1563 (setq doom-modeline--project-root nil) 1564 (and buffer-file-name (revert-buffer t t))))))) 1565 1566 (defun doom-modeline-project-p () 1567 "Check if the file is in a project." 1568 (doom-modeline--project-root)) 1569 1570 (defun doom-modeline-project-root () 1571 "Get the path to the root of your project. 1572 Return `default-directory' if no project was found." 1573 (abbreviate-file-name 1574 (or (doom-modeline--project-root) default-directory))) 1575 1576 (defun doom-modeline--format-buffer-file-name () 1577 "Get and format the buffer file name." 1578 (let ((buffer-file-name (file-local-name 1579 (or (buffer-file-name (buffer-base-buffer)) "")))) 1580 (or (and doom-modeline-buffer-file-name-function 1581 (funcall doom-modeline-buffer-file-name-function buffer-file-name)) 1582 buffer-file-name))) 1583 1584 (defun doom-modeline--format-buffer-file-truename (b-f-n) 1585 "Get and format buffer file truename via B-F-N." 1586 (let ((buffer-file-truename (file-local-name 1587 (or (file-truename b-f-n) "")))) 1588 (or (and doom-modeline-buffer-file-truename-function 1589 (funcall doom-modeline-buffer-file-truename-function buffer-file-truename)) 1590 buffer-file-truename))) 1591 1592 (defun doom-modeline-buffer-file-name () 1593 "Propertize file name based on `doom-modeline-buffer-file-name-style'." 1594 (let* ((buffer-file-name (doom-modeline--format-buffer-file-name)) 1595 (buffer-file-truename (doom-modeline--format-buffer-file-truename buffer-file-name)) 1596 (file-name 1597 (pcase doom-modeline-buffer-file-name-style 1598 ('auto 1599 (if (doom-modeline-project-p) 1600 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide) 1601 (propertize "%b" 'face 'doom-modeline-buffer-file))) 1602 ('truncate-upto-project 1603 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink)) 1604 ('truncate-from-project 1605 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil 'shrink)) 1606 ('truncate-with-project 1607 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide)) 1608 ('truncate-except-project 1609 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink)) 1610 ('truncate-upto-root 1611 (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename)) 1612 ('truncate-all 1613 (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename t)) 1614 ('truncate-nil 1615 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename)) 1616 ('relative-to-project 1617 (doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename)) 1618 ('relative-from-project 1619 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide)) 1620 ('file-name 1621 (propertize (file-name-nondirectory buffer-file-name) 1622 'face 'doom-modeline-buffer-file)) 1623 ('file-name-with-project 1624 (format "%s|%s" 1625 (propertize (file-name-nondirectory 1626 (directory-file-name (file-local-name (doom-modeline-project-root)))) 1627 'face 'doom-modeline-project-dir) 1628 (propertize (file-name-nondirectory buffer-file-name) 1629 'face 'doom-modeline-buffer-file))) 1630 ((or 'buffer-name _) 1631 (propertize "%b" 'face 'doom-modeline-buffer-file))))) 1632 (propertize (if (string-empty-p file-name) 1633 (propertize "%b" 'face 'doom-modeline-buffer-file) 1634 file-name) 1635 'mouse-face 'mode-line-highlight 1636 'help-echo (concat buffer-file-truename 1637 (unless (string= (file-name-nondirectory buffer-file-truename) 1638 (buffer-name)) 1639 (concat "\n" (buffer-name))) 1640 "\nmouse-1: Previous buffer\nmouse-3: Next buffer") 1641 'local-map mode-line-buffer-identification-keymap))) 1642 1643 (defun doom-modeline--buffer-file-name-truncate (file-path true-file-path &optional truncate-tail) 1644 "Propertize file name that truncates every dir along path. 1645 1646 If TRUNCATE-TAIL is t also truncate the parent directory of the file." 1647 (let ((dirs (shrink-path-prompt (file-name-directory true-file-path)))) 1648 (if (null dirs) 1649 (propertize "%b" 'face 'doom-modeline-buffer-file) 1650 (let ((dirname (car dirs)) 1651 (basename (cdr dirs))) 1652 (concat (propertize (concat dirname 1653 (if truncate-tail (substring basename 0 1) basename) 1654 "/") 1655 'face 'doom-modeline-project-root-dir) 1656 (propertize (file-name-nondirectory file-path) 1657 'face 'doom-modeline-buffer-file)))))) 1658 1659 (defun doom-modeline--buffer-file-name-relative (_file-path true-file-path &optional include-project) 1660 "Propertize file name showing directories relative to project's root only. 1661 1662 If INCLUDE-PROJECT is non-nil, the project path will be included." 1663 (let ((root (file-local-name (doom-modeline-project-root)))) 1664 (if (null root) 1665 (propertize "%b" 'face 'doom-modeline-buffer-file) 1666 (let ((relative-dirs (file-relative-name (file-name-directory true-file-path) 1667 (if include-project (concat root "../") root)))) 1668 (and (equal "./" relative-dirs) (setq relative-dirs "")) 1669 (concat (propertize relative-dirs 'face 'doom-modeline-buffer-path) 1670 (propertize (file-name-nondirectory true-file-path) 1671 'face 'doom-modeline-buffer-file)))))) 1672 1673 (defun doom-modeline--buffer-file-name (file-path 1674 true-file-path 1675 &optional 1676 truncate-project-root-parent 1677 truncate-project-relative-path 1678 hide-project-root-parent) 1679 "Propertize buffer name given by FILE-PATH or TRUE-FILE-PATH. 1680 1681 If TRUNCATE-PROJECT-ROOT-PARENT is non-nil will be saved by truncating project 1682 root parent down fish-shell style. 1683 1684 Example: 1685 ~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el 1686 1687 If TRUNCATE-PROJECT-RELATIVE-PATH is non-nil will be saved by truncating project 1688 relative path down fish-shell style. 1689 1690 Example: 1691 ~/Projects/FOSS/emacs/lisp/comint.el => ~/Projects/FOSS/emacs/l/comint.el 1692 1693 If HIDE-PROJECT-ROOT-PARENT is non-nil will hide project root parent. 1694 1695 Example: 1696 ~/Projects/FOSS/emacs/lisp/comint.el => emacs/lisp/comint.el" 1697 (let ((project-root (file-local-name (doom-modeline-project-root)))) 1698 (concat 1699 ;; Project root parent 1700 (unless hide-project-root-parent 1701 (when-let* ((root-path-parent 1702 (file-name-directory (directory-file-name project-root)))) 1703 (propertize 1704 (if (and truncate-project-root-parent 1705 (not (string-empty-p root-path-parent)) 1706 (not (string= root-path-parent "/"))) 1707 (shrink-path--dirs-internal root-path-parent t) 1708 (abbreviate-file-name root-path-parent)) 1709 'face 'doom-modeline-project-parent-dir))) 1710 ;; Project directory 1711 (propertize 1712 (concat (file-name-nondirectory (directory-file-name project-root)) "/") 1713 'face 'doom-modeline-project-dir) 1714 ;; relative path 1715 (propertize 1716 (when-let* ((relative-path (file-relative-name 1717 (or (file-name-directory 1718 (if doom-modeline-buffer-file-true-name 1719 true-file-path file-path)) 1720 "./") 1721 project-root))) 1722 (if (string= relative-path "./") 1723 "" 1724 (if truncate-project-relative-path 1725 (substring (shrink-path--dirs-internal relative-path t) 1) 1726 relative-path))) 1727 'face 'doom-modeline-buffer-path) 1728 ;; File name 1729 (propertize (file-name-nondirectory file-path) 1730 'face 'doom-modeline-buffer-file)))) 1731 1732 (provide 'doom-modeline-core) 1733 1734 ;;; doom-modeline-core.el ends here