config

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

doom-modeline-core.el (62169B)


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