config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

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