doom-modeline-core.el (62752B)
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-workspace-name t 513 "Whether display the workspace name. 514 515 Non-nil to display in the mode-line." 516 :type 'boolean 517 :group 'doom-modeline) 518 519 (defcustom doom-modeline-persp-name t 520 "Whether display the perspective name. 521 522 Non-nil to display in the mode-line." 523 :type 'boolean 524 :group 'doom-modeline) 525 526 (defcustom doom-modeline-display-default-persp-name nil 527 "If non nil the default perspective name is displayed in the mode-line." 528 :type 'boolean 529 :group 'doom-modeline) 530 531 (defcustom doom-modeline-persp-icon t 532 "If non nil the perspective name is displayed alongside a folder icon." 533 :type 'boolean 534 :group 'doom-modeline) 535 536 (defcustom doom-modeline-repl t 537 "Whether display the `repl' state. 538 539 Non-nil to display in the mode-line." 540 :type 'boolean 541 :group 'doom-modeline) 542 543 (defcustom doom-modeline-lsp t 544 "Whether display the `lsp' state. 545 546 Non-nil to display in the mode-line." 547 :type 'boolean 548 :group 'doom-modeline) 549 550 (defcustom doom-modeline-github nil 551 "Whether display the GitHub notifications. 552 553 It requires `ghub' and `async' packages. Additionally, your GitHub personal 554 access token must have `notifications' permissions. 555 556 If you use `pass' to manage your secrets, you also need to add this hook: 557 (add-hook \\='doom-modeline-before-github-fetch-notification-hook 558 #\\='auth-source-pass-enable)" 559 :type 'boolean 560 :group 'doom-modeline) 561 562 (defcustom doom-modeline-github-interval 1800 ; (* 30 60) 563 "The interval of checking GitHub." 564 :type 'integer 565 :group 'doom-modeline) 566 567 (defcustom doom-modeline-env-version t 568 "Whether display the environment version." 569 :type 'boolean 570 :group 'doom-modeline) 571 572 (defcustom doom-modeline-modal t 573 "Whether display the modal state. 574 575 Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." 576 :type 'boolean 577 :group 'doom-modeline) 578 579 (defcustom doom-modeline-modal-icon t 580 "Whether display the modal state icon. 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-modern-icon t 587 "Whether display the modern icons for modals." 588 :type 'boolean 589 :group 'doom-modeline) 590 591 (defcustom doom-modeline-always-show-macro-register nil 592 "When non-nil, always show the register name when recording an evil macro." 593 :type 'boolean 594 :group 'doom-modeline) 595 596 (defcustom doom-modeline-mu4e nil 597 "Whether display the mu4e notifications. 598 599 It requires `mu4e-alert' package." 600 :type 'boolean 601 :group 'doom-modeline) 602 603 (defcustom doom-modeline-gnus nil 604 "Whether to display notifications from gnus. 605 606 It requires `gnus' to be setup" 607 :type 'boolean 608 :group 'doom-modeline) 609 610 (defcustom doom-modeline-gnus-timer 2 611 "The wait time in minutes before gnus fetches mail. 612 613 If nil, don't set up a hook." 614 :type 'integer 615 :group 'doom-modeline) 616 617 (defcustom doom-modeline-gnus-idle nil 618 "Whether to wait an idle time to scan for news. 619 620 When t, sets `doom-modeline-gnus-timer' as an idle timer. If a 621 number, Emacs must have been idle this given time, checked after 622 reach the defined timer, to fetch news. The time step can be 623 configured in `gnus-demon-timestep'." 624 :type '(choice 625 (boolean :tag "Set `doom-modeline-gnus-timer' as an idle timer") 626 (number :tag "Set a custom idle timer")) 627 :group 'doom-modeline) 628 629 (defcustom doom-modeline-gnus-excluded-groups nil 630 "A list of groups to be excluded from the unread count. 631 Groups' names list in `gnus-newsrc-alist'`" 632 :type '(repeat string) 633 :group 'doom-modeline) 634 635 (defcustom doom-modeline-irc t 636 "Whether display the irc notifications. 637 638 It requires either `circe' , `erc' or `rcirc' package." 639 :type 'boolean 640 :group 'doom-modeline) 641 642 (defcustom doom-modeline-irc-buffers nil 643 "Whether display the unread irc buffers." 644 :type 'boolean 645 :group 'doom-modeline) 646 647 (defcustom doom-modeline-irc-stylize #'doom-modeline-shorten-irc 648 "Which function to call to stylize IRC buffer names. 649 650 Buffer names are stylized using the selected `function'. 651 By default buffer names are shortened, you may want to disable or call 652 your own function. 653 The function must accept `buffer-name' and return `shortened-name'." 654 :type '(radio (function-item :tag "Shorten" 655 :format "%t: %v\n %h" 656 doom-modeline-shorten-irc) 657 (function-item 658 :tag "Leave unchanged" 659 :format "%t: %v\n" 660 identity) 661 (function 662 :tag "Other function")) 663 :group 'doom-modeline) 664 665 (defcustom doom-modeline-battery t 666 "Whether display the battery status. 667 668 It respects `display-battery-mode'." 669 :type 'boolean 670 :group 'doom-modeline) 671 672 (defcustom doom-modeline-time t 673 "Whether display the time. 674 675 It respects `display-time-mode'." 676 :type 'boolean 677 :group 'doom-modeline) 678 679 (defcustom doom-modeline-display-misc-in-all-mode-lines t 680 "Whether display the misc segment on all mode lines. 681 682 If nil, display only if the mode line is active." 683 :type 'boolean 684 :group 'doom-modeline) 685 686 (defcustom doom-modeline-always-visible-segments nil 687 "A list of segments that should be visible even in inactive windows." 688 :type '(repeat symbol) 689 :group 'doom-modeline) 690 691 (defcustom doom-modeline-buffer-file-name-function #'identity 692 "The function to handle variable `buffer-file-name'." 693 :type 'function 694 :group 'doom-modeline) 695 696 (defcustom doom-modeline-buffer-file-truename-function #'identity 697 "The function to handle `buffer-file-truename'." 698 :type 'function 699 :group 'doom-modeline) 700 701 (defcustom doom-modeline-k8s-show-namespace t 702 "Whether to show the current Kubernetes context's default namespace." 703 :type 'boolean 704 :group 'doom-modeline) 705 706 707 ;; 708 ;; Faces 709 ;; 710 711 (defgroup doom-modeline-faces nil 712 "The faces of `doom-modeline'." 713 :group 'doom-modeline 714 :group 'faces 715 :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) 716 717 (defface doom-modeline 718 '((t ())) 719 "Default face." 720 :group 'doom-modeline-faces) 721 722 (defface doom-modeline-emphasis 723 '((t (:inherit (doom-modeline mode-line-emphasis)))) 724 "Face used for emphasis." 725 :group 'doom-modeline-faces) 726 727 (defface doom-modeline-highlight 728 '((t (:inherit (doom-modeline mode-line-highlight)))) 729 "Face used for highlighting." 730 :group 'doom-modeline-faces) 731 732 (defface doom-modeline-buffer-path 733 '((t (:inherit (doom-modeline-emphasis bold)))) 734 "Face used for the dirname part of the buffer path." 735 :group 'doom-modeline-faces) 736 737 (defface doom-modeline-buffer-file 738 '((t (:inherit (doom-modeline mode-line-buffer-id bold)))) 739 "Face used for the filename part of the mode-line buffer path." 740 :group 'doom-modeline-faces) 741 742 (defface doom-modeline-buffer-modified 743 '((t (:inherit (doom-modeline warning bold) :background unspecified))) 744 "Face used for the \\='unsaved\\=' symbol in the mode-line." 745 :group 'doom-modeline-faces) 746 747 (defface doom-modeline-buffer-major-mode 748 '((t (:inherit (doom-modeline-emphasis bold)))) 749 "Face used for the major-mode segment in the mode-line." 750 :group 'doom-modeline-faces) 751 752 (defface doom-modeline-buffer-minor-mode 753 '((t (:inherit (doom-modeline font-lock-doc-face) :weight normal :slant normal))) 754 "Face used for the minor-modes segment in the mode-line." 755 :group 'doom-modeline-faces) 756 757 (defface doom-modeline-project-parent-dir 758 '((t (:inherit (doom-modeline font-lock-comment-face bold)))) 759 "Face used for the project parent directory of the mode-line buffer path." 760 :group 'doom-modeline-faces) 761 762 (defface doom-modeline-project-dir 763 '((t (:inherit (doom-modeline font-lock-string-face bold)))) 764 "Face used for the project directory of the mode-line buffer path." 765 :group 'doom-modeline-faces) 766 767 (defface doom-modeline-project-root-dir 768 '((t (:inherit (doom-modeline-emphasis bold)))) 769 "Face used for the project part of the mode-line buffer path." 770 :group 'doom-modeline-faces) 771 772 (defface doom-modeline-panel 773 '((t (:inherit doom-modeline-highlight))) 774 "Face for \\='X out of Y\\=' segments. 775 This applies to `anzu', `evil-substitute', `iedit' etc." 776 :group 'doom-modeline-faces) 777 778 (defface doom-modeline-host 779 '((t (:inherit (doom-modeline italic)))) 780 "Face for remote hosts in the mode-line." 781 :group 'doom-modeline-faces) 782 783 (defface doom-modeline-input-method 784 '((t (:inherit (doom-modeline-emphasis)))) 785 "Face for input method in the mode-line." 786 :group 'doom-modeline-faces) 787 788 (defface doom-modeline-input-method-alt 789 '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) 790 "Alternative face for input method in the mode-line." 791 :group 'doom-modeline-faces) 792 793 (defface doom-modeline-debug 794 '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) 795 "Face for debug-level messages in the mode-line. Used by vcs, check, etc." 796 :group 'doom-modeline-faces) 797 798 (defface doom-modeline-info 799 '((t (:inherit (doom-modeline success)))) 800 "Face for info-level messages in the mode-line. Used by vcs, check, etc." 801 :group 'doom-modeline-faces) 802 803 (defface doom-modeline-warning 804 '((t (:inherit (doom-modeline warning)))) 805 "Face for warnings in the mode-line. Used by vcs, check, etc." 806 :group 'doom-modeline-faces) 807 808 (defface doom-modeline-urgent 809 '((t (:inherit (doom-modeline error)))) 810 "Face for errors in the mode-line. Used by vcs, check, etc." 811 :group 'doom-modeline-faces) 812 813 (defface doom-modeline-notification 814 '((t (:inherit doom-modeline-warning))) 815 "Face for notifications in the mode-line. Used by GitHub, mu4e, etc. 816 Also see the face `doom-modeline-unread-number'." 817 :group 'doom-modeline-faces) 818 819 (defface doom-modeline-unread-number 820 '((t (:inherit doom-modeline :slant italic))) 821 "Face for unread number in the mode-line. Used by GitHub, mu4e, etc." 822 :group 'doom-modeline-faces) 823 824 (defface doom-modeline-bar 825 '((t (:inherit doom-modeline-highlight))) 826 "The face used for the left-most bar in the mode-line of an active window." 827 :group 'doom-modeline-faces) 828 829 (defface doom-modeline-bar-inactive 830 `((t (:inherit doom-modeline))) 831 "The face used for the left-most bar in the mode-line of an inactive window." 832 :group 'doom-modeline-faces) 833 834 (defface doom-modeline-debug-visual 835 '((((background light)) :foreground "#D4843E" :inherit doom-modeline) 836 (((background dark)) :foreground "#915B2D" :inherit doom-modeline)) 837 "Face to use for the mode-line while debugging." 838 :group 'doom-modeline-faces) 839 840 (defface doom-modeline-evil-emacs-state 841 '((t (:inherit (doom-modeline font-lock-builtin-face)))) 842 "Face for the Emacs state tag in evil indicator." 843 :group 'doom-modeline-faces) 844 845 (defface doom-modeline-evil-insert-state 846 '((t (:inherit (doom-modeline font-lock-keyword-face)))) 847 "Face for the insert state tag in evil indicator." 848 :group 'doom-modeline-faces) 849 850 (defface doom-modeline-evil-motion-state 851 '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) 852 "Face for the motion state tag in evil indicator." 853 :group 'doom-modeline-faces) 854 855 (defface doom-modeline-evil-normal-state 856 '((t (:inherit doom-modeline-info))) 857 "Face for the normal state tag in evil indicator." 858 :group 'doom-modeline-faces) 859 860 (defface doom-modeline-evil-operator-state 861 '((t (:inherit (doom-modeline mode-line)))) 862 "Face for the operator state tag in evil indicator." 863 :group 'doom-modeline-faces) 864 865 (defface doom-modeline-evil-visual-state 866 '((t (:inherit doom-modeline-warning))) 867 "Face for the visual state tag in evil indicator." 868 :group 'doom-modeline-faces) 869 870 (defface doom-modeline-evil-replace-state 871 '((t (:inherit doom-modeline-urgent))) 872 "Face for the replace state tag in evil indicator." 873 :group 'doom-modeline-faces) 874 875 (defface doom-modeline-evil-user-state 876 '((t (:inherit doom-modeline-warning))) 877 "Face for the replace state tag in evil indicator." 878 :group 'doom-modeline-faces) 879 880 (defface doom-modeline-overwrite 881 '((t (:inherit doom-modeline-urgent))) 882 "Face for overwrite indicator." 883 :group 'doom-modeline-faces) 884 885 (defface doom-modeline-god 886 '((t (:inherit doom-modeline-info))) 887 "Face for god-mode indicator." 888 :group 'doom-modeline-faces) 889 890 (defface doom-modeline-ryo 891 '((t (:inherit doom-modeline-info))) 892 "Face for RYO indicator." 893 :group 'doom-modeline-faces) 894 895 (defface doom-modeline-fly-insert-state 896 '((t (:inherit (doom-modeline font-lock-keyword-face)))) 897 "Face for the insert state in xah-fly-keys indicator." 898 :group 'doom-modeline-faces) 899 900 (defface doom-modeline-fly-normal-state 901 '((t (:inherit doom-modeline-info))) 902 "Face for the normal state in xah-fly-keys indicator." 903 :group 'doom-modeline-faces) 904 905 (defface doom-modeline-boon-command-state 906 '((t (:inherit doom-modeline-info))) 907 "Face for the command state tag in boon indicator." 908 :group 'doom-modeline-faces) 909 910 (defface doom-modeline-boon-insert-state 911 '((t (:inherit (doom-modeline font-lock-keyword-face)))) 912 "Face for the insert state tag in boon indicator." 913 :group 'doom-modeline-faces) 914 915 (defface doom-modeline-boon-special-state 916 '((t (:inherit (doom-modeline font-lock-builtin-face)))) 917 "Face for the special state tag in boon indicator." 918 :group 'doom-modeline-faces) 919 920 (defface doom-modeline-boon-off-state 921 '((t (:inherit (doom-modeline mode-line)))) 922 "Face for the off state tag in boon indicator." 923 :group 'doom-modeline-faces) 924 925 (defface doom-modeline-meow-normal-state 926 '((t (:inherit doom-modeline-evil-normal-state))) 927 "Face for the normal state in meow-edit indicator." 928 :group 'doom-modeline-faces) 929 930 (defface doom-modeline-meow-insert-state 931 '((t (:inherit doom-modeline-evil-insert-state))) 932 "Face for the insert state in meow-edit indicator." 933 :group 'doom-modeline-faces) 934 935 (defface doom-modeline-meow-beacon-state 936 '((t (:inherit doom-modeline-evil-visual-state))) 937 "Face for the beacon state in meow-edit indicator." 938 :group 'doom-modeline-faces) 939 940 (defface doom-modeline-meow-motion-state 941 '((t (:inherit doom-modeline-evil-motion-state))) 942 "Face for the motion state in meow-edit indicator." 943 :group 'doom-modeline-faces) 944 945 (defface doom-modeline-meow-keypad-state 946 '((t (:inherit doom-modeline-evil-operator-state))) 947 "Face for the keypad state in meow-edit indicator." 948 :group 'doom-modeline-faces) 949 950 (defface doom-modeline-persp-name 951 '((t (:inherit (doom-modeline font-lock-comment-face italic)))) 952 "Face for the persp name." 953 :group 'doom-modeline-faces) 954 955 (defface doom-modeline-persp-buffer-not-in-persp 956 '((t (:inherit (doom-modeline font-lock-doc-face italic)))) 957 "Face for the buffers which are not in the persp." 958 :group 'doom-modeline-faces) 959 960 (defface doom-modeline-repl-success 961 '((t (:inherit doom-modeline-info))) 962 "Face for REPL success state." 963 :group 'doom-modeline-faces) 964 965 (defface doom-modeline-repl-warning 966 '((t (:inherit doom-modeline-warning))) 967 "Face for REPL warning state." 968 :group 'doom-modeline-faces) 969 970 (defface doom-modeline-lsp-success 971 '((t (:inherit doom-modeline-info))) 972 "Face for LSP success state." 973 :group 'doom-modeline-faces) 974 975 (defface doom-modeline-lsp-warning 976 '((t (:inherit doom-modeline-warning))) 977 "Face for LSP warning state." 978 :group 'doom-modeline-faces) 979 980 (defface doom-modeline-lsp-error 981 '((t (:inherit doom-modeline-urgent))) 982 "Face for LSP error state." 983 :group 'doom-modeline-faces) 984 985 (defface doom-modeline-lsp-running 986 '((t (:inherit (doom-modeline compilation-mode-line-run) :weight normal :slant normal))) 987 "Face for LSP running state." 988 :group 'doom-modeline-faces) 989 990 (defface doom-modeline-battery-charging 991 '((t (:inherit doom-modeline-info))) 992 "Face for battery charging status." 993 :group 'doom-modeline-faces) 994 995 (defface doom-modeline-battery-full 996 '((t (:inherit doom-modeline-info))) 997 "Face for battery full status." 998 :group 'doom-modeline-faces) 999 1000 (defface doom-modeline-battery-normal 1001 '((t (:inherit (doom-modeline mode-line)))) 1002 "Face for battery normal status." 1003 :group 'doom-modeline-faces) 1004 1005 (defface doom-modeline-battery-warning 1006 '((t (:inherit doom-modeline-warning))) 1007 "Face for battery warning status." 1008 :group 'doom-modeline-faces) 1009 1010 (defface doom-modeline-battery-critical 1011 '((t (:inherit doom-modeline-urgent))) 1012 "Face for battery critical status." 1013 :group 'doom-modeline-faces) 1014 1015 (defface doom-modeline-battery-error 1016 '((t (:inherit doom-modeline-urgent))) 1017 "Face for battery error status." 1018 :group 'doom-modeline-faces) 1019 1020 (defface doom-modeline-buffer-timemachine 1021 '((t (:inherit doom-modeline-buffer-file :slant italic))) 1022 "Face for timemachine status." 1023 :group 'doom-modeline-faces) 1024 1025 (defface doom-modeline-time 1026 '((t (:inherit doom-modeline))) 1027 "Face for display time." 1028 :group 'doom-modeline-faces) 1029 1030 (defface doom-modeline-compilation 1031 '((t (:inherit doom-modeline-warning :slant italic :height 0.9))) 1032 "Face for compilation progress." 1033 :group 'doom-modeline-faces) 1034 1035 ;; 1036 ;; Externals 1037 ;; 1038 1039 (defvar mode-line-right-align-edge) 1040 1041 (declare-function doom-modeline-shorten-irc "doom-modeline-segments") 1042 (declare-function face-remap-remove-relative "face-remap") 1043 (declare-function ffip-project-root "ext:find-file-in-project") 1044 (declare-function project-root "project") 1045 (declare-function projectile-project-root "ext:projectile") 1046 1047 1048 ;; 1049 ;; Utilities 1050 ;; 1051 1052 (defun doom-modeline-add-font-lock () 1053 "Fontify `doom-modeline-def-*' statements." 1054 (font-lock-add-keywords 1055 'emacs-lisp-mode 1056 '(("(\\(doom-modeline-def-.+\\)\\_> +\\(.*?\\)\\_>" 1057 (1 font-lock-keyword-face) 1058 (2 font-lock-constant-face))))) 1059 (doom-modeline-add-font-lock) 1060 1061 (defun doom-modeline-add-imenu () 1062 "Add to `imenu' index." 1063 (add-to-list 1064 'imenu-generic-expression 1065 '("Modelines" 1066 "^\\s-*(\\(doom-modeline-def-modeline\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\s'\\|\\\\.\\)+\\)" 1067 2)) 1068 (add-to-list 1069 'imenu-generic-expression 1070 '("Segments" 1071 "^\\s-*(\\(doom-modeline-def-segment\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 1072 2)) 1073 (add-to-list 1074 'imenu-generic-expression 1075 '("Envs" 1076 "^\\s-*(\\(doom-modeline-def-env\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 1077 2))) 1078 1079 1080 ;; 1081 ;; Core helpers 1082 ;; 1083 1084 ;; FIXME #183: Force to calculate mode-line height 1085 ;; @see https://github.com/seagle0128/doom-modeline/issues/183 1086 ;; @see https://github.com/seagle0128/doom-modeline/issues/483 1087 (unless (>= emacs-major-version 29) 1088 (eval-and-compile 1089 (defun doom-modeline-redisplay (&rest _) 1090 "Call `redisplay' to trigger mode-line height calculations. 1091 1092 Certain functions, including e.g. `fit-window-to-buffer', base 1093 their size calculations on values which are incorrect if the 1094 mode-line has a height different from that of the `default' face 1095 and certain other calculations have not yet taken place for the 1096 window in question. 1097 1098 These calculations can be triggered by calling `redisplay' 1099 explicitly at the appropriate time and this functions purpose 1100 is to make it easier to do so. 1101 1102 This function is like `redisplay' with non-nil FORCE argument, 1103 but it will only trigger a redisplay when there is a non nil 1104 `mode-line-format' and the height of the mode-line is different 1105 from that of the `default' face. This function is intended to be 1106 used as an advice to window creation functions." 1107 (when (and (bound-and-true-p doom-modeline-mode) 1108 mode-line-format 1109 (/= (frame-char-height) (window-mode-line-height))) 1110 (redisplay t)))) 1111 (advice-add #'fit-window-to-buffer :before #'doom-modeline-redisplay)) 1112 1113 ;; For `flycheck-color-mode-line' 1114 (with-eval-after-load 'flycheck-color-mode-line 1115 (defvar flycheck-color-mode-line-face-to-color) 1116 (setq flycheck-color-mode-line-face-to-color 'doom-modeline)) 1117 1118 (defun doom-modeline-icon-displayable-p () 1119 "Return non-nil if icons are displayable." 1120 (and doom-modeline-icon (featurep 'nerd-icons))) 1121 1122 (defun doom-modeline-mwheel-available-p () 1123 "Whether mouse wheel is available." 1124 (and (featurep 'mwheel) (bound-and-true-p mouse-wheel-mode))) 1125 1126 ;; Keep `doom-modeline-current-window' up-to-date 1127 (defun doom-modeline--selected-window () 1128 "Get the selected window." 1129 (frame-selected-window)) 1130 1131 (defvar doom-modeline-current-window (doom-modeline--selected-window) 1132 "Current window.") 1133 1134 (defun doom-modeline--active () 1135 "Whether is an active window." 1136 (unless (and (bound-and-true-p mini-frame-frame) 1137 (and (frame-live-p mini-frame-frame) 1138 (frame-visible-p mini-frame-frame))) 1139 (and doom-modeline-current-window 1140 (eq (doom-modeline--selected-window) doom-modeline-current-window)))) 1141 1142 (defvar-local doom-modeline--limited-width-p nil) 1143 1144 (defun doom-modeline--segment-visible (name) 1145 "Whether the segment NAME should be displayed." 1146 (and 1147 (or (doom-modeline--active) 1148 (member name doom-modeline-always-visible-segments)) 1149 (not doom-modeline--limited-width-p))) 1150 1151 (defun doom-modeline-set-selected-window (&rest _) 1152 "Set `doom-modeline-current-window' appropriately." 1153 (let ((win (doom-modeline--selected-window))) 1154 (setq doom-modeline-current-window 1155 (if (minibuffer-window-active-p win) 1156 (minibuffer-selected-window) 1157 win)))) 1158 1159 (defun doom-modeline-unset-selected-window () 1160 "Unset `doom-modeline-current-window' appropriately." 1161 (setq doom-modeline-current-window nil)) 1162 1163 (add-hook 'pre-redisplay-functions #'doom-modeline-set-selected-window) 1164 1165 ;; Ensure modeline is inactive when Emacs is unfocused 1166 (defvar doom-modeline--remap-faces '(mode-line 1167 mode-line-active 1168 mode-line-emphasis 1169 mode-line-highlight 1170 mode-line-buffer-id 1171 doom-modeline 1172 solaire-mode-line-face 1173 solaire-mode-line-active-face 1174 paradox-mode-line-face 1175 flycheck-color-mode-line-error-face 1176 flycheck-color-mode-line-warning-face 1177 flycheck-color-mode-line-info-face 1178 flycheck-color-mode-line-success-face)) 1179 1180 (defvar doom-modeline--remap-face-cookie-alist nil) 1181 (defun doom-modeline-focus () 1182 "Focus mode-line." 1183 (mapc #'face-remap-remove-relative doom-modeline--remap-face-cookie-alist)) 1184 1185 (defun doom-modeline-unfocus () 1186 "Unfocus mode-line." 1187 (dolist (face doom-modeline--remap-faces) 1188 (add-to-list 'doom-modeline--remap-face-cookie-alist 1189 (face-remap-add-relative face 'mode-line-inactive)))) 1190 1191 (with-no-warnings 1192 (if (boundp 'after-focus-change-function) 1193 (progn 1194 (defun doom-modeline-focus-change (&rest _) 1195 (if (frame-focus-state (frame-parent)) 1196 (progn 1197 (doom-modeline-focus) 1198 ;; HACK: pulse after focusing in the frame to refresh the buffer name. 1199 ;; @see https://github.com/seagle0128/doom-modeline/issues/591 1200 (when (fboundp 'pulse-momentary-highlight-region) 1201 (pulse-momentary-highlight-region 0 0))) 1202 (doom-modeline-unfocus))) 1203 (advice-add #'handle-switch-frame :after #'doom-modeline-focus-change) 1204 (add-function :after after-focus-change-function #'doom-modeline-focus-change)) 1205 (progn 1206 (add-hook 'focus-in-hook #'doom-modeline-focus) 1207 (add-hook 'focus-out-hook #'doom-modeline-unfocus)))) 1208 1209 1210 ;; 1211 ;; Core 1212 ;; 1213 1214 (defvar doom-modeline-fn-alist ()) 1215 (defvar doom-modeline-var-alist ()) 1216 1217 (defmacro doom-modeline-def-segment (name &rest body) 1218 "Define a modeline segment NAME with BODY and byte compiles it." 1219 (declare (indent defun) (doc-string 2)) 1220 (let ((sym (intern (format "doom-modeline-segment--%s" name))) 1221 (docstring (if (stringp (car body)) 1222 (pop body) 1223 (format "%s modeline segment" name)))) 1224 (cond ((and (symbolp (car body)) 1225 (not (cdr body))) 1226 `(add-to-list 'doom-modeline-var-alist (cons ',name ',(car body)))) 1227 (t 1228 `(progn 1229 (defun ,sym () ,docstring ,@body) 1230 (add-to-list 'doom-modeline-fn-alist (cons ',name ',sym)) 1231 ,(unless (bound-and-true-p byte-compile-current-file) 1232 `(let (byte-compile-warnings) 1233 (unless (and (fboundp 'subr-native-elisp-p) 1234 (subr-native-elisp-p (symbol-function #',sym))) 1235 (byte-compile #',sym))))))))) 1236 1237 (defun doom-modeline--prepare-segments (segments) 1238 "Prepare mode-line `SEGMENTS'." 1239 (let (forms it) 1240 (dolist (seg segments) 1241 (cond ((stringp seg) 1242 (push seg forms)) 1243 ((symbolp seg) 1244 (cond ((setq it (alist-get seg doom-modeline-fn-alist)) 1245 (push (list :eval (list it)) forms)) 1246 ((setq it (alist-get seg doom-modeline-var-alist)) 1247 (push it forms)) 1248 ((error "%s is not a defined segment" seg)))) 1249 ((error "%s is not a valid segment" seg)))) 1250 (nreverse forms))) 1251 1252 (defun doom-modeline-def-modeline (name lhs &optional rhs) 1253 "Define a modeline format and byte-compiles it. 1254 NAME is a symbol to identify it (used by `doom-modeline' for retrieval). 1255 LHS and RHS are lists of symbols of modeline segments defined with 1256 `doom-modeline-def-segment'. 1257 1258 Example: 1259 (doom-modeline-def-modeline \\='minimal 1260 \\='(bar matches \" \" buffer-info) 1261 \\='(media-info major-mode)) 1262 (doom-modeline-set-modeline \\='minimal t)" 1263 (let ((sym (intern (format "doom-modeline-format--%s" name))) 1264 (lhs-forms (doom-modeline--prepare-segments lhs)) 1265 (rhs-forms (doom-modeline--prepare-segments rhs))) 1266 (defalias sym 1267 (lambda () 1268 (list lhs-forms 1269 (let* ((rhs-str (format-mode-line (cons "" rhs-forms))) 1270 (rhs-width (progn 1271 (add-face-text-property 1272 0 (length rhs-str) 'mode-line t rhs-str) 1273 (doom-modeline-string-pixel-width rhs-str)))) 1274 (propertize 1275 " " 1276 'face (doom-modeline-face) 1277 'display 1278 ;; Backport from `mode-line-right-align-edge' in 30 1279 (if (and (display-graphic-p) 1280 (not (eq mode-line-right-align-edge 'window))) 1281 `(space :align-to (- ,mode-line-right-align-edge 1282 (,rhs-width))) 1283 `(space :align-to (,(- (window-pixel-width) 1284 (window-scroll-bar-width) 1285 (window-right-divider-width) 1286 (* (or (cdr (window-margins)) 1) 1287 (frame-char-width)) 1288 (pcase mode-line-right-align-edge 1289 ('right-margin 1290 (or (cdr (window-margins)) 0)) 1291 ('right-fringe 1292 (or (cadr (window-fringes)) 0)) 1293 (_ 0)) 1294 rhs-width)))))) 1295 rhs-forms)) 1296 (concat "Modeline:\n" 1297 (format " %s\n %s" 1298 (prin1-to-string lhs) 1299 (prin1-to-string rhs)))))) 1300 (put 'doom-modeline-def-modeline 'lisp-indent-function 'defun) 1301 1302 (defun doom-modeline (key) 1303 "Return a mode-line configuration associated with KEY (a symbol). 1304 Throws an error if it doesn't exist." 1305 (let ((fn (intern-soft (format "doom-modeline-format--%s" key)))) 1306 (when (functionp fn) 1307 `(:eval (,fn))))) 1308 1309 (defun doom-modeline-set-modeline (key &optional default) 1310 "Set the modeline format. Does nothing if the modeline KEY doesn't exist. 1311 If DEFAULT is non-nil, set the default mode-line for all buffers." 1312 (when-let ((modeline (doom-modeline key))) 1313 (setf (if default 1314 (default-value 'mode-line-format) 1315 mode-line-format) 1316 (list "%e" modeline)))) 1317 1318 ;; 1319 ;; Helpers 1320 ;; 1321 1322 (defconst doom-modeline-ellipsis 1323 (if (char-displayable-p ?…) "…" "...") 1324 "Ellipsis.") 1325 1326 (defsubst doom-modeline-spc () 1327 "Whitespace." 1328 (propertize " " 'face (doom-modeline-face))) 1329 1330 (defsubst doom-modeline-wspc () 1331 "Wide Whitespace." 1332 (propertize " " 'face (doom-modeline-face))) 1333 1334 (defsubst doom-modeline-vspc () 1335 "Thin whitespace." 1336 (propertize " " 1337 'face (doom-modeline-face) 1338 'display '((space :relative-width 0.5)))) 1339 1340 (defun doom-modeline-face (&optional face inactive-face) 1341 "Display FACE in active window, and INACTIVE-FACE in inactive window. 1342 IF FACE is nil, `mode-line' face will be used. 1343 If INACTIVE-FACE is nil, `mode-line-inactive' face will be used." 1344 (if (doom-modeline--active) 1345 (or (and (facep face) `(:inherit (doom-modeline ,face))) 1346 (and (facep 'mode-line-active) '(:inherit (doom-modeline mode-line-active))) 1347 '(:inherit (doom-modeline mode-line))) 1348 (or (and (facep face) `(:inherit (doom-modeline mode-line-inactive ,face))) 1349 (and (facep inactive-face) `(:inherit (doom-modeline ,inactive-face))) 1350 '(:inherit (doom-modeline mode-line-inactive))))) 1351 1352 (defun doom-modeline-string-pixel-width (str) 1353 "Return the width of STR in pixels." 1354 (if (fboundp 'string-pixel-width) 1355 (string-pixel-width str) 1356 (* (string-width str) (window-font-width nil 'mode-line) 1357 (if (display-graphic-p) 1.05 1.0)))) 1358 1359 (defun doom-modeline--font-height () 1360 "Calculate the actual char height of the mode-line." 1361 (let ((height (face-attribute 'mode-line :height)) 1362 (char-height (window-font-height nil 'mode-line))) 1363 (round 1364 (* 1.0 (cond ((integerp height) (/ height 10)) 1365 ((floatp height) (* height char-height)) 1366 (t char-height)))))) 1367 1368 (defun doom-modeline--original-value (sym) 1369 "Return the original value for SYM, if any. 1370 1371 If SYM has an original value, return it in a list. Return nil 1372 otherwise." 1373 (let* ((orig-val-expr (get sym 'standard-value))) 1374 (when (consp orig-val-expr) 1375 (ignore-errors 1376 (list 1377 (eval (car orig-val-expr))))))) 1378 1379 (defun doom-modeline-add-variable-watcher (symbol watch-function) 1380 "Cause WATCH-FUNCTION to be called when SYMBOL is set if possible. 1381 1382 See docs of `add-variable-watcher'." 1383 (when (fboundp 'add-variable-watcher) 1384 (add-variable-watcher symbol watch-function))) 1385 1386 (defun doom-modeline-propertize-icon (icon &optional face) 1387 "Propertize the ICON with the specified FACE. 1388 1389 The face should be the first attribute, or the font family may be overridden. 1390 So convert the face \":family XXX :height XXX :inherit XXX\" to 1391 \":inherit XXX :family XXX :height XXX\". 1392 See https://github.com/seagle0128/doom-modeline/issues/301." 1393 (when icon 1394 (if (doom-modeline-icon-displayable-p) 1395 (when-let ((props (get-text-property 0 'face icon))) 1396 (when (listp props) 1397 (cl-destructuring-bind (&key family height inherit &allow-other-keys) props 1398 (propertize icon 'face `(:inherit (doom-modeline ,(or face inherit props)) 1399 :family ,(or family "") 1400 :height ,(or height 1.0)))))) 1401 (propertize icon 'face `(:inherit (doom-modeline ,face)))))) 1402 1403 (defun doom-modeline-icon (icon-set icon-name unicode text &rest args) 1404 "Display icon of ICON-NAME with ARGS in mode-line. 1405 1406 ICON-SET includes `ipsicon', `octicon', `pomicon', `powerline', `faicon', 1407 `wicon', `sucicon', `devicon', `codicon', `flicon' and `mdicon', etc. 1408 UNICODE is the unicode char fallback. TEXT is the ASCII char fallback. 1409 ARGS is same as `nerd-icons-octicon' and others." 1410 (let ((face `(:inherit (doom-modeline 1411 ,(or (plist-get args :face) 'mode-line))))) 1412 (cond 1413 ;; Icon 1414 ((and (doom-modeline-icon-displayable-p) 1415 icon-name 1416 (not (string-empty-p icon-name))) 1417 (if-let* ((func (nerd-icons--function-name icon-set)) 1418 (icon (and (fboundp func) 1419 (apply func icon-name args)))) 1420 (doom-modeline-propertize-icon icon face) 1421 "")) 1422 ;; Unicode fallback 1423 ((and doom-modeline-unicode-fallback 1424 unicode 1425 (not (string-empty-p unicode)) 1426 (char-displayable-p (string-to-char unicode))) 1427 (propertize unicode 'face face)) 1428 ;; ASCII text 1429 (text 1430 (propertize text 'face face)) 1431 ;; Fallback 1432 (t "")))) 1433 1434 (defun doom-modeline-icon-for-buffer () 1435 "Get the formatted icon for the current buffer." 1436 (nerd-icons-icon-for-buffer)) 1437 1438 (defun doom-modeline-display-icon (icon) 1439 "Display ICON in mode-line." 1440 (if (doom-modeline--active) 1441 icon 1442 (doom-modeline-propertize-icon icon 'mode-line-inactive))) 1443 1444 (defun doom-modeline-display-text (text) 1445 "Display TEXT in mode-line." 1446 (if (doom-modeline--active) 1447 text 1448 (propertize text 'face `(:inherit (mode-line-inactive 1449 ,(get-text-property 0 'face text)))))) 1450 1451 (defun doom-modeline-vcs-name () 1452 "Display the vcs name." 1453 (and vc-mode (cadr (split-string (string-trim vc-mode) "^[A-Z]+[-:]+")))) 1454 1455 (defun doom-modeline--create-bar-image (face width height) 1456 "Create the bar image. 1457 1458 Use FACE for the bar, WIDTH and HEIGHT are the image size in pixels." 1459 (when (and (image-type-available-p 'pbm) 1460 (numberp width) (> width 0) 1461 (numberp height) (> height 0)) 1462 (propertize 1463 " " 'display 1464 (let ((color (or (face-background face nil t) "None"))) 1465 (ignore-errors 1466 (create-image 1467 (concat (format "P1\n%i %i\n" width height) 1468 (make-string (* width height) ?1) 1469 "\n") 1470 'pbm t :scale 1 :foreground color :ascent 'center)))))) 1471 1472 (defun doom-modeline--create-hud-image 1473 (face1 face2 width height top-margin bottom-margin) 1474 "Create the hud image. 1475 1476 Use FACE1 for the bar, FACE2 for the background. 1477 WIDTH and HEIGHT are the image size in pixels. 1478 TOP-MARGIN and BOTTOM-MARGIN are the size of the margin above and below the bar, 1479 respectively." 1480 (when (and (display-graphic-p) 1481 (image-type-available-p 'pbm) 1482 (numberp width) (> width 0) 1483 (numberp height) (> height 0)) 1484 (let ((min-height (min height doom-modeline-hud-min-height))) 1485 (unless (> (- height top-margin bottom-margin) min-height) 1486 (let ((margin (- height min-height))) 1487 (setq top-margin (/ (* margin top-margin) (+ top-margin bottom-margin)) 1488 bottom-margin (- margin top-margin))))) 1489 (propertize 1490 " " 'display 1491 (let ((color1 (or (face-background face1 nil t) "None")) 1492 (color2 (or (face-background face2 nil t) "None"))) 1493 (create-image 1494 (concat 1495 (format "P1\n%i %i\n" width height) 1496 (make-string (* top-margin width) ?0) 1497 (make-string (* (- height top-margin bottom-margin) width) ?1) 1498 (make-string (* bottom-margin width) ?0) 1499 "\n") 1500 'pbm t :foreground color1 :background color2 :ascent 'center))))) 1501 1502 ;; Check whether `window-total-width' is smaller than the limit 1503 (defun doom-modeline-window-size-change-function (&rest _) 1504 "Function for `window-size-change-functions'." 1505 (setq doom-modeline--limited-width-p 1506 (cond 1507 ((integerp doom-modeline-window-width-limit) 1508 (<= (window-total-width) doom-modeline-window-width-limit)) 1509 ((floatp doom-modeline-window-width-limit) 1510 (<= (/ (window-total-width) (frame-width) 1.0) 1511 doom-modeline-window-width-limit))))) 1512 1513 (add-hook 'after-revert-hook #'doom-modeline-window-size-change-function) 1514 (add-hook 'buffer-list-update-hook #'doom-modeline-window-size-change-function) 1515 (add-hook 'window-size-change-functions #'doom-modeline-window-size-change-function) 1516 1517 (defvar-local doom-modeline--project-root nil) 1518 (defun doom-modeline--project-root () 1519 "Get the path to the project root. 1520 Return nil if no project was found." 1521 (or doom-modeline--project-root 1522 (setq doom-modeline--project-root 1523 (cond 1524 ((and (memq doom-modeline-project-detection '(auto ffip)) 1525 (fboundp 'ffip-project-root)) 1526 (let ((inhibit-message t)) 1527 (ffip-project-root))) 1528 ((and (memq doom-modeline-project-detection '(auto projectile)) 1529 (bound-and-true-p projectile-mode)) 1530 (projectile-project-root)) 1531 ((and (memq doom-modeline-project-detection '(auto project)) 1532 (fboundp 'project-current)) 1533 (when-let ((project (project-current))) 1534 (expand-file-name 1535 (if (fboundp 'project-root) 1536 (project-root project) 1537 (car (with-no-warnings 1538 (project-roots project))))))))))) 1539 1540 (doom-modeline-add-variable-watcher 1541 'doom-modeline-project-detection 1542 (lambda (_sym val op _where) 1543 (when (eq op 'set) 1544 (setq doom-modeline-project-detection val) 1545 (dolist (buf (buffer-list)) 1546 (with-current-buffer buf 1547 (setq doom-modeline--project-root nil) 1548 (and buffer-file-name (revert-buffer t t))))))) 1549 1550 (defun doom-modeline-project-p () 1551 "Check if the file is in a project." 1552 (doom-modeline--project-root)) 1553 1554 (defun doom-modeline-project-root () 1555 "Get the path to the root of your project. 1556 Return `default-directory' if no project was found." 1557 (abbreviate-file-name 1558 (or (doom-modeline--project-root) default-directory))) 1559 1560 (defun doom-modeline--format-buffer-file-name () 1561 "Get and format the buffer file name." 1562 (let ((buffer-file-name (file-local-name 1563 (or (buffer-file-name (buffer-base-buffer)) "")))) 1564 (or (and doom-modeline-buffer-file-name-function 1565 (funcall doom-modeline-buffer-file-name-function buffer-file-name)) 1566 buffer-file-name))) 1567 1568 (defun doom-modeline--format-buffer-file-truename (b-f-n) 1569 "Get and format buffer file truename via B-F-N." 1570 (let ((buffer-file-truename (file-local-name 1571 (or (file-truename b-f-n) "")))) 1572 (or (and doom-modeline-buffer-file-truename-function 1573 (funcall doom-modeline-buffer-file-truename-function buffer-file-truename)) 1574 buffer-file-truename))) 1575 1576 (defun doom-modeline-buffer-file-name () 1577 "Propertize file name based on `doom-modeline-buffer-file-name-style'." 1578 (let* ((buffer-file-name (doom-modeline--format-buffer-file-name)) 1579 (buffer-file-truename (doom-modeline--format-buffer-file-truename buffer-file-name)) 1580 (file-name 1581 (pcase doom-modeline-buffer-file-name-style 1582 ('auto 1583 (if (doom-modeline-project-p) 1584 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide) 1585 (propertize "%b" 'face 'doom-modeline-buffer-file))) 1586 ('truncate-upto-project 1587 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink)) 1588 ('truncate-from-project 1589 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil 'shrink)) 1590 ('truncate-with-project 1591 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide)) 1592 ('truncate-except-project 1593 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink)) 1594 ('truncate-upto-root 1595 (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename)) 1596 ('truncate-all 1597 (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename t)) 1598 ('truncate-nil 1599 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename)) 1600 ('relative-to-project 1601 (doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename)) 1602 ('relative-from-project 1603 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide)) 1604 ('file-name 1605 (propertize (file-name-nondirectory buffer-file-name) 1606 'face 'doom-modeline-buffer-file)) 1607 ('file-name-with-project 1608 (format "%s|%s" 1609 (propertize (file-name-nondirectory 1610 (directory-file-name (file-local-name (doom-modeline-project-root)))) 1611 'face 'doom-modeline-project-dir) 1612 (propertize (file-name-nondirectory buffer-file-name) 1613 'face 'doom-modeline-buffer-file))) 1614 ((or 'buffer-name _) 1615 (propertize "%b" 'face 'doom-modeline-buffer-file))))) 1616 (propertize (if (string-empty-p file-name) 1617 (propertize "%b" 'face 'doom-modeline-buffer-file) 1618 file-name) 1619 'mouse-face 'mode-line-highlight 1620 'help-echo (concat buffer-file-truename 1621 (unless (string= (file-name-nondirectory buffer-file-truename) 1622 (buffer-name)) 1623 (concat "\n" (buffer-name))) 1624 "\nmouse-1: Previous buffer\nmouse-3: Next buffer") 1625 'local-map mode-line-buffer-identification-keymap))) 1626 1627 (defun doom-modeline--buffer-file-name-truncate (file-path true-file-path &optional truncate-tail) 1628 "Propertize file name that truncates every dir along path. 1629 1630 If TRUNCATE-TAIL is t also truncate the parent directory of the file." 1631 (let ((dirs (shrink-path-prompt (file-name-directory true-file-path)))) 1632 (if (null dirs) 1633 (propertize "%b" 'face 'doom-modeline-buffer-file) 1634 (let ((dirname (car dirs)) 1635 (basename (cdr dirs))) 1636 (concat (propertize (concat dirname 1637 (if truncate-tail (substring basename 0 1) basename) 1638 "/") 1639 'face 'doom-modeline-project-root-dir) 1640 (propertize (file-name-nondirectory file-path) 1641 'face 'doom-modeline-buffer-file)))))) 1642 1643 (defun doom-modeline--buffer-file-name-relative (_file-path true-file-path &optional include-project) 1644 "Propertize file name showing directories relative to project's root only. 1645 1646 If INCLUDE-PROJECT is non-nil, the project path will be included." 1647 (let ((root (file-local-name (doom-modeline-project-root)))) 1648 (if (null root) 1649 (propertize "%b" 'face 'doom-modeline-buffer-file) 1650 (let ((relative-dirs (file-relative-name (file-name-directory true-file-path) 1651 (if include-project (concat root "../") root)))) 1652 (and (equal "./" relative-dirs) (setq relative-dirs "")) 1653 (concat (propertize relative-dirs 'face 'doom-modeline-buffer-path) 1654 (propertize (file-name-nondirectory true-file-path) 1655 'face 'doom-modeline-buffer-file)))))) 1656 1657 (defun doom-modeline--buffer-file-name (file-path 1658 true-file-path 1659 &optional 1660 truncate-project-root-parent 1661 truncate-project-relative-path 1662 hide-project-root-parent) 1663 "Propertize buffer name given by FILE-PATH or TRUE-FILE-PATH. 1664 1665 If TRUNCATE-PROJECT-ROOT-PARENT is non-nil will be saved by truncating project 1666 root parent down fish-shell style. 1667 1668 Example: 1669 ~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el 1670 1671 If TRUNCATE-PROJECT-RELATIVE-PATH is non-nil will be saved by truncating project 1672 relative path down fish-shell style. 1673 1674 Example: 1675 ~/Projects/FOSS/emacs/lisp/comint.el => ~/Projects/FOSS/emacs/l/comint.el 1676 1677 If HIDE-PROJECT-ROOT-PARENT is non-nil will hide project root parent. 1678 1679 Example: 1680 ~/Projects/FOSS/emacs/lisp/comint.el => emacs/lisp/comint.el" 1681 (let ((project-root (file-local-name (doom-modeline-project-root)))) 1682 (concat 1683 ;; Project root parent 1684 (unless hide-project-root-parent 1685 (when-let (root-path-parent 1686 (file-name-directory (directory-file-name project-root))) 1687 (propertize 1688 (if (and truncate-project-root-parent 1689 (not (string-empty-p root-path-parent)) 1690 (not (string= root-path-parent "/"))) 1691 (shrink-path--dirs-internal root-path-parent t) 1692 (abbreviate-file-name root-path-parent)) 1693 'face 'doom-modeline-project-parent-dir))) 1694 ;; Project directory 1695 (propertize 1696 (concat (file-name-nondirectory (directory-file-name project-root)) "/") 1697 'face 'doom-modeline-project-dir) 1698 ;; relative path 1699 (propertize 1700 (when-let (relative-path (file-relative-name 1701 (or (file-name-directory 1702 (if doom-modeline-buffer-file-true-name 1703 true-file-path file-path)) 1704 "./") 1705 project-root)) 1706 (if (string= relative-path "./") 1707 "" 1708 (if truncate-project-relative-path 1709 (substring (shrink-path--dirs-internal relative-path t) 1) 1710 relative-path))) 1711 'face 'doom-modeline-buffer-path) 1712 ;; File name 1713 (propertize (file-name-nondirectory file-path) 1714 'face 'doom-modeline-buffer-file)))) 1715 1716 (provide 'doom-modeline-core) 1717 1718 ;;; doom-modeline-core.el ends here