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