config

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

doom-modeline-core.el (63223B)


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