doom-modeline-core.el (62099B)
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 face-remap-remove-relative "face-remap") 1029 (declare-function ffip-project-root "ext:find-file-in-project") 1030 (declare-function project-root "project") 1031 (declare-function projectile-project-root "ext:projectile") 1032 1033 1034 ;; 1035 ;; Utilities 1036 ;; 1037 1038 (defun doom-modeline-add-font-lock () 1039 "Fontify `doom-modeline-def-*' statements." 1040 (font-lock-add-keywords 1041 'emacs-lisp-mode 1042 '(("(\\(doom-modeline-def-.+\\)\\_> +\\(.*?\\)\\_>" 1043 (1 font-lock-keyword-face) 1044 (2 font-lock-constant-face))))) 1045 (doom-modeline-add-font-lock) 1046 1047 (defun doom-modeline-add-imenu () 1048 "Add to `imenu' index." 1049 (add-to-list 1050 'imenu-generic-expression 1051 '("Modelines" 1052 "^\\s-*(\\(doom-modeline-def-modeline\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\s'\\|\\\\.\\)+\\)" 1053 2)) 1054 (add-to-list 1055 'imenu-generic-expression 1056 '("Segments" 1057 "^\\s-*(\\(doom-modeline-def-segment\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 1058 2)) 1059 (add-to-list 1060 'imenu-generic-expression 1061 '("Envs" 1062 "^\\s-*(\\(doom-modeline-def-env\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" 1063 2))) 1064 1065 1066 ;; 1067 ;; Core helpers 1068 ;; 1069 1070 ;; FIXME #183: Force to calculate mode-line height 1071 ;; @see https://github.com/seagle0128/doom-modeline/issues/183 1072 ;; @see https://github.com/seagle0128/doom-modeline/issues/483 1073 (unless (>= emacs-major-version 29) 1074 (eval-and-compile 1075 (defun doom-modeline-redisplay (&rest _) 1076 "Call `redisplay' to trigger mode-line height calculations. 1077 1078 Certain functions, including e.g. `fit-window-to-buffer', base 1079 their size calculations on values which are incorrect if the 1080 mode-line has a height different from that of the `default' face 1081 and certain other calculations have not yet taken place for the 1082 window in question. 1083 1084 These calculations can be triggered by calling `redisplay' 1085 explicitly at the appropriate time and this functions purpose 1086 is to make it easier to do so. 1087 1088 This function is like `redisplay' with non-nil FORCE argument, 1089 but it will only trigger a redisplay when there is a non nil 1090 `mode-line-format' and the height of the mode-line is different 1091 from that of the `default' face. This function is intended to be 1092 used as an advice to window creation functions." 1093 (when (and (bound-and-true-p doom-modeline-mode) 1094 mode-line-format 1095 (/= (frame-char-height) (window-mode-line-height))) 1096 (redisplay t)))) 1097 (advice-add #'fit-window-to-buffer :before #'doom-modeline-redisplay)) 1098 1099 ;; For `flycheck-color-mode-line' 1100 (with-eval-after-load 'flycheck-color-mode-line 1101 (defvar flycheck-color-mode-line-face-to-color) 1102 (setq flycheck-color-mode-line-face-to-color 'doom-modeline)) 1103 1104 (defun doom-modeline-icon-displayable-p () 1105 "Return non-nil if icons are displayable." 1106 (and doom-modeline-icon (featurep 'nerd-icons))) 1107 1108 (defun doom-modeline-mwheel-available-p () 1109 "Whether mouse wheel is available." 1110 (and (featurep 'mwheel) (bound-and-true-p mouse-wheel-mode))) 1111 1112 ;; Keep `doom-modeline-current-window' up-to-date 1113 (defun doom-modeline--selected-window () 1114 "Get the selected window." 1115 (frame-selected-window)) 1116 1117 (defvar doom-modeline-current-window (doom-modeline--selected-window) 1118 "Current window.") 1119 1120 (defun doom-modeline--active () 1121 "Whether is an active window." 1122 (unless (and (bound-and-true-p mini-frame-frame) 1123 (and (frame-live-p mini-frame-frame) 1124 (frame-visible-p mini-frame-frame))) 1125 (and doom-modeline-current-window 1126 (eq (doom-modeline--selected-window) doom-modeline-current-window)))) 1127 1128 (defvar-local doom-modeline--limited-width-p nil) 1129 1130 (defun doom-modeline--segment-visible (name) 1131 "Whether the segment NAME should be displayed." 1132 (and 1133 (or (doom-modeline--active) 1134 (member name doom-modeline-always-visible-segments)) 1135 (not doom-modeline--limited-width-p))) 1136 1137 (defun doom-modeline-set-selected-window (&rest _) 1138 "Set `doom-modeline-current-window' appropriately." 1139 (let ((win (doom-modeline--selected-window))) 1140 (setq doom-modeline-current-window 1141 (if (minibuffer-window-active-p win) 1142 (minibuffer-selected-window) 1143 win)))) 1144 1145 (defun doom-modeline-unset-selected-window () 1146 "Unset `doom-modeline-current-window' appropriately." 1147 (setq doom-modeline-current-window nil)) 1148 1149 (add-hook 'pre-redisplay-functions #'doom-modeline-set-selected-window) 1150 1151 ;; Ensure modeline is inactive when Emacs is unfocused 1152 (defvar doom-modeline--remap-faces '(mode-line 1153 mode-line-active 1154 mode-line-emphasis 1155 mode-line-highlight 1156 mode-line-buffer-id 1157 doom-modeline 1158 solaire-mode-line-face 1159 solaire-mode-line-active-face 1160 paradox-mode-line-face 1161 flycheck-color-mode-line-error-face 1162 flycheck-color-mode-line-warning-face 1163 flycheck-color-mode-line-info-face 1164 flycheck-color-mode-line-success-face)) 1165 1166 (defvar doom-modeline--remap-face-cookie-alist nil) 1167 (defun doom-modeline-focus () 1168 "Focus mode-line." 1169 (mapc #'face-remap-remove-relative doom-modeline--remap-face-cookie-alist)) 1170 1171 (defun doom-modeline-unfocus () 1172 "Unfocus mode-line." 1173 (dolist (face doom-modeline--remap-faces) 1174 (add-to-list 'doom-modeline--remap-face-cookie-alist 1175 (face-remap-add-relative face 'mode-line-inactive)))) 1176 1177 (with-no-warnings 1178 (if (boundp 'after-focus-change-function) 1179 (progn 1180 (defun doom-modeline-focus-change (&rest _) 1181 (if (frame-focus-state (frame-parent)) 1182 (progn 1183 (doom-modeline-focus) 1184 ;; HACK: pulse after focusing in the frame to refresh the buffer name. 1185 ;; @see https://github.com/seagle0128/doom-modeline/issues/591 1186 (when (fboundp 'pulse-momentary-highlight-region) 1187 (pulse-momentary-highlight-region 0 0))) 1188 (doom-modeline-unfocus))) 1189 (advice-add #'handle-switch-frame :after #'doom-modeline-focus-change) 1190 (add-function :after after-focus-change-function #'doom-modeline-focus-change)) 1191 (progn 1192 (add-hook 'focus-in-hook #'doom-modeline-focus) 1193 (add-hook 'focus-out-hook #'doom-modeline-unfocus)))) 1194 1195 1196 ;; 1197 ;; Core 1198 ;; 1199 1200 (defvar doom-modeline-fn-alist ()) 1201 (defvar doom-modeline-var-alist ()) 1202 1203 (defmacro doom-modeline-def-segment (name &rest body) 1204 "Define a modeline segment NAME with BODY and byte compiles it." 1205 (declare (indent defun) (doc-string 2)) 1206 (let ((sym (intern (format "doom-modeline-segment--%s" name))) 1207 (docstring (if (stringp (car body)) 1208 (pop body) 1209 (format "%s modeline segment" name)))) 1210 (cond ((and (symbolp (car body)) 1211 (not (cdr body))) 1212 `(add-to-list 'doom-modeline-var-alist (cons ',name ',(car body)))) 1213 (t 1214 `(progn 1215 (defun ,sym () ,docstring ,@body) 1216 (add-to-list 'doom-modeline-fn-alist (cons ',name ',sym)) 1217 ,(unless (bound-and-true-p byte-compile-current-file) 1218 `(let (byte-compile-warnings) 1219 (unless (and (fboundp 'subr-native-elisp-p) 1220 (subr-native-elisp-p (symbol-function #',sym))) 1221 (byte-compile #',sym))))))))) 1222 1223 (defun doom-modeline--prepare-segments (segments) 1224 "Prepare mode-line `SEGMENTS'." 1225 (let (forms it) 1226 (dolist (seg segments) 1227 (cond ((stringp seg) 1228 (push seg forms)) 1229 ((symbolp seg) 1230 (cond ((setq it (alist-get seg doom-modeline-fn-alist)) 1231 (push (list :eval (list it)) forms)) 1232 ((setq it (alist-get seg doom-modeline-var-alist)) 1233 (push it forms)) 1234 ((error "%s is not a defined segment" seg)))) 1235 ((error "%s is not a valid segment" seg)))) 1236 (nreverse forms))) 1237 1238 (defun doom-modeline-def-modeline (name lhs &optional rhs) 1239 "Define a modeline format and byte-compiles it. 1240 NAME is a symbol to identify it (used by `doom-modeline' for retrieval). 1241 LHS and RHS are lists of symbols of modeline segments defined with 1242 `doom-modeline-def-segment'. 1243 1244 Example: 1245 (doom-modeline-def-modeline \\='minimal 1246 \\='(bar matches \" \" buffer-info) 1247 \\='(media-info major-mode)) 1248 (doom-modeline-set-modeline \\='minimal t)" 1249 (let ((sym (intern (format "doom-modeline-format--%s" name))) 1250 (lhs-forms (doom-modeline--prepare-segments lhs)) 1251 (rhs-forms (doom-modeline--prepare-segments rhs))) 1252 (defalias sym 1253 (lambda () 1254 (list lhs-forms 1255 (let* ((rhs-str (format-mode-line (cons "" rhs-forms))) 1256 (rhs-width (progn 1257 (add-face-text-property 1258 0 (length rhs-str) 'mode-line t rhs-str) 1259 (doom-modeline-string-pixel-width rhs-str)))) 1260 (propertize 1261 " " 1262 'face (doom-modeline-face) 1263 'display 1264 ;; Backport from `mode-line-right-align-edge' in 30 1265 (if (and (display-graphic-p) 1266 (not (eq mode-line-right-align-edge 'window))) 1267 `(space :align-to (- ,mode-line-right-align-edge 1268 (,rhs-width))) 1269 `(space :align-to (,(- (window-pixel-width) 1270 (window-scroll-bar-width) 1271 (window-right-divider-width) 1272 (* (or (cdr (window-margins)) 1) 1273 (frame-char-width)) 1274 (pcase mode-line-right-align-edge 1275 ('right-margin 1276 (or (cdr (window-margins)) 0)) 1277 ('right-fringe 1278 (or (cadr (window-fringes)) 0)) 1279 (_ 0)) 1280 rhs-width)))))) 1281 rhs-forms)) 1282 (concat "Modeline:\n" 1283 (format " %s\n %s" 1284 (prin1-to-string lhs) 1285 (prin1-to-string rhs)))))) 1286 (put 'doom-modeline-def-modeline 'lisp-indent-function 'defun) 1287 1288 (defun doom-modeline (key) 1289 "Return a mode-line configuration associated with KEY (a symbol). 1290 Throws an error if it doesn't exist." 1291 (let ((fn (intern-soft (format "doom-modeline-format--%s" key)))) 1292 (when (functionp fn) 1293 `(:eval (,fn))))) 1294 1295 (defun doom-modeline-set-modeline (key &optional default) 1296 "Set the modeline format. Does nothing if the modeline KEY doesn't exist. 1297 If DEFAULT is non-nil, set the default mode-line for all buffers." 1298 (when-let ((modeline (doom-modeline key))) 1299 (setf (if default 1300 (default-value 'mode-line-format) 1301 mode-line-format) 1302 (list "%e" modeline)))) 1303 1304 ;; 1305 ;; Helpers 1306 ;; 1307 1308 (defconst doom-modeline-ellipsis 1309 (if (char-displayable-p ?…) "…" "...") 1310 "Ellipsis.") 1311 1312 (defsubst doom-modeline-spc () 1313 "Whitespace." 1314 (propertize " " 'face (doom-modeline-face))) 1315 1316 (defsubst doom-modeline-wspc () 1317 "Wide Whitespace." 1318 (propertize " " 'face (doom-modeline-face))) 1319 1320 (defsubst doom-modeline-vspc () 1321 "Thin whitespace." 1322 (propertize " " 1323 'face (doom-modeline-face) 1324 'display '((space :relative-width 0.5)))) 1325 1326 (defun doom-modeline-face (&optional face inactive-face) 1327 "Display FACE in active window, and INACTIVE-FACE in inactive window. 1328 IF FACE is nil, `mode-line' face will be used. 1329 If INACTIVE-FACE is nil, `mode-line-inactive' face will be used." 1330 (if (doom-modeline--active) 1331 (or (and (facep face) `(:inherit (doom-modeline ,face))) 1332 (and (facep 'mode-line-active) '(:inherit (doom-modeline mode-line-active))) 1333 '(:inherit (doom-modeline mode-line))) 1334 (or (and (facep face) `(:inherit (doom-modeline mode-line-inactive ,face))) 1335 (and (facep inactive-face) `(:inherit (doom-modeline ,inactive-face))) 1336 '(:inherit (doom-modeline mode-line-inactive))))) 1337 1338 (defun doom-modeline-string-pixel-width (str) 1339 "Return the width of STR in pixels." 1340 (if (fboundp 'string-pixel-width) 1341 (string-pixel-width str) 1342 (* (string-width str) (window-font-width nil 'mode-line) 1343 (if (display-graphic-p) 1.05 1.0)))) 1344 1345 (defun doom-modeline--font-height () 1346 "Calculate the actual char height of the mode-line." 1347 (let ((height (face-attribute 'mode-line :height)) 1348 (char-height (window-font-height nil 'mode-line))) 1349 (round 1350 (* 1.0 (cond ((integerp height) (/ height 10)) 1351 ((floatp height) (* height char-height)) 1352 (t char-height)))))) 1353 1354 (defun doom-modeline--original-value (sym) 1355 "Return the original value for SYM, if any. 1356 1357 If SYM has an original value, return it in a list. Return nil 1358 otherwise." 1359 (let* ((orig-val-expr (get sym 'standard-value))) 1360 (when (consp orig-val-expr) 1361 (ignore-errors 1362 (list 1363 (eval (car orig-val-expr))))))) 1364 1365 (defun doom-modeline-add-variable-watcher (symbol watch-function) 1366 "Cause WATCH-FUNCTION to be called when SYMBOL is set if possible. 1367 1368 See docs of `add-variable-watcher'." 1369 (when (fboundp 'add-variable-watcher) 1370 (add-variable-watcher symbol watch-function))) 1371 1372 (defun doom-modeline-propertize-icon (icon &optional face) 1373 "Propertize the ICON with the specified FACE. 1374 1375 The face should be the first attribute, or the font family may be overridden. 1376 So convert the face \":family XXX :height XXX :inherit XXX\" to 1377 \":inherit XXX :family XXX :height XXX\". 1378 See https://github.com/seagle0128/doom-modeline/issues/301." 1379 (when icon 1380 (if (doom-modeline-icon-displayable-p) 1381 (when-let ((props (get-text-property 0 'face icon))) 1382 (when (listp props) 1383 (cl-destructuring-bind (&key family height inherit &allow-other-keys) props 1384 (propertize icon 'face `(:inherit (doom-modeline ,(or face inherit props)) 1385 :family ,(or family "") 1386 :height ,(or height 1.0)))))) 1387 (propertize icon 'face `(:inherit (doom-modeline ,face)))))) 1388 1389 (defun doom-modeline-icon (icon-set icon-name unicode text &rest args) 1390 "Display icon of ICON-NAME with ARGS in mode-line. 1391 1392 ICON-SET includes `ipsicon', `octicon', `pomicon', `powerline', `faicon', 1393 `wicon', `sucicon', `devicon', `codicon', `flicon' and `mdicon', etc. 1394 UNICODE is the unicode char fallback. TEXT is the ASCII char fallback. 1395 ARGS is same as `nerd-icons-octicon' and others." 1396 (let ((face `(:inherit (doom-modeline 1397 ,(or (plist-get args :face) 'mode-line))))) 1398 (cond 1399 ;; Icon 1400 ((and (doom-modeline-icon-displayable-p) 1401 icon-name 1402 (not (string-empty-p icon-name))) 1403 (if-let* ((func (nerd-icons--function-name icon-set)) 1404 (icon (and (fboundp func) 1405 (apply func icon-name args)))) 1406 (doom-modeline-propertize-icon icon face) 1407 "")) 1408 ;; Unicode fallback 1409 ((and doom-modeline-unicode-fallback 1410 unicode 1411 (not (string-empty-p unicode)) 1412 (char-displayable-p (string-to-char unicode))) 1413 (propertize unicode 'face face)) 1414 ;; ASCII text 1415 (text 1416 (propertize text 'face face)) 1417 ;; Fallback 1418 (t "")))) 1419 1420 (defun doom-modeline-icon-for-buffer () 1421 "Get the formatted icon for the current buffer." 1422 (nerd-icons-icon-for-buffer)) 1423 1424 (defun doom-modeline-display-icon (icon) 1425 "Display ICON in mode-line." 1426 (if (doom-modeline--active) 1427 icon 1428 (doom-modeline-propertize-icon icon 'mode-line-inactive))) 1429 1430 (defun doom-modeline-display-text (text) 1431 "Display TEXT in mode-line." 1432 (if (doom-modeline--active) 1433 text 1434 (propertize text 'face `(:inherit (mode-line-inactive 1435 ,(get-text-property 0 'face text)))))) 1436 1437 (defun doom-modeline-vcs-name () 1438 "Display the vcs name." 1439 (and vc-mode (cadr (split-string (string-trim vc-mode) "^[A-Z]+[-:]+")))) 1440 1441 (defun doom-modeline--create-bar-image (face width height) 1442 "Create the bar image. 1443 1444 Use FACE for the bar, WIDTH and HEIGHT are the image size in pixels." 1445 (when (and (image-type-available-p 'pbm) 1446 (numberp width) (> width 0) 1447 (numberp height) (> height 0)) 1448 (propertize 1449 " " 'display 1450 (let ((color (or (face-background face nil t) "None"))) 1451 (ignore-errors 1452 (create-image 1453 (concat (format "P1\n%i %i\n" width height) 1454 (make-string (* width height) ?1) 1455 "\n") 1456 'pbm t :scale 1 :foreground color :ascent 'center)))))) 1457 1458 (defun doom-modeline--create-hud-image 1459 (face1 face2 width height top-margin bottom-margin) 1460 "Create the hud image. 1461 1462 Use FACE1 for the bar, FACE2 for the background. 1463 WIDTH and HEIGHT are the image size in pixels. 1464 TOP-MARGIN and BOTTOM-MARGIN are the size of the margin above and below the bar, 1465 respectively." 1466 (when (and (display-graphic-p) 1467 (image-type-available-p 'pbm) 1468 (numberp width) (> width 0) 1469 (numberp height) (> height 0)) 1470 (let ((min-height (min height doom-modeline-hud-min-height))) 1471 (unless (> (- height top-margin bottom-margin) min-height) 1472 (let ((margin (- height min-height))) 1473 (setq top-margin (/ (* margin top-margin) (+ top-margin bottom-margin)) 1474 bottom-margin (- margin top-margin))))) 1475 (propertize 1476 " " 'display 1477 (let ((color1 (or (face-background face1 nil t) "None")) 1478 (color2 (or (face-background face2 nil t) "None"))) 1479 (create-image 1480 (concat 1481 (format "P1\n%i %i\n" width height) 1482 (make-string (* top-margin width) ?0) 1483 (make-string (* (- height top-margin bottom-margin) width) ?1) 1484 (make-string (* bottom-margin width) ?0) 1485 "\n") 1486 'pbm t :foreground color1 :background color2 :ascent 'center))))) 1487 1488 ;; Check whether `window-total-width' is smaller than the limit 1489 (defun doom-modeline-window-size-change-function (&rest _) 1490 "Function for `window-size-change-functions'." 1491 (setq doom-modeline--limited-width-p 1492 (cond 1493 ((integerp doom-modeline-window-width-limit) 1494 (<= (window-total-width) doom-modeline-window-width-limit)) 1495 ((floatp doom-modeline-window-width-limit) 1496 (<= (/ (window-total-width) (frame-width) 1.0) 1497 doom-modeline-window-width-limit))))) 1498 1499 (add-hook 'after-revert-hook #'doom-modeline-window-size-change-function) 1500 (add-hook 'buffer-list-update-hook #'doom-modeline-window-size-change-function) 1501 (add-hook 'window-size-change-functions #'doom-modeline-window-size-change-function) 1502 1503 (defvar-local doom-modeline--project-root nil) 1504 (defun doom-modeline--project-root () 1505 "Get the path to the project root. 1506 Return nil if no project was found." 1507 (or doom-modeline--project-root 1508 (setq doom-modeline--project-root 1509 (cond 1510 ((and (memq doom-modeline-project-detection '(auto ffip)) 1511 (fboundp 'ffip-project-root)) 1512 (let ((inhibit-message t)) 1513 (ffip-project-root))) 1514 ((and (memq doom-modeline-project-detection '(auto projectile)) 1515 (bound-and-true-p projectile-mode)) 1516 (projectile-project-root)) 1517 ((and (memq doom-modeline-project-detection '(auto project)) 1518 (fboundp 'project-current)) 1519 (when-let ((project (project-current))) 1520 (expand-file-name 1521 (if (fboundp 'project-root) 1522 (project-root project) 1523 (car (with-no-warnings 1524 (project-roots project))))))))))) 1525 1526 (doom-modeline-add-variable-watcher 1527 'doom-modeline-project-detection 1528 (lambda (_sym val op _where) 1529 (when (eq op 'set) 1530 (setq doom-modeline-project-detection val) 1531 (dolist (buf (buffer-list)) 1532 (with-current-buffer buf 1533 (setq doom-modeline--project-root nil) 1534 (and buffer-file-name (revert-buffer t t))))))) 1535 1536 (defun doom-modeline-project-p () 1537 "Check if the file is in a project." 1538 (doom-modeline--project-root)) 1539 1540 (defun doom-modeline-project-root () 1541 "Get the path to the root of your project. 1542 Return `default-directory' if no project was found." 1543 (abbreviate-file-name 1544 (or (doom-modeline--project-root) default-directory))) 1545 1546 (defun doom-modeline--format-buffer-file-name () 1547 "Get and format the buffer file name." 1548 (let ((buffer-file-name (file-local-name 1549 (or (buffer-file-name (buffer-base-buffer)) "")))) 1550 (or (and doom-modeline-buffer-file-name-function 1551 (funcall doom-modeline-buffer-file-name-function buffer-file-name)) 1552 buffer-file-name))) 1553 1554 (defun doom-modeline--format-buffer-file-truename (b-f-n) 1555 "Get and format buffer file truename via B-F-N." 1556 (let ((buffer-file-truename (file-local-name 1557 (or (file-truename b-f-n) "")))) 1558 (or (and doom-modeline-buffer-file-truename-function 1559 (funcall doom-modeline-buffer-file-truename-function buffer-file-truename)) 1560 buffer-file-truename))) 1561 1562 (defun doom-modeline-buffer-file-name () 1563 "Propertize file name based on `doom-modeline-buffer-file-name-style'." 1564 (let* ((buffer-file-name (doom-modeline--format-buffer-file-name)) 1565 (buffer-file-truename (doom-modeline--format-buffer-file-truename buffer-file-name)) 1566 (file-name 1567 (pcase doom-modeline-buffer-file-name-style 1568 ('auto 1569 (if (doom-modeline-project-p) 1570 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide) 1571 (propertize "%b" 'face 'doom-modeline-buffer-file))) 1572 ('truncate-upto-project 1573 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink)) 1574 ('truncate-from-project 1575 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil 'shrink)) 1576 ('truncate-with-project 1577 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide)) 1578 ('truncate-except-project 1579 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink)) 1580 ('truncate-upto-root 1581 (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename)) 1582 ('truncate-all 1583 (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename t)) 1584 ('truncate-nil 1585 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename)) 1586 ('relative-to-project 1587 (doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename)) 1588 ('relative-from-project 1589 (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide)) 1590 ('file-name 1591 (propertize (file-name-nondirectory buffer-file-name) 1592 'face 'doom-modeline-buffer-file)) 1593 ('file-name-with-project 1594 (format "%s|%s" 1595 (propertize (file-name-nondirectory 1596 (directory-file-name (file-local-name (doom-modeline-project-root)))) 1597 'face 'doom-modeline-project-dir) 1598 (propertize (file-name-nondirectory buffer-file-name) 1599 'face 'doom-modeline-buffer-file))) 1600 ((or 'buffer-name _) 1601 (propertize "%b" 'face 'doom-modeline-buffer-file))))) 1602 (propertize (if (string-empty-p file-name) 1603 (propertize "%b" 'face 'doom-modeline-buffer-file) 1604 file-name) 1605 'mouse-face 'mode-line-highlight 1606 'help-echo (concat buffer-file-truename 1607 (unless (string= (file-name-nondirectory buffer-file-truename) 1608 (buffer-name)) 1609 (concat "\n" (buffer-name))) 1610 "\nmouse-1: Previous buffer\nmouse-3: Next buffer") 1611 'local-map mode-line-buffer-identification-keymap))) 1612 1613 (defun doom-modeline--buffer-file-name-truncate (file-path true-file-path &optional truncate-tail) 1614 "Propertize file name that truncates every dir along path. 1615 1616 If TRUNCATE-TAIL is t also truncate the parent directory of the file." 1617 (let ((dirs (shrink-path-prompt (file-name-directory true-file-path)))) 1618 (if (null dirs) 1619 (propertize "%b" 'face 'doom-modeline-buffer-file) 1620 (let ((dirname (car dirs)) 1621 (basename (cdr dirs))) 1622 (concat (propertize (concat dirname 1623 (if truncate-tail (substring basename 0 1) basename) 1624 "/") 1625 'face 'doom-modeline-project-root-dir) 1626 (propertize (file-name-nondirectory file-path) 1627 'face 'doom-modeline-buffer-file)))))) 1628 1629 (defun doom-modeline--buffer-file-name-relative (_file-path true-file-path &optional include-project) 1630 "Propertize file name showing directories relative to project's root only. 1631 1632 If INCLUDE-PROJECT is non-nil, the project path will be included." 1633 (let ((root (file-local-name (doom-modeline-project-root)))) 1634 (if (null root) 1635 (propertize "%b" 'face 'doom-modeline-buffer-file) 1636 (let ((relative-dirs (file-relative-name (file-name-directory true-file-path) 1637 (if include-project (concat root "../") root)))) 1638 (and (equal "./" relative-dirs) (setq relative-dirs "")) 1639 (concat (propertize relative-dirs 'face 'doom-modeline-buffer-path) 1640 (propertize (file-name-nondirectory true-file-path) 1641 'face 'doom-modeline-buffer-file)))))) 1642 1643 (defun doom-modeline--buffer-file-name (file-path 1644 true-file-path 1645 &optional 1646 truncate-project-root-parent 1647 truncate-project-relative-path 1648 hide-project-root-parent) 1649 "Propertize buffer name given by FILE-PATH or TRUE-FILE-PATH. 1650 1651 If TRUNCATE-PROJECT-ROOT-PARENT is non-nil will be saved by truncating project 1652 root parent down fish-shell style. 1653 1654 Example: 1655 ~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el 1656 1657 If TRUNCATE-PROJECT-RELATIVE-PATH is non-nil will be saved by truncating project 1658 relative path down fish-shell style. 1659 1660 Example: 1661 ~/Projects/FOSS/emacs/lisp/comint.el => ~/Projects/FOSS/emacs/l/comint.el 1662 1663 If HIDE-PROJECT-ROOT-PARENT is non-nil will hide project root parent. 1664 1665 Example: 1666 ~/Projects/FOSS/emacs/lisp/comint.el => emacs/lisp/comint.el" 1667 (let ((project-root (file-local-name (doom-modeline-project-root)))) 1668 (concat 1669 ;; Project root parent 1670 (unless hide-project-root-parent 1671 (when-let (root-path-parent 1672 (file-name-directory (directory-file-name project-root))) 1673 (propertize 1674 (if (and truncate-project-root-parent 1675 (not (string-empty-p root-path-parent)) 1676 (not (string= root-path-parent "/"))) 1677 (shrink-path--dirs-internal root-path-parent t) 1678 (abbreviate-file-name root-path-parent)) 1679 'face 'doom-modeline-project-parent-dir))) 1680 ;; Project directory 1681 (propertize 1682 (concat (file-name-nondirectory (directory-file-name project-root)) "/") 1683 'face 'doom-modeline-project-dir) 1684 ;; relative path 1685 (propertize 1686 (when-let (relative-path (file-relative-name 1687 (or (file-name-directory 1688 (if doom-modeline-buffer-file-true-name 1689 true-file-path file-path)) 1690 "./") 1691 project-root)) 1692 (if (string= relative-path "./") 1693 "" 1694 (if truncate-project-relative-path 1695 (substring (shrink-path--dirs-internal relative-path t) 1) 1696 relative-path))) 1697 'face 'doom-modeline-buffer-path) 1698 ;; File name 1699 (propertize (file-name-nondirectory file-path) 1700 'face 'doom-modeline-buffer-file)))) 1701 1702 (provide 'doom-modeline-core) 1703 1704 ;;; doom-modeline-core.el ends here