config

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

doom-modeline-segments.el (138081B)


      1 ;;; doom-modeline-segments.el --- The segments 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 segments for doom-modeline.
     25 ;; Use `doom-modeline-def-segment' to create a new segment.
     26 ;;
     27 
     28 ;;; Code:
     29 
     30 (require 'doom-modeline-core)
     31 (require 'doom-modeline-env)
     32 (eval-when-compile
     33   (require 'cl-lib)
     34   (require 'seq)
     35   (require 'subr-x))
     36 
     37 
     38 ;;
     39 ;; Externals
     40 ;;
     41 
     42 (defvar Info-current-file)
     43 (defvar Info-current-node)
     44 (defvar Info-mode-line-node-keymap)
     45 (defvar anzu--cached-count)
     46 (defvar anzu--current-position)
     47 (defvar anzu--overflow-p)
     48 (defvar anzu--state)
     49 (defvar anzu--total-matched)
     50 (defvar anzu-cons-mode-line-p)
     51 (defvar aw-keys)
     52 (defvar battery-echo-area-format)
     53 (defvar battery-load-critical)
     54 (defvar battery-mode-line-format)
     55 (defvar battery-mode-line-limit)
     56 (defvar battery-status-function)
     57 (defvar boon-command-state)
     58 (defvar boon-insert-state)
     59 (defvar boon-off-state)
     60 (defvar boon-special-state)
     61 (defvar display-time-string)
     62 (defvar edebug-execution-mode)
     63 (defvar eglot--managed-mode)
     64 (defvar eglot-menu)
     65 (defvar eglot-menu-string)
     66 (defvar eglot-server-menu)
     67 (defvar erc-modified-channels-alist)
     68 (defvar evil-ex-active-highlights-alist)
     69 (defvar evil-ex-argument)
     70 (defvar evil-ex-range)
     71 (defvar evil-mc-frozen)
     72 (defvar evil-state)
     73 (defvar evil-visual-beginning)
     74 (defvar evil-visual-end)
     75 (defvar evil-visual-selection)
     76 (defvar flycheck--automatically-enabled-checkers)
     77 (defvar flycheck-current-errors)
     78 (defvar flycheck-mode-menu-map)
     79 (defvar flymake--mode-line-format)
     80 (defvar flymake--state)
     81 (defvar flymake-menu)
     82 (defvar gnus-newsrc-alist)
     83 (defvar gnus-newsrc-hashtb)
     84 (defvar grip--process)
     85 (defvar helm--mode-line-display-prefarg)
     86 (defvar iedit-occurrences-overlays)
     87 (defvar kele-menu-map)
     88 (defvar meow--indicator)
     89 (defvar minions-mode-line-lighter)
     90 (defvar minions-mode-line-minor-modes-map)
     91 (defvar mlscroll-right-align)
     92 (defvar mu4e--modeline-item)
     93 (defvar mu4e-alert-mode-line)
     94 (defvar mu4e-alert-modeline-formatter)
     95 (defvar mu4e-modeline-mode)
     96 (defvar objed--obj-state)
     97 (defvar objed--object)
     98 (defvar objed-modeline-setup-func)
     99 (defvar persp-nil-name)
    100 (defvar phi-replace--mode-line-format)
    101 (defvar phi-search--overlays)
    102 (defvar phi-search--selection)
    103 (defvar phi-search-mode-line-format)
    104 (defvar projectile-mode-map)
    105 (defvar rcirc-activity)
    106 (defvar symbol-overlay-keywords-alist)
    107 (defvar symbol-overlay-temp-symbol)
    108 (defvar text-scale-mode-amount)
    109 (defvar tracking-buffers)
    110 (defvar winum-auto-setup-mode-line)
    111 (defvar xah-fly-insert-state-p)
    112 
    113 (declare-function anzu--reset-status "ext:anzu")
    114 (declare-function anzu--where-is-here "ext:anzu")
    115 (declare-function async-inject-variables "ext:async")
    116 (declare-function async-start "ext:async")
    117 (declare-function avy-traverse "ext:avy")
    118 (declare-function avy-tree "ext:avy")
    119 (declare-function aw-update "ext:ace-window")
    120 (declare-function aw-window-list "ext:ace-window")
    121 (declare-function battery-format "battery")
    122 (declare-function battery-update "battery")
    123 (declare-function boon-modeline-string "ext:boon")
    124 (declare-function boon-state-string "ext:boon")
    125 (declare-function cider--connection-info "ext:cider")
    126 (declare-function cider-connected-p "ext:cider")
    127 (declare-function cider-current-repl "ext:cider")
    128 (declare-function cider-jack-in "ext:cider")
    129 (declare-function cider-quit "ext:cider")
    130 (declare-function citre-mode "ext:citre-basic-tools")
    131 (declare-function compilation-goto-in-progress-buffer "compile")
    132 (declare-function dap--cur-session "ext:dap-mode")
    133 (declare-function dap--debug-session-name "ext:dap-mode")
    134 (declare-function dap--debug-session-state "ext:dap-mode")
    135 (declare-function dap--session-running "ext:dap-mode")
    136 (declare-function dap-debug-recent "ext:dap-mode")
    137 (declare-function dap-disconnect "ext:dap-mode")
    138 (declare-function dap-hydra "ext:dap-hydra")
    139 (declare-function edebug-help "edebug")
    140 (declare-function edebug-next-mode "edebug")
    141 (declare-function edebug-stop "edebug")
    142 (declare-function eglot--major-modes "eglot")
    143 (declare-function eglot--server-info "eglot" t t)
    144 (declare-function eglot-current-server "eglot")
    145 (declare-function eglot-managed-p "eglot")
    146 (declare-function eglot-project-nickname "eglot" t t)
    147 (declare-function erc-switch-to-buffer "erc")
    148 (declare-function erc-track-switch-buffer "erc-track")
    149 (declare-function evil-delimited-arguments "ext:evil-common")
    150 (declare-function evil-emacs-state-p "ext:evil-states" t t)
    151 (declare-function evil-force-normal-state "ext:evil-commands" t t)
    152 (declare-function evil-insert-state-p "ext:evil-states" t t)
    153 (declare-function evil-motion-state-p "ext:evil-states" t t)
    154 (declare-function evil-normal-state-p "ext:evil-states" t t)
    155 (declare-function evil-operator-state-p "ext:evil-states" t t)
    156 (declare-function evil-replace-state-p "ext:evil-states" t t)
    157 (declare-function evil-state-property "ext:evil-common")
    158 (declare-function evil-visual-state-p "ext:evil-states" t t)
    159 (declare-function eyebrowse--get "ext:eyebrowse")
    160 (declare-function face-remap-remove-relative "face-remap")
    161 (declare-function fancy-narrow-active-p "ext:fancy-narrow")
    162 (declare-function flycheck-buffer "ext:flycheck")
    163 (declare-function flycheck-count-errors "ext:flycheck")
    164 (declare-function flycheck-error-level-compilation-level "ext:flycheck")
    165 (declare-function flycheck-list-errors "ext:flycheck")
    166 (declare-function flycheck-next-error "ext:flycheck")
    167 (declare-function flycheck-previous-error "ext:flycheck")
    168 (declare-function flymake--diag-type "flymake" t t)
    169 (declare-function flymake--handle-report "flymake")
    170 (declare-function flymake--lookup-type-property "flymake")
    171 (declare-function flymake--state-diags "flymake" t t)
    172 (declare-function flymake-disabled-backends "flymake")
    173 (declare-function flymake-goto-next-error "flymake")
    174 (declare-function flymake-goto-prev-error "flymake")
    175 (declare-function flymake-reporting-backends "flymake")
    176 (declare-function flymake-running-backends "flymake")
    177 (declare-function flymake-show-buffer-diagnostics "flymake")
    178 (declare-function flymake-show-buffer-diagnostics "flymake")
    179 (declare-function flymake-start "flymake")
    180 (declare-function follow-all-followers "follow")
    181 (declare-function gnus-demon-add-handler "gnus-demon")
    182 (declare-function grip--preview-url "ext:grip-mode")
    183 (declare-function grip-browse-preview "ext:grip-mode")
    184 (declare-function grip-restart-preview "ext:grip-mode")
    185 (declare-function grip-stop-preview "ext:grip-mode")
    186 (declare-function helm-candidate-number-at-point "ext:helm-core")
    187 (declare-function helm-get-candidate-number "ext:helm-core")
    188 (declare-function iedit-find-current-occurrence-overlay "ext:iedit-lib")
    189 (declare-function iedit-prev-occurrence "ext:iedit-lib")
    190 (declare-function image-get-display-property "image-mode")
    191 (declare-function jsonrpc--request-continuations "jsonrpc" t t)
    192 (declare-function jsonrpc-last-error "jsonrpc" t t)
    193 (declare-function jsonrpc-name "jsonrpc" t t)
    194 (declare-function kele-current-context-name "ext:kele")
    195 (declare-function kele-current-namespace "ext:kele")
    196 (declare-function lsp--workspace-print "ext:lsp-mode")
    197 (declare-function lsp-describe-session "ext:lsp-mode")
    198 (declare-function lsp-workspace-folders-open "ext:lsp-mode")
    199 (declare-function lsp-workspace-restart "ext:lsp-mode")
    200 (declare-function lsp-workspace-shutdown "ext:lsp-mode")
    201 (declare-function lsp-workspaces "ext:lsp-mode")
    202 (declare-function lv-message "ext:lv")
    203 (declare-function mc/num-cursors "ext:multiple-cursors-core")
    204 (declare-function meow--current-state "ext:meow")
    205 (declare-function meow-beacon-mode-p "ext:meow")
    206 (declare-function meow-insert-mode-p "ext:meow")
    207 (declare-function meow-keypad-mode-p "ext:meow")
    208 (declare-function meow-motion-mode-p "ext:meow")
    209 (declare-function meow-normal-mode-p "ext:meow")
    210 (declare-function minions--prominent-modes "ext:minions")
    211 (declare-function mlscroll-mode-line "ext:mlscroll")
    212 (declare-function mu4e--modeline-string "ext:mu4e-modeline")
    213 (declare-function mu4e-alert-default-mode-line-formatter "ext:mu4e-alert")
    214 (declare-function mu4e-alert-enable-mode-line-display "ext:mu4e-alert")
    215 (declare-function nyan-create "ext:nyan-mode")
    216 (declare-function org-edit-src-save "org-src")
    217 (declare-function parrot-create "ext:parrot")
    218 (declare-function pdf-cache-number-of-pages "ext:pdf-cache" t t)
    219 (declare-function persp-add-buffer "ext:persp-mode")
    220 (declare-function persp-contain-buffer-p "ext:persp-mode")
    221 (declare-function persp-switch "ext:persp-mode")
    222 (declare-function phi-search--initialize "ext:phi-search")
    223 (declare-function poke-line-create "ext:poke-line")
    224 (declare-function popup-create "ext:popup")
    225 (declare-function popup-delete "ext:popup")
    226 (declare-function project-name "project")
    227 (declare-function projectile-project-name "ext:projectile")
    228 (declare-function rcirc-next-active-buffer "rcirc")
    229 (declare-function rcirc-short-buffer-name "rcirc")
    230 (declare-function rcirc-switch-to-server-buffer "rcirc")
    231 (declare-function rcirc-window-configuration-change "rcirc")
    232 (declare-function rime--should-enable-p "ext:rime")
    233 (declare-function rime--should-inline-ascii-p "ext:rime")
    234 (declare-function sml-modeline-create "ext:sml-modeline")
    235 (declare-function svg-circle "svg")
    236 (declare-function svg-create "svg")
    237 (declare-function svg-image "svg")
    238 (declare-function svg-line "svg")
    239 (declare-function symbol-overlay-assoc "ext:symbol-overlay")
    240 (declare-function symbol-overlay-get-list "ext:symbol-overlay")
    241 (declare-function symbol-overlay-get-symbol "ext:symbol-overlay")
    242 (declare-function symbol-overlay-rename "ext:symbol-overlay")
    243 (declare-function tab-bar--current-tab "tab-bar")
    244 (declare-function tab-bar--current-tab-index "tab-bar")
    245 (declare-function tracking-next-buffer "ext:tracking")
    246 (declare-function tracking-previous-buffer "ext:tracking")
    247 (declare-function tracking-shorten "ext:tracking")
    248 (declare-function warning-numeric-level "warnings")
    249 (declare-function window-numbering-clear-mode-line "ext:window-numbering")
    250 (declare-function window-numbering-get-number-string "ext:window-numbering")
    251 (declare-function window-numbering-install-mode-line "ext:window-numbering")
    252 (declare-function winum--clear-mode-line "ext:winum")
    253 (declare-function winum--install-mode-line "ext:winum")
    254 (declare-function winum-get-number-string "ext:winum")
    255 
    256 
    257 
    258 ;;
    259 ;; Buffer information
    260 ;;
    261 
    262 (defvar-local doom-modeline--buffer-file-icon nil)
    263 (defun doom-modeline-update-buffer-file-icon (&rest _)
    264   "Update file icon in mode-line."
    265   (setq doom-modeline--buffer-file-icon
    266         (when (and doom-modeline-major-mode-icon
    267                    (doom-modeline-icon-displayable-p))
    268           (let ((icon (doom-modeline-icon-for-buffer)))
    269             (propertize (if (or (null icon) (symbolp icon))
    270                             (doom-modeline-icon 'faicon "nf-fa-file_o" nil nil
    271                                                 :face 'nerd-icons-dsilver)
    272                           (doom-modeline-propertize-icon icon))
    273                         'help-echo (format "Major-mode: %s" (format-mode-line mode-name)))))))
    274 (add-hook 'find-file-hook #'doom-modeline-update-buffer-file-icon)
    275 (add-hook 'after-change-major-mode-hook #'doom-modeline-update-buffer-file-icon)
    276 (add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-icon)
    277 
    278 (doom-modeline-add-variable-watcher
    279  'doom-modeline-icon
    280  (lambda (_sym val op _where)
    281    (when (eq op 'set)
    282      (setq doom-modeline-icon val)
    283      (dolist (buf (buffer-list))
    284        (with-current-buffer buf
    285          (doom-modeline-update-buffer-file-icon))))))
    286 
    287 (defun doom-modeline-buffer-file-state-icon (icon unicode text face)
    288   "Displays an ICON of buffer state with FACE.
    289 UNICODE and TEXT are the alternatives if it is not applicable.
    290 Uses `nerd-icons-mdicon' to fetch the icon."
    291   (doom-modeline-icon 'mdicon icon unicode text :face face))
    292 
    293 (defvar-local doom-modeline--buffer-file-state-icon nil)
    294 (defun doom-modeline-update-buffer-file-state-icon (&rest _)
    295   "Update the buffer or file state in mode-line."
    296   (setq doom-modeline--buffer-file-state-icon
    297         (when doom-modeline-buffer-state-icon
    298           (ignore-errors
    299             (concat
    300              (cond ((not (or (and (buffer-file-name) (file-remote-p buffer-file-name))
    301                              (verify-visited-file-modtime (current-buffer))))
    302                     (doom-modeline-buffer-file-state-icon
    303                      "nf-md-reload_alert" "âŸŗ" "%1*"
    304                      'doom-modeline-warning))
    305                    (buffer-read-only
    306                     (doom-modeline-buffer-file-state-icon
    307                      "nf-md-lock" "🔒" "%1*"
    308                      'doom-modeline-warning))
    309                    ((and buffer-file-name (buffer-modified-p)
    310                          doom-modeline-buffer-modification-icon)
    311                     (doom-modeline-buffer-file-state-icon
    312                      "nf-md-content_save_edit" "💾" "%1*"
    313                      'doom-modeline-warning))
    314                    ((and buffer-file-name
    315                          ;; Avoid freezing while connection is lost
    316                          (not (file-remote-p buffer-file-name))
    317                          (not (file-exists-p buffer-file-name)))
    318                     (doom-modeline-buffer-file-state-icon
    319                      "nf-md-cancel" "đŸšĢ" "!"
    320                      'doom-modeline-urgent))
    321                    (t ""))
    322              (when (or (buffer-narrowed-p)
    323                        (and (bound-and-true-p fancy-narrow-mode)
    324                             (fancy-narrow-active-p))
    325                        (bound-and-true-p dired-narrow-mode))
    326                (doom-modeline-buffer-file-state-icon
    327                 "nf-md-unfold_less_horizontal" "↕" "><"
    328                 'doom-modeline-warning)))))))
    329 
    330 (defvar-local doom-modeline--buffer-file-name nil)
    331 (defun doom-modeline-update-buffer-file-name (&rest _)
    332   "Update buffer file name in mode-line."
    333   (setq doom-modeline--buffer-file-name
    334         (ignore-errors
    335           (save-match-data
    336             (if buffer-file-name
    337                 (doom-modeline-buffer-file-name)
    338               (propertize "%b"
    339                           'face 'doom-modeline-buffer-file
    340                           'mouse-face 'doom-modeline-highlight
    341                           'help-echo "Buffer name
    342 mouse-1: Previous buffer\nmouse-3: Next buffer"
    343                           'local-map mode-line-buffer-identification-keymap))))))
    344 (add-hook 'find-file-hook #'doom-modeline-update-buffer-file-name)
    345 (add-hook 'after-save-hook #'doom-modeline-update-buffer-file-name)
    346 (add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-name)
    347 (add-hook 'evil-insert-state-exit-hook #'doom-modeline-update-buffer-file-name)
    348 (add-hook 'Info-selection-hook #'doom-modeline-update-buffer-file-name)
    349 (advice-add #'rename-buffer :after #'doom-modeline-update-buffer-file-name)
    350 (advice-add #'set-visited-file-name :after #'doom-modeline-update-buffer-file-name)
    351 (advice-add #'pop-to-buffer :after #'doom-modeline-update-buffer-file-name)
    352 (advice-add #'popup-create :after #'doom-modeline-update-buffer-file-name)
    353 (advice-add #'popup-delete :after #'doom-modeline-update-buffer-file-name)
    354 ;; (advice-add #'primitive-undo :after #'doom-modeline-update-buffer-file-name)
    355 ;; (advice-add #'set-buffer-modified-p :after #'doom-modeline-update-buffer-file-name)
    356 
    357 (with-no-warnings
    358   (if (boundp 'after-focus-change-function)
    359       (progn
    360         (advice-add #'handle-switch-frame :after #'doom-modeline-update-buffer-file-name)
    361         (add-function :after after-focus-change-function #'doom-modeline-update-buffer-file-name))
    362     (progn
    363       (add-hook 'focus-in-hook #'doom-modeline-update-buffer-file-name)
    364       (add-hook 'focus-out-hook #'doom-modeline-update-buffer-file-name))))
    365 
    366 (doom-modeline-add-variable-watcher
    367  'doom-modeline-buffer-file-name-style
    368  (lambda (_sym val op _where)
    369    (when (eq op 'set)
    370      (setq doom-modeline-buffer-file-name-style val)
    371      (dolist (buf (buffer-list))
    372        (with-current-buffer buf
    373          (when buffer-file-name
    374            (doom-modeline-update-buffer-file-name)))))))
    375 
    376 (defsubst doom-modeline--buffer-mode-icon ()
    377   "The icon of the current major mode."
    378   (when (and doom-modeline-icon doom-modeline-major-mode-icon)
    379     (when-let* ((icon (or doom-modeline--buffer-file-icon
    380                           (doom-modeline-update-buffer-file-icon))))
    381       (unless (string-empty-p icon)
    382         (concat
    383          (if doom-modeline-major-mode-color-icon
    384              (doom-modeline-display-icon icon)
    385            (doom-modeline-propertize-icon
    386             icon
    387             (doom-modeline-face)))
    388          (doom-modeline-vspc))))))
    389 
    390 (defsubst doom-modeline--buffer-state-icon ()
    391   "The icon of the current buffer state."
    392   (when doom-modeline-buffer-state-icon
    393     (when-let* ((icon (doom-modeline-update-buffer-file-state-icon)))
    394       (unless (string-empty-p icon)
    395         (concat
    396          (doom-modeline-display-icon icon)
    397          (doom-modeline-vspc))))))
    398 
    399 (defsubst doom-modeline--buffer-simple-name ()
    400   "The buffer simple name."
    401   (propertize "%b"
    402               'face (doom-modeline-face
    403                      (if (and doom-modeline-highlight-modified-buffer-name
    404                               (buffer-modified-p))
    405                          'doom-modeline-buffer-modified
    406                        'doom-modeline-buffer-file))
    407               'mouse-face 'doom-modeline-highlight
    408               'help-echo "Buffer name
    409 mouse-1: Previous buffer\nmouse-3: Next buffer"
    410               'local-map mode-line-buffer-identification-keymap))
    411 
    412 (defsubst doom-modeline--buffer-name ()
    413   "The current buffer name."
    414   (when doom-modeline-buffer-name
    415     (if (and (not (eq doom-modeline-buffer-file-name-style 'file-name))
    416              doom-modeline--limited-width-p)
    417         ;; Only display the buffer name if the window is small, and doesn't
    418         ;; need to respect file-name style.
    419         (doom-modeline--buffer-simple-name)
    420       (when-let* ((name (or doom-modeline--buffer-file-name
    421                             (doom-modeline-update-buffer-file-name))))
    422         ;; Check if the buffer is modified
    423         (if (and doom-modeline-highlight-modified-buffer-name
    424                  (buffer-modified-p))
    425             (propertize name 'face (doom-modeline-face 'doom-modeline-buffer-modified))
    426           (doom-modeline-display-text name))))))
    427 
    428 (doom-modeline-def-segment buffer-info
    429   "Combined information about the current buffer.
    430 
    431 Including the current working directory, the file name, and its state (modified,
    432 read-only or non-existent)."
    433   (concat
    434    (doom-modeline-spc)
    435    (doom-modeline--buffer-mode-icon)
    436    (doom-modeline--buffer-state-icon)
    437    (doom-modeline--buffer-name)))
    438 
    439 (doom-modeline-def-segment buffer-info-simple
    440   "Display only the current buffer's name, but with fontification."
    441   (concat
    442    (doom-modeline-spc)
    443    (doom-modeline--buffer-mode-icon)
    444    (doom-modeline--buffer-state-icon)
    445    (doom-modeline--buffer-simple-name)))
    446 
    447 (doom-modeline-def-segment calc
    448   "Display calculator icons and info."
    449   (concat
    450    (doom-modeline-spc)
    451    (when-let* ((icon (doom-modeline-icon 'faicon "nf-fa-calculator" "🖩" "")))
    452      (concat
    453       (doom-modeline-display-icon icon)
    454       (doom-modeline-vspc)))
    455    (doom-modeline--buffer-simple-name)))
    456 
    457 (doom-modeline-def-segment buffer-default-directory
    458   "Displays `default-directory' with the icon and state.
    459 
    460 This is for special buffers like the scratch buffer where knowing the current
    461 project directory is important."
    462   (let ((face (doom-modeline-face
    463                (if (and buffer-file-name (buffer-modified-p))
    464                    'doom-modeline-buffer-modified
    465                  'doom-modeline-buffer-path))))
    466     (concat
    467      (doom-modeline-spc)
    468      (and doom-modeline-major-mode-icon
    469           (concat
    470            (doom-modeline-icon
    471             'octicon "nf-oct-file_directory_fill" "đŸ–ŋ" "" :face face)
    472            (doom-modeline-vspc)))
    473      (doom-modeline--buffer-state-icon)
    474      (propertize (abbreviate-file-name default-directory) 'face face))))
    475 
    476 (doom-modeline-def-segment buffer-default-directory-simple
    477   "Displays `default-directory'.
    478 
    479 This is for special buffers like the scratch buffer where knowing the current
    480 project directory is important."
    481   (let ((face (doom-modeline-face 'doom-modeline-buffer-path)))
    482     (concat
    483      (doom-modeline-spc)
    484      (and doom-modeline-major-mode-icon
    485           (concat
    486            (doom-modeline-icon
    487             'octicon "nf-oct-file_directory_fill" "đŸ–ŋ" "" :face face)
    488            (doom-modeline-vspc)))
    489      (propertize (abbreviate-file-name default-directory) 'face face))))
    490 
    491 
    492 ;;
    493 ;; Encoding
    494 ;;
    495 
    496 (doom-modeline-def-segment buffer-encoding
    497   "Displays the eol and the encoding style of the buffer."
    498   (when doom-modeline-buffer-encoding
    499     (let ((sep (doom-modeline-spc))
    500           (face (doom-modeline-face))
    501           (mouse-face 'doom-modeline-highlight))
    502       (concat
    503        sep
    504 
    505        ;; eol type
    506        (let ((eol (coding-system-eol-type buffer-file-coding-system)))
    507          (when (or (eq doom-modeline-buffer-encoding t)
    508                    (and (eq doom-modeline-buffer-encoding 'nondefault)
    509                         (not (equal eol doom-modeline-default-eol-type))))
    510            (propertize
    511             (pcase eol
    512               (0 "LF ")
    513               (1 "CRLF ")
    514               (2 "CR ")
    515               (_ ""))
    516             'face face
    517             'mouse-face mouse-face
    518             'help-echo (format "End-of-line style: %s\nmouse-1: Cycle"
    519                                (pcase eol
    520                                  (0 "Unix-style LF")
    521                                  (1 "DOS-style CRLF")
    522                                  (2 "Mac-style CR")
    523                                  (_ "Undecided")))
    524             'local-map (let ((map (make-sparse-keymap)))
    525                          (define-key map [mode-line mouse-1] 'mode-line-change-eol)
    526                          map))))
    527 
    528        ;; coding system
    529        (let* ((sys (coding-system-plist buffer-file-coding-system))
    530               (cat (plist-get sys :category))
    531               (sym (if (memq cat
    532                              '(coding-category-undecided coding-category-utf-8))
    533                        'utf-8
    534                      (plist-get sys :name))))
    535          (when (or (eq doom-modeline-buffer-encoding t)
    536                    (and (eq doom-modeline-buffer-encoding 'nondefault)
    537                         (not (eq cat 'coding-category-undecided))
    538                         (not (eq sym doom-modeline-default-coding-system))))
    539            (propertize
    540             (upcase (symbol-name sym))
    541             'face face
    542             'mouse-face mouse-face
    543             'help-echo 'mode-line-mule-info-help-echo
    544             'local-map mode-line-coding-system-map)))
    545 
    546        sep))))
    547 
    548 
    549 ;;
    550 ;; Indentation
    551 ;;
    552 
    553 (doom-modeline-def-segment indent-info
    554   "Displays the indentation information."
    555   (when doom-modeline-indent-info
    556     (let ((do-propertize
    557            (lambda (mode size)
    558              (propertize
    559               (format " %s %d " mode size)
    560               'face (doom-modeline-face)))))
    561       (if indent-tabs-mode
    562           (funcall do-propertize "TAB" tab-width)
    563         (let ((lookup-var
    564                (seq-find (lambda (var)
    565                            (and var (boundp var) (symbol-value var)))
    566                          (cdr (assoc major-mode doom-modeline-indent-alist)) nil)))
    567           (funcall do-propertize "SPC"
    568                    (if lookup-var
    569                        (symbol-value lookup-var)
    570                      tab-width)))))))
    571 
    572 ;;
    573 ;; Remote host
    574 ;;
    575 
    576 (doom-modeline-def-segment remote-host
    577   "Hostname for remote buffers."
    578   (when default-directory
    579     (when-let* ((host (file-remote-p default-directory 'host)))
    580       (propertize
    581        (concat "@" host)
    582        'face (doom-modeline-face 'doom-modeline-host)))))
    583 
    584 
    585 ;;
    586 ;; Major mode
    587 ;;
    588 
    589 (doom-modeline-def-segment major-mode
    590   "The major mode, including environment and text-scale info."
    591   (let ((sep (doom-modeline-spc))
    592         (face (doom-modeline-face 'doom-modeline-buffer-major-mode)))
    593     (concat
    594      sep
    595      (propertize (concat
    596                   (format-mode-line
    597                    (or (and (boundp 'delighted-modes)
    598                             (cadr (assq major-mode delighted-modes)))
    599                        mode-name))
    600                   (when (and doom-modeline-env-version doom-modeline-env--version)
    601                     (format " %s" doom-modeline-env--version)))
    602                  'help-echo "Major mode\n\
    603 mouse-1: Display major mode menu\n\
    604 mouse-2: Show help for major mode\n\
    605 mouse-3: Toggle minor modes"
    606                  'face face
    607                  'mouse-face 'doom-modeline-highlight
    608                  'local-map mode-line-major-mode-keymap)
    609      (and (boundp 'text-scale-mode-amount)
    610           (/= text-scale-mode-amount 0)
    611           (propertize
    612            (format
    613             (if (> text-scale-mode-amount 0) " (%+d)" " (%-d)")
    614             text-scale-mode-amount)
    615            'face face))
    616      sep)))
    617 
    618 
    619 ;;
    620 ;; Process
    621 ;;
    622 
    623 (doom-modeline-def-segment process
    624   "The process info."
    625   (doom-modeline-display-text
    626    (format-mode-line mode-line-process)))
    627 
    628 
    629 ;;
    630 ;; Minor modes
    631 ;;
    632 
    633 (doom-modeline-def-segment minor-modes
    634   (when doom-modeline-minor-modes
    635     (let ((sep (doom-modeline-spc))
    636           (face (doom-modeline-face 'doom-modeline-buffer-minor-mode))
    637           (mouse-face 'doom-modeline-highlight)
    638           (help-echo "Minor mode
    639   mouse-1: Display minor mode menu
    640   mouse-2: Show help for minor mode
    641   mouse-3: Toggle minor modes"))
    642       (if (bound-and-true-p minions-mode)
    643           `((:propertize ("" ,(minions--prominent-modes))
    644              face ,face
    645 		     mouse-face ,mouse-face
    646 		     help-echo ,help-echo
    647 		     local-map ,mode-line-minor-mode-keymap)
    648             ,sep
    649             (:propertize ("" ,(doom-modeline-icon 'octicon "nf-oct-gear" "⚙"
    650                                                   minions-mode-line-lighter
    651                                                   :face face))
    652              mouse-face ,mouse-face
    653              help-echo "Minions
    654 mouse-1: Display minor modes menu"
    655              local-map ,minions-mode-line-minor-modes-map)
    656             ,sep)
    657         `((:propertize ("" minor-mode-alist)
    658            face ,face
    659            mouse-face ,mouse-face
    660            help-echo ,help-echo
    661            local-map ,mode-line-minor-mode-keymap)
    662           ,sep)))))
    663 
    664 
    665 ;;
    666 ;; VCS
    667 ;;
    668 
    669 (defun doom-modeline-vcs-icon (icon &optional unicode text face)
    670   "Displays the vcs ICON with FACE and VOFFSET.
    671 
    672 UNICODE and TEXT are fallbacks.
    673 Uses `nerd-icons-octicon' to fetch the icon."
    674   (doom-modeline-icon 'devicon (and doom-modeline-vcs-icon icon)
    675                       unicode text :face face))
    676 
    677 (defvar-local doom-modeline--vcs nil)
    678 (defun doom-modeline-update-vcs (&rest _)
    679   "Update vcs state in mode-line."
    680   (setq doom-modeline--vcs
    681         (when (and vc-mode buffer-file-name)
    682           (let* ((backend (vc-backend buffer-file-name))
    683                  (state (vc-state buffer-file-name backend))
    684                  (icon (cond ((memq state '(edited added))
    685                               (doom-modeline-vcs-icon "nf-dev-git_compare" "🔃" "*" 'doom-modeline-info))
    686                              ((eq state 'needs-merge)
    687                               (doom-modeline-vcs-icon "nf-dev-git_merge" "🔀" "?" 'doom-modeline-info))
    688                              ((eq state 'needs-update)
    689                               (doom-modeline-vcs-icon "nf-dev-git_pull_request" "âŦ‡" "!" 'doom-modeline-warning))
    690                              ((memq state '(removed conflict unregistered))
    691                               (doom-modeline-icon 'octicon "nf-oct-alert" "⚠" "!" :face 'doom-modeline-urgent))
    692                              (t (doom-modeline-vcs-icon "nf-dev-git_branch" "" "@" 'doom-modeline-info))))
    693                  (str (or (and vc-display-status
    694                                (functionp doom-modeline-vcs-display-function)
    695                                (funcall doom-modeline-vcs-display-function))
    696                           ""))
    697                  (face (cond ((eq state 'needs-update)
    698                               '(doom-modeline-warning bold))
    699                              ((memq state '(removed conflict unregistered))
    700                               '(doom-modeline-urgent bold))
    701                              (t '(doom-modeline-info bold))))
    702                  (text (propertize (if (length> str doom-modeline-vcs-max-length)
    703                                        (concat
    704                                         (substring str 0 (- doom-modeline-vcs-max-length 3))
    705                                         doom-modeline-ellipsis)
    706                                      str)
    707                                    'face face)))
    708             `((icon . ,icon) (text . ,text))))))
    709 (add-hook 'find-file-hook #'doom-modeline-update-vcs)
    710 (add-hook 'after-save-hook #'doom-modeline-update-vcs)
    711 (advice-add #'vc-refresh-state :after #'doom-modeline-update-vcs)
    712 
    713 (doom-modeline-add-variable-watcher
    714  'doom-modeline-icon
    715  (lambda (_sym val op _where)
    716    (when (eq op 'set)
    717      (setq doom-modeline-icon val)
    718      (dolist (buf (buffer-list))
    719        (with-current-buffer buf
    720          (doom-modeline-update-vcs))))))
    721 
    722 (doom-modeline-add-variable-watcher
    723  'doom-modeline-unicode-fallback
    724  (lambda (_sym val op _where)
    725    (when (eq op 'set)
    726      (setq doom-modeline-unicode-fallback val)
    727      (dolist (buf (buffer-list))
    728        (with-current-buffer buf
    729          (doom-modeline-update-vcs))))))
    730 
    731 (doom-modeline-add-variable-watcher
    732  'doom-modeline-vcs-icon
    733  (lambda (_sym val op _where)
    734    (when (eq op 'set)
    735      (setq doom-modeline-vcs-icon val)
    736      (dolist (buf (buffer-list))
    737        (with-current-buffer buf
    738          (doom-modeline-update-vcs))))))
    739 
    740 (doom-modeline-add-variable-watcher
    741  'vc-display-status
    742  (lambda (_sym val op _where)
    743    (when (eq op 'set)
    744      (setq vc-display-status val)
    745      (dolist (buf (buffer-list))
    746        (with-current-buffer buf
    747          (doom-modeline-update-vcs))))))
    748 
    749 (doom-modeline-def-segment vcs
    750   "Displays the current branch, colored based on its state."
    751   (when doom-modeline--vcs
    752     (let-alist doom-modeline--vcs
    753       (let ((sep (doom-modeline-spc))
    754             (vsep (doom-modeline-vspc)))
    755         (concat sep
    756                 (propertize (concat
    757                              (doom-modeline-display-icon .icon)
    758                              vsep
    759                              (doom-modeline-display-text .text))
    760                             'help-echo (get-text-property 1 'help-echo vc-mode)
    761                             'mouse-face 'doom-modeline-highlight
    762                             'local-map (get-text-property 1 'local-map vc-mode))
    763                 sep)))))
    764 
    765 
    766 ;;
    767 ;; Check
    768 ;;
    769 
    770 (defun doom-modeline-check-icon (icon unicode text face)
    771   "Displays the check ICON with FACE.
    772 
    773 UNICODE and TEXT are fallbacks.
    774 Uses `nerd-icons-mdicon' to fetch the icon."
    775   (doom-modeline-icon 'mdicon (and doom-modeline-check-icon icon)
    776                       unicode text :face face))
    777 
    778 (defun doom-modeline-check-text (text &optional face)
    779   "Displays the check TEXT with FACE."
    780   (propertize text 'face (or face 'mode-line)))
    781 
    782 ;; Flycheck
    783 
    784 (defun doom-modeline--flycheck-count-errors ()
    785   "Count the number of ERRORS, grouped by level.
    786 
    787 Return an alist, where each ITEM is a cons cell whose `car' is an
    788 error level, and whose `cdr' is the number of errors of that
    789 level."
    790   (let ((info 0) (warning 0) (error 0))
    791     (mapc
    792      (lambda (item)
    793        (let ((count (cdr item)))
    794          (pcase (flycheck-error-level-compilation-level (car item))
    795            (0 (cl-incf info count))
    796            (1 (cl-incf warning count))
    797            (2 (cl-incf error count)))))
    798      (flycheck-count-errors flycheck-current-errors))
    799     `((info . ,info) (warning . ,warning) (error . ,error))))
    800 
    801 (defvar-local doom-modeline--flycheck nil)
    802 (defun doom-modeline-update-flycheck (&optional status)
    803   "Update flycheck via STATUS."
    804   (setq doom-modeline--flycheck
    805         (let-alist (doom-modeline--flycheck-count-errors)
    806           (let* ((vsep (doom-modeline-vspc))
    807                  (seg (if doom-modeline-check-simple-format
    808                           (let ((count (+ .error .warning .info)))
    809                             (pcase status
    810                               ('finished    (if (> count 0)
    811                                                 (let ((face (if (> .error 0) 'doom-modeline-urgent 'doom-modeline-warning)))
    812                                                   (concat
    813                                                    (doom-modeline-check-icon "nf-md-alert_circle_outline" "⚠" "!" face)
    814                                                    vsep
    815                                                    (doom-modeline-check-text (number-to-string count) face)))
    816                                               (doom-modeline-check-icon "nf-md-check_circle_outline" "✔" "*" 'doom-modeline-info)))
    817                               ('running     (concat
    818                                              (doom-modeline-check-icon "nf-md-timer_sand" "âŗ" "*" 'doom-modeline-debug)
    819                                              (when (> count 0)
    820                                                (concat
    821                                                 vsep
    822                                                 (doom-modeline-check-text (number-to-string count) 'doom-modeline-debug)))))
    823                               ('no-checker  (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "-" 'doom-modeline-debug))
    824                               ('errored     (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-urgent))
    825                               ('interrupted (doom-modeline-check-icon "nf-md-pause_circle_outline" "âĻˇ" "." 'doom-modeline-debug))
    826                               ('suspicious  (doom-modeline-check-icon "nf-md-file_question_outline" "❓" "?" 'doom-modeline-debug))
    827                               (_ "")))
    828                         (concat (doom-modeline-check-icon "nf-md-close_circle_outline" "⎞" "!" 'doom-modeline-urgent)
    829                                 vsep
    830                                 (doom-modeline-check-text (number-to-string .error) 'doom-modeline-urgent)
    831                                 vsep
    832                                 (doom-modeline-check-icon "nf-md-alert_outline" "⚠" "!" 'doom-modeline-warning)
    833                                 vsep
    834                                 (doom-modeline-check-text (number-to-string .warning) 'doom-modeline-warning)
    835                                 vsep
    836                                 (doom-modeline-check-icon "nf-md-information_outline" "🛈" "!" 'doom-modeline-info)
    837                                 vsep
    838                                 (doom-modeline-check-text (number-to-string .info) 'doom-modeline-info)))))
    839             (propertize seg
    840                         'help-echo (concat "Flycheck\n"
    841                                            (pcase status
    842                                              ('finished (format "error: %d, warning: %d, info: %d" .error .warning .info))
    843                                              ('running "Checking...")
    844                                              ('no-checker "No Checker")
    845                                              ('errored "Error")
    846                                              ('interrupted "Interrupted")
    847                                              ('suspicious "Suspicious"))
    848                                            "\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode")
    849                         'mouse-face 'doom-modeline-highlight
    850                         'local-map (let ((map (make-sparse-keymap)))
    851                                      (define-key map [mode-line down-mouse-1]
    852                                        flycheck-mode-menu-map)
    853                                      (define-key map [mode-line mouse-2]
    854                                        (lambda ()
    855                                          (interactive)
    856                                          (describe-function 'flycheck-mode)))
    857                                      map))))))
    858 (add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck)
    859 (add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck)
    860 
    861 (doom-modeline-add-variable-watcher
    862  'doom-modeline-icon
    863  (lambda (_sym val op _where)
    864    (when (eq op 'set)
    865      (setq doom-modeline-icon val)
    866      (dolist (buf (buffer-list))
    867        (with-current-buffer buf
    868          (when (bound-and-true-p flycheck-mode)
    869            (doom-modeline-update-flycheck)))))))
    870 
    871 (doom-modeline-add-variable-watcher
    872  'doom-modeline-check-icon
    873  (lambda (_sym val op _where)
    874    (when (eq op 'set)
    875      (setq doom-modeline-check-icon val)
    876      (dolist (buf (buffer-list))
    877        (with-current-buffer buf
    878          (when (bound-and-true-p flycheck-mode)
    879            (doom-modeline-update-flycheck)))))))
    880 
    881 (doom-modeline-add-variable-watcher
    882  'doom-modeline-unicode-fallback
    883  (lambda (_sym val op _where)
    884    (when (eq op 'set)
    885      (setq doom-modeline-unicode-fallback val)
    886      (dolist (buf (buffer-list))
    887        (with-current-buffer buf
    888          (when (bound-and-true-p flycheck-mode)
    889            (doom-modeline-update-flycheck)))))))
    890 
    891 (doom-modeline-add-variable-watcher
    892  'doom-modeline-check-simple-format
    893  (lambda (_sym val op _where)
    894    (when (eq op 'set)
    895      (setq doom-modeline-check-simple-format val)
    896      (dolist (buf (buffer-list))
    897        (with-current-buffer buf
    898          (when (bound-and-true-p flycheck-mode)
    899            (doom-modeline-update-flycheck)))))))
    900 
    901 ;; Flymake
    902 
    903 ;; Compatibility
    904 ;; @see https://github.com/emacs-mirror/emacs/commit/6e100869012da9244679696634cab6b9cac96303.
    905 (with-eval-after-load 'flymake
    906   (unless (boundp 'flymake--state)
    907     (defvaralias 'flymake--state 'flymake--backend-state))
    908   (unless (fboundp 'flymake--state-diags)
    909     (defalias 'flymake--state-diags 'flymake--backend-state-diags)))
    910 
    911 (defun doom-modeline--flymake-count-errors ()
    912   "Count the number of ERRORS, grouped by level."
    913   (let ((warning-level (warning-numeric-level :warning))
    914         (note-level (warning-numeric-level :debug))
    915         (note 0) (warning 0) (error 0))
    916     (maphash (lambda (_b state)
    917                (cl-loop
    918                 with diags = (flymake--state-diags state)
    919                 for diag in diags do
    920                 (let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity
    921                                                                (warning-numeric-level :error))))
    922                   (cond ((> severity warning-level) (cl-incf error))
    923                         ((> severity note-level) (cl-incf warning))
    924                         (t (cl-incf note))))))
    925              flymake--state)
    926     `((note . ,note) (warning . ,warning) (error . ,error))))
    927 
    928 (defvar-local doom-modeline--flymake nil)
    929 (defun doom-modeline-update-flymake (&rest _)
    930   "Update flymake."
    931   (setq doom-modeline--flymake
    932         (let* ((known (hash-table-keys flymake--state))
    933                (running (flymake-running-backends))
    934                (disabled (flymake-disabled-backends))
    935                (reported (flymake-reporting-backends))
    936                (all-disabled (and disabled (null running)))
    937                (some-waiting (cl-set-difference running reported)))
    938           (let-alist (doom-modeline--flymake-count-errors)
    939             (let* ((vsep (doom-modeline-vspc))
    940                    (seg (if doom-modeline-check-simple-format
    941                             (let ((count (+ .error .warning .note)))
    942                               (cond
    943                                (some-waiting (concat
    944                                               (doom-modeline-check-icon "nf-md-timer_sand" "âŗ" "*" 'doom-modeline-debug)
    945                                               (when (> count 0)
    946                                                 (concat
    947                                                  vsep
    948                                                  (doom-modeline-check-text (number-to-string count) 'doom-modeline-debug)))))
    949                                ((null known) (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-urgent))
    950                                (all-disabled (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-warning))
    951                                (t (if (> count 0)
    952                                       (let ((face (cond ((> .error 0) 'doom-modeline-urgent)
    953                                                         ((> .warning 0) 'doom-modeline-warning)
    954                                                         (t 'doom-modeline-info))))
    955                                         (concat
    956                                          (doom-modeline-check-icon "nf-md-alert_circle_outline" "⚠" "!" face)
    957                                          vsep
    958                                          (doom-modeline-check-text (number-to-string count) face)))
    959                                     (doom-modeline-check-icon "nf-md-check_circle_outline" "✔" "*" 'doom-modeline-info)))))
    960                           (concat
    961                            (doom-modeline-check-icon "nf-md-close_circle_outline" "⎞" "!" 'doom-modeline-urgent)
    962                            vsep
    963                            (doom-modeline-check-text (number-to-string .error) 'doom-modeline-urgent)
    964                            vsep
    965                            (doom-modeline-check-icon "nf-md-alert_outline" "⚠" "!" 'doom-modeline-warning)
    966                            vsep
    967                            (doom-modeline-check-text (number-to-string .warning) 'doom-modeline-warning)
    968                            vsep
    969                            (doom-modeline-check-icon "nf-md-information_outline" "🛈" "!" 'doom-modeline-info)
    970                            vsep
    971                            (doom-modeline-check-text (number-to-string .note) 'doom-modeline-info)))))
    972               (propertize
    973                seg
    974                'help-echo (concat
    975                            "Flymake\n"
    976                            (cond (some-waiting "Checking...")
    977                                  ((null known) "No Checker")
    978                                  (all-disabled "All Checkers Disabled")
    979                                  (t (format "%d/%d backends running\nerror: %d, warning: %d, note: %d"
    980                                             (length running) (length known) .error .warning .note)))
    981                            "\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode")
    982                'mouse-face 'doom-modeline-highlight
    983                'local-map (let ((map (make-sparse-keymap)))
    984                             (define-key map [mode-line down-mouse-1]
    985                               flymake-menu)
    986                             (define-key map [mode-line mouse-2]
    987                               (lambda ()
    988                                 (interactive)
    989                                 (describe-function 'flymake-mode)))
    990                             map)))))))
    991 (advice-add #'flymake--handle-report :after #'doom-modeline-update-flymake)
    992 
    993 (doom-modeline-add-variable-watcher
    994  'doom-modeline-icon
    995  (lambda (_sym val op _where)
    996    (when (eq op 'set)
    997      (setq doom-modeline-icon val)
    998      (dolist (buf (buffer-list))
    999        (with-current-buffer buf
   1000          (when (bound-and-true-p flymake-mode)
   1001            (doom-modeline-update-flymake)))))))
   1002 
   1003 (doom-modeline-add-variable-watcher
   1004  'doom-modeline-check-icon
   1005  (lambda (_sym val op _where)
   1006    (when (eq op 'set)
   1007      (setq doom-modeline-check-icon val)
   1008      (dolist (buf (buffer-list))
   1009        (with-current-buffer buf
   1010          (when (bound-and-true-p flymake-mode)
   1011            (doom-modeline-update-flymake)))))))
   1012 
   1013 (doom-modeline-add-variable-watcher
   1014  'doom-modeline-unicode-fallback
   1015  (lambda (_sym val op _where)
   1016    (when (eq op 'set)
   1017      (setq doom-modeline-unicode-fallback val)
   1018      (dolist (buf (buffer-list))
   1019        (with-current-buffer buf
   1020          (when (bound-and-true-p flymake-mode)
   1021            (doom-modeline-update-flymake)))))))
   1022 
   1023 (doom-modeline-add-variable-watcher
   1024  'doom-modeline-check-simple-format
   1025  (lambda (_sym val op _where)
   1026    (when (eq op 'set)
   1027      (setq doom-modeline-check-simple-format val)
   1028      (dolist (buf (buffer-list))
   1029        (with-current-buffer buf
   1030          (when (bound-and-true-p flymake-mode)
   1031            (doom-modeline-update-flymake)))))))
   1032 
   1033 (doom-modeline-def-segment check
   1034   "Displays color-coded error status in the current buffer with pretty icons."
   1035   (when-let* ((sep (doom-modeline-spc))
   1036               (vsep (doom-modeline-vspc))
   1037               (seg (cond
   1038                     ((and (bound-and-true-p flymake-mode)
   1039                           (bound-and-true-p flymake--state)) ; only support 26+
   1040                      doom-modeline--flymake)
   1041                     ((and (bound-and-true-p flycheck-mode)
   1042                           (bound-and-true-p flycheck--automatically-enabled-checkers))
   1043                      doom-modeline--flycheck))))
   1044     (concat
   1045      sep
   1046      (let ((str))
   1047        (dolist (s (split-string seg " "))
   1048          (setq str
   1049                (concat str
   1050                        (if (string-match-p "^[0-9]+$" s)
   1051                            (concat vsep
   1052                                    (doom-modeline-display-text s)
   1053                                    vsep)
   1054                          (doom-modeline-display-icon s)))))
   1055        (propertize str
   1056                    'help-echo (get-text-property 0 'help-echo seg)
   1057                    'mouse-face 'doom-modeline-highlight
   1058                    'local-map (get-text-property 0 'local-map seg)))
   1059      sep)))
   1060 
   1061 
   1062 ;;
   1063 ;; Word Count
   1064 ;;
   1065 
   1066 (doom-modeline-def-segment word-count
   1067   "The buffer word count.
   1068 Displayed when in a major mode in `doom-modeline-continuous-word-count-modes'.
   1069 Respects `doom-modeline-enable-word-count'."
   1070   (when (and doom-modeline-enable-word-count
   1071              (member major-mode doom-modeline-continuous-word-count-modes))
   1072     (propertize (format " %dW" (count-words (point-min) (point-max)))
   1073                 'face (doom-modeline-face))))
   1074 
   1075 
   1076 ;;
   1077 ;; Selection
   1078 ;;
   1079 
   1080 (defsubst doom-modeline-column (pos)
   1081   "Get the column of the position `POS'."
   1082   (save-excursion (goto-char pos)
   1083                   (current-column)))
   1084 
   1085 (doom-modeline-def-segment selection-info
   1086   "Information about the current selection.
   1087 
   1088 Such as how many characters and lines are selected, or the NxM dimensions of a
   1089 block selection."
   1090   (when (and (or mark-active (and (bound-and-true-p evil-local-mode)
   1091                                   (eq evil-state 'visual)))
   1092              (doom-modeline--active))
   1093     (cl-destructuring-bind (beg . end)
   1094       (if (and (bound-and-true-p evil-local-mode) (eq evil-state 'visual))
   1095           (cons evil-visual-beginning evil-visual-end)
   1096         (cons (region-beginning) (region-end)))
   1097       (propertize
   1098        (let ((lines (count-lines beg (min end (point-max)))))
   1099          (concat
   1100           " "
   1101           (cond ((or (bound-and-true-p rectangle-mark-mode)
   1102                      (and (bound-and-true-p evil-visual-selection)
   1103                           (eq 'block evil-visual-selection)))
   1104                  (let ((cols (abs (- (doom-modeline-column end)
   1105                                      (doom-modeline-column beg)))))
   1106                    (format "%dx%dB" lines cols)))
   1107                 ((and (bound-and-true-p evil-visual-selection)
   1108                       (eq evil-visual-selection 'line))
   1109                  (format "%dL" lines))
   1110                 ((> lines 1)
   1111                  (format "%dC %dL" (- end beg) lines))
   1112                 (t
   1113                  (format "%dC" (- end beg))))
   1114           (when doom-modeline-enable-word-count
   1115             (format " %dW" (count-words beg end)))
   1116           " "))
   1117        'face 'doom-modeline-emphasis))))
   1118 
   1119 
   1120 ;;
   1121 ;; Matches (macro, anzu, evil-substitute, iedit, symbol-overlay and multi-cursors)
   1122 ;;
   1123 
   1124 (defsubst doom-modeline--macro-recording ()
   1125   "Display current Emacs or evil macro being recorded."
   1126   (when (and (doom-modeline--active)
   1127              (or defining-kbd-macro executing-kbd-macro))
   1128     (let ((sep (propertize " " 'face 'doom-modeline-panel))
   1129           (vsep (propertize " " 'face
   1130                             '(:inherit (doom-modeline-panel variable-pitch))))
   1131           (macro-name (if (bound-and-true-p evil-this-macro)
   1132                           (format " @%s "
   1133                                   (char-to-string evil-this-macro))
   1134                         "Macro")))
   1135       (concat
   1136        sep
   1137        (if doom-modeline-always-show-macro-register
   1138            (propertize macro-name 'face 'doom-modeline-panel)
   1139          (concat
   1140           (doom-modeline-icon 'mdicon "nf-md-record" "●"
   1141                               macro-name
   1142                               :face '(:inherit (doom-modeline-urgent doom-modeline-panel))
   1143                               :v-adjust 0.15)
   1144           vsep
   1145           (doom-modeline-icon 'mdicon "nf-md-menu_right" "â–ļ" ">"
   1146                               :face 'doom-modeline-panel
   1147                               :v-adjust 0.15)))
   1148        sep))))
   1149 
   1150 ;; `anzu' and `evil-anzu' expose current/total state that can be displayed in the
   1151 ;; mode-line.
   1152 (defun doom-modeline-fix-anzu-count (positions here)
   1153   "Calulate anzu count via POSITIONS and HERE."
   1154   (cl-loop with i = 0
   1155            for (start . end) in positions
   1156            do (cl-incf i)
   1157            when (and (>= here start) (<= here end))
   1158            return i
   1159            finally return 0))
   1160 
   1161 (advice-add #'anzu--where-is-here :override #'doom-modeline-fix-anzu-count)
   1162 
   1163 (setq anzu-cons-mode-line-p nil) ; manage modeline segment ourselves
   1164 ;; Ensure anzu state is cleared when searches & iedit are done
   1165 (with-eval-after-load 'anzu
   1166   (add-hook 'isearch-mode-end-hook #'anzu--reset-status t)
   1167   (add-hook 'iedit-mode-end-hook #'anzu--reset-status)
   1168   (advice-add #'evil-force-normal-state :after #'anzu--reset-status)
   1169   ;; Fix matches segment mirroring across all buffers
   1170   (mapc #'make-variable-buffer-local
   1171         '(anzu--total-matched
   1172           anzu--current-position anzu--state anzu--cached-count
   1173           anzu--cached-positions anzu--last-command
   1174           anzu--last-isearch-string anzu--overflow-p)))
   1175 
   1176 (defsubst doom-modeline--anzu ()
   1177   "Show the match index and total number thereof.
   1178 Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with
   1179 `evil-search'."
   1180   (when (and (bound-and-true-p anzu--state)
   1181              (not (bound-and-true-p iedit-mode)))
   1182     (propertize
   1183      (let ((here anzu--current-position)
   1184            (total anzu--total-matched))
   1185        (cond ((eq anzu--state 'replace-query)
   1186               (format " %d replace " anzu--cached-count))
   1187              ((eq anzu--state 'replace)
   1188               (format " %d/%d " here total))
   1189              (anzu--overflow-p
   1190               (format " %s+ " total))
   1191              (t
   1192               (format " %s/%d " here total))))
   1193      'face (doom-modeline-face 'doom-modeline-panel))))
   1194 
   1195 (defsubst doom-modeline--evil-substitute ()
   1196   "Show number of matches for `evil-ex' in real time.
   1197 The number of matches contains substitutions and highlightings."
   1198   (when (and (bound-and-true-p evil-local-mode)
   1199              (or (assq 'evil-ex-substitute evil-ex-active-highlights-alist)
   1200                  (assq 'evil-ex-global-match evil-ex-active-highlights-alist)
   1201                  (assq 'evil-ex-buffer-match evil-ex-active-highlights-alist)))
   1202     (propertize
   1203      (let ((range (if evil-ex-range
   1204                       (cons (car evil-ex-range) (cadr evil-ex-range))
   1205                     (cons (line-beginning-position) (line-end-position))))
   1206            (pattern (car-safe (evil-delimited-arguments evil-ex-argument 2))))
   1207        (if pattern
   1208            (format " %s matches " (how-many pattern (car range) (cdr range)))
   1209          " - "))
   1210      'face (doom-modeline-face 'doom-modeline-panel))))
   1211 
   1212 (defun doom-modeline-themes--overlay-sort (a b)
   1213   "Sort overlay A and B."
   1214   (< (overlay-start a) (overlay-start b)))
   1215 
   1216 (defsubst doom-modeline--iedit ()
   1217   "Show the number of iedit regions matches + what match you're on."
   1218   (when (and (bound-and-true-p iedit-mode)
   1219              (bound-and-true-p iedit-occurrences-overlays))
   1220     (propertize
   1221      (let ((this-oc (or (let ((inhibit-message t))
   1222                           (iedit-find-current-occurrence-overlay))
   1223                         (save-excursion (iedit-prev-occurrence)
   1224                                         (iedit-find-current-occurrence-overlay))))
   1225            (length (length iedit-occurrences-overlays)))
   1226        (format " %s/%d "
   1227                (if this-oc
   1228                    (- length
   1229                       (length (memq this-oc (sort (append iedit-occurrences-overlays nil)
   1230                                                   #'doom-modeline-themes--overlay-sort)))
   1231                       -1)
   1232                  "-")
   1233                length))
   1234      'face (doom-modeline-face 'doom-modeline-panel))))
   1235 
   1236 (defsubst doom-modeline--symbol-overlay ()
   1237   "Show the number of matches for symbol overlay."
   1238   (when (and (doom-modeline--active)
   1239              (bound-and-true-p symbol-overlay-keywords-alist)
   1240              (not (bound-and-true-p symbol-overlay-temp-symbol))
   1241              (not (bound-and-true-p iedit-mode)))
   1242     (let* ((keyword (symbol-overlay-assoc (symbol-overlay-get-symbol t)))
   1243            (symbol (car keyword))
   1244            (before (symbol-overlay-get-list -1 symbol))
   1245            (after (symbol-overlay-get-list 1 symbol))
   1246            (count (length before)))
   1247       (if (symbol-overlay-assoc symbol)
   1248           (propertize
   1249            (format (concat  " %d/%d " (and (cadr keyword) "in scope "))
   1250                    (+ count 1)
   1251                    (+ count (length after)))
   1252            'face (doom-modeline-face 'doom-modeline-panel))))))
   1253 
   1254 (defsubst doom-modeline--multiple-cursors ()
   1255   "Show the number of multiple cursors."
   1256   (cl-destructuring-bind (count . face)
   1257     (cond ((bound-and-true-p multiple-cursors-mode)
   1258            (cons (mc/num-cursors)
   1259                  (doom-modeline-face 'doom-modeline-panel)))
   1260           ((bound-and-true-p evil-mc-cursor-list)
   1261            (cons (length evil-mc-cursor-list)
   1262                  (doom-modeline-face (if evil-mc-frozen
   1263                                          'doom-modeline-bar
   1264                                        'doom-modeline-panel))))
   1265           ((cons nil nil)))
   1266     (when count
   1267       (concat (propertize " " 'face face)
   1268               (if (doom-modeline-icon-displayable-p)
   1269                   (doom-modeline-icon 'faicon "nf-fa-i_cursor" "" "" :face face)
   1270                 (propertize "I"
   1271                             'face `(:inherit ,face :height 1.4 :weight normal)
   1272                             'display '(raise -0.1)))
   1273               (propertize " "
   1274                           'face `(:inherit (variable-pitch ,face)))
   1275               (propertize (format "%d " count)
   1276                           'face face)))))
   1277 
   1278 (defsubst doom-modeline--phi-search ()
   1279   "Show the number of matches for `phi-search' and `phi-replace'."
   1280   (when (and (doom-modeline--active)
   1281              (bound-and-true-p phi-search--overlays))
   1282     (let ((total (length phi-search--overlays))
   1283           (selection phi-search--selection))
   1284       (when selection
   1285         (propertize
   1286          (format " %d/%d " (1+ selection) total)
   1287          'face (doom-modeline-face 'doom-modeline-panel))))))
   1288 
   1289 (defun doom-modeline--override-phi-search (orig-fun &rest args)
   1290   "Override the mode-line of `phi-search' and `phi-replace'.
   1291 Apply ORIG-FUN with ARGS."
   1292   (if (bound-and-true-p doom-modeline-mode)
   1293       (apply orig-fun mode-line-format (cdr args))
   1294     (apply orig-fun args)))
   1295 (advice-add #'phi-search--initialize :around #'doom-modeline--override-phi-search)
   1296 
   1297 (defsubst doom-modeline--buffer-size ()
   1298   "Show buffer size."
   1299   (when size-indication-mode
   1300     (let ((sep (doom-modeline-spc)))
   1301       (concat sep
   1302               (propertize "%I"
   1303                           'face (doom-modeline-face)
   1304                           'help-echo "Buffer size
   1305 mouse-1: Display Line and Column Mode Menu"
   1306                           'mouse-face 'doom-modeline-highlight
   1307                           'local-map mode-line-column-line-number-mode-map)
   1308               sep))))
   1309 
   1310 (doom-modeline-def-segment matches
   1311   "Displays matches.
   1312 
   1313 Including:
   1314 1. the currently recording macro, 2. A current/total for the
   1315 current search term (with `anzu'), 3. The number of substitutions being
   1316 conducted with `evil-ex-substitute', and/or 4. The number of active `iedit'
   1317 regions, 5. The current/total for the highlight term (with `symbol-overlay'),
   1318 6. The number of active `multiple-cursors'."
   1319   (let ((meta (concat (doom-modeline--macro-recording)
   1320                       (doom-modeline--anzu)
   1321                       (doom-modeline--phi-search)
   1322                       (doom-modeline--evil-substitute)
   1323                       (doom-modeline--iedit)
   1324                       (doom-modeline--symbol-overlay)
   1325                       (doom-modeline--multiple-cursors))))
   1326     (or (and (not (string-empty-p meta)) meta)
   1327         (doom-modeline--buffer-size))))
   1328 
   1329 (doom-modeline-def-segment buffer-size
   1330   "Display buffer size."
   1331   (doom-modeline--buffer-size))
   1332 
   1333 ;;
   1334 ;; Media
   1335 ;;
   1336 
   1337 (doom-modeline-def-segment media-info
   1338   "Metadata regarding the current file, such as dimensions for images."
   1339   ;; TODO: Include other information
   1340   (cond ((eq major-mode 'image-mode)
   1341          (cl-destructuring-bind (width . height)
   1342            (when (fboundp 'image-size)
   1343              (image-size (image-get-display-property) :pixels))
   1344            (format "  %dx%d  " width height)))))
   1345 
   1346 
   1347 ;;
   1348 ;; Bars
   1349 ;;
   1350 
   1351 (defvar doom-modeline--bar-active nil)
   1352 (defvar doom-modeline--bar-inactive nil)
   1353 
   1354 (defsubst doom-modeline--bar ()
   1355   "The default bar regulates the height of the mode-line in GUI."
   1356   (unless (and doom-modeline--bar-active doom-modeline--bar-inactive)
   1357     (let ((width doom-modeline-bar-width)
   1358           (height (max doom-modeline-height (doom-modeline--font-height))))
   1359       (setq doom-modeline--bar-active
   1360             (doom-modeline--create-bar-image 'doom-modeline-bar width height)
   1361             doom-modeline--bar-inactive
   1362             (doom-modeline--create-bar-image
   1363              'doom-modeline-bar-inactive width height))))
   1364   (if (doom-modeline--active)
   1365       doom-modeline--bar-active
   1366     doom-modeline--bar-inactive))
   1367 
   1368 (defun doom-modeline-refresh-bars ()
   1369   "Refresh mode-line bars on next redraw."
   1370   (setq doom-modeline--bar-active nil
   1371         doom-modeline--bar-inactive nil))
   1372 
   1373 (cl-defstruct doom-modeline--hud-cache active inactive top-margin bottom-margin)
   1374 
   1375 (defsubst doom-modeline--hud ()
   1376   "Powerline's hud segment reimplemented in the style of Doom's bar segment."
   1377   (let* ((ws (window-start))
   1378          (we (window-end))
   1379          (bs (buffer-size))
   1380          (height (max doom-modeline-height (doom-modeline--font-height)))
   1381          (top-margin (if (zerop bs)
   1382                          0
   1383                        (/ (* height (1- ws)) bs)))
   1384          (bottom-margin (if (zerop bs)
   1385                             0
   1386                           (max 0 (/ (* height (- bs we 1)) bs))))
   1387          (cache (or (window-parameter nil 'doom-modeline--hud-cache)
   1388                     (set-window-parameter
   1389                      nil
   1390                      'doom-modeline--hud-cache
   1391                      (make-doom-modeline--hud-cache)))))
   1392     (unless (and (doom-modeline--hud-cache-active cache)
   1393                  (doom-modeline--hud-cache-inactive cache)
   1394                  (= top-margin (doom-modeline--hud-cache-top-margin cache))
   1395                  (= bottom-margin
   1396                     (doom-modeline--hud-cache-bottom-margin cache)))
   1397       (setf (doom-modeline--hud-cache-active cache)
   1398             (doom-modeline--create-hud-image
   1399              'doom-modeline-bar 'default doom-modeline-bar-width
   1400              height top-margin bottom-margin)
   1401             (doom-modeline--hud-cache-inactive cache)
   1402             (doom-modeline--create-hud-image
   1403              'doom-modeline-bar-inactive 'default doom-modeline-bar-width
   1404              height top-margin bottom-margin)
   1405             (doom-modeline--hud-cache-top-margin cache) top-margin
   1406             (doom-modeline--hud-cache-bottom-margin cache) bottom-margin))
   1407     (if (doom-modeline--active)
   1408         (doom-modeline--hud-cache-active cache)
   1409       (doom-modeline--hud-cache-inactive cache))))
   1410 
   1411 (defun doom-modeline-invalidate-huds ()
   1412   "Invalidate all cached hud images."
   1413   (dolist (frame (frame-list))
   1414     (dolist (window (window-list frame))
   1415       (set-window-parameter window 'doom-modeline--hud-cache nil))))
   1416 
   1417 (doom-modeline-add-variable-watcher
   1418  'doom-modeline-height
   1419  (lambda (_sym val op _where)
   1420    (when (and (eq op 'set) (integerp val))
   1421      (doom-modeline-refresh-bars)
   1422      (doom-modeline-invalidate-huds))))
   1423 
   1424 (doom-modeline-add-variable-watcher
   1425  'doom-modeline-bar-width
   1426  (lambda (_sym val op _where)
   1427    (when (and (eq op 'set) (integerp val))
   1428      (doom-modeline-refresh-bars)
   1429      (doom-modeline-invalidate-huds))))
   1430 
   1431 (doom-modeline-add-variable-watcher
   1432  'doom-modeline-icon
   1433  (lambda (_sym _val op _where)
   1434    (when (eq op 'set)
   1435      (doom-modeline-refresh-bars)
   1436      (doom-modeline-invalidate-huds))))
   1437 
   1438 (doom-modeline-add-variable-watcher
   1439  'doom-modeline-unicode-fallback
   1440  (lambda (_sym _val op _where)
   1441    (when (eq op 'set)
   1442      (doom-modeline-refresh-bars)
   1443      (doom-modeline-invalidate-huds))))
   1444 
   1445 (add-hook 'window-configuration-change-hook #'doom-modeline-refresh-bars)
   1446 (add-hook 'window-configuration-change-hook #'doom-modeline-invalidate-huds)
   1447 
   1448 (doom-modeline-def-segment bar
   1449   "The bar regulates the height of the `doom-modeline' in GUI."
   1450   (when (display-graphic-p)
   1451     (concat
   1452      (if doom-modeline-hud
   1453          (doom-modeline--hud)
   1454        (doom-modeline--bar))
   1455      (doom-modeline-spc))))
   1456 
   1457 (doom-modeline-def-segment hud
   1458   "Powerline's hud segment reimplemented in the style of bar segment."
   1459   (when (display-graphic-p)
   1460     (concat
   1461      (doom-modeline--hud)
   1462      (doom-modeline-spc))))
   1463 
   1464 
   1465 ;;
   1466 ;; Window number
   1467 ;;
   1468 
   1469 ;; HACK: `ace-window-display-mode' should respect the ignore buffers.
   1470 (defun doom-modeline-aw-update ()
   1471   "Update ace-window-path window parameter for all windows.
   1472 Ensure all windows are labeled so the user can select a specific
   1473 one. The ignored buffers are excluded unless `aw-ignore-on' is nil."
   1474   (let ((ignore-window-parameters t))
   1475     (avy-traverse
   1476      (avy-tree (aw-window-list) aw-keys)
   1477      (lambda (path leaf)
   1478        (set-window-parameter
   1479         leaf 'ace-window-path
   1480         (propertize
   1481          (apply #'string (reverse path))
   1482          'face 'aw-mode-line-face))))))
   1483 (advice-add #'aw-update :override #'doom-modeline-aw-update)
   1484 
   1485 ;; Remove original window number of `ace-window-display-mode'.
   1486 (add-hook 'ace-window-display-mode-hook
   1487           (lambda ()
   1488             (setq-default mode-line-format
   1489                           (assq-delete-all 'ace-window-display-mode
   1490                                            (default-value 'mode-line-format)))))
   1491 
   1492 (advice-add #'window-numbering-install-mode-line :override #'ignore)
   1493 (advice-add #'window-numbering-clear-mode-line :override #'ignore)
   1494 (advice-add #'winum--install-mode-line :override #'ignore)
   1495 (advice-add #'winum--clear-mode-line :override #'ignore)
   1496 
   1497 (doom-modeline-def-segment window-number
   1498   "The current window number."
   1499   (let ((num (cond
   1500               ((bound-and-true-p ace-window-display-mode)
   1501                (aw-update)
   1502                (window-parameter (selected-window) 'ace-window-path))
   1503               ((bound-and-true-p winum-mode)
   1504                (setq winum-auto-setup-mode-line nil)
   1505                (winum-get-number-string))
   1506               ((bound-and-true-p window-numbering-mode)
   1507                (window-numbering-get-number-string))
   1508               (t ""))))
   1509     (when (and (length> num 0)
   1510                (length> (cl-mapcan
   1511                          (lambda (frame)
   1512                            ;; Exclude minibuffer, tooltip and child frames
   1513                            (unless (or (and (fboundp 'frame-parent) (frame-parent frame))
   1514                                        (string= (frame-parameter frame 'name)
   1515                                                 (alist-get 'name (bound-and-true-p tooltip-frame-parameters))))
   1516                              (window-list frame 'never)))
   1517                          (visible-frame-list))
   1518                         1))
   1519       (propertize (format " %s " num)
   1520                   'face (doom-modeline-face 'doom-modeline-buffer-major-mode)))))
   1521 
   1522 ;;
   1523 ;; Project
   1524 ;;
   1525 
   1526 (defvar doom-modeline-project-map
   1527   (cond
   1528    ((and (memq doom-modeline-project-detection '(auto projectile))
   1529          (bound-and-true-p projectile-mode))
   1530     projectile-mode-map)
   1531    ((and (memq doom-modeline-project-detection '(auto project))
   1532          (fboundp 'project-current))
   1533     (let ((map (make-sparse-keymap)))
   1534       (define-key map [mode-line down-mouse-1]
   1535         (bound-and-true-p menu-bar-project-item))
   1536       map))))
   1537 
   1538 (defvar-local doom-modeline--project-name nil)
   1539 (defun doom-modeline-project-name ()
   1540   "Get the project name."
   1541   (or doom-modeline--project-name
   1542       (setq doom-modeline--project-name
   1543             (let ((name (cond
   1544                          ((and (memq doom-modeline-project-detection '(auto projectile))
   1545                                (bound-and-true-p projectile-mode))
   1546                           (projectile-project-name))
   1547                          ((and (memq doom-modeline-project-detection '(auto project))
   1548                                (fboundp 'project-current))
   1549                           (when-let* ((project (project-current)))
   1550                             (project-name project))))))
   1551               (if (and name (not (string-empty-p name)))
   1552                   (format " [%s] " name)
   1553                 "")))))
   1554 
   1555 (doom-modeline-add-variable-watcher
   1556  'doom-modeline-project-detection
   1557  (lambda (_sym val op _where)
   1558    (when (eq op 'set)
   1559      (setq doom-modeline-project-detection val)
   1560      (dolist (buf (buffer-list))
   1561        (with-current-buffer buf
   1562          (setq doom-modeline--project-name nil)
   1563          (and buffer-file-name (revert-buffer t t)))))))
   1564 
   1565 (doom-modeline-def-segment project-name
   1566   "The current perspective name."
   1567   (when (and doom-modeline-project-name
   1568              (doom-modeline--segment-visible 'project-name))
   1569     (propertize (doom-modeline-project-name)
   1570                 'face (doom-modeline-face 'doom-modeline-project-name)
   1571                 'mouse-face 'mode-line-highlight
   1572                 'help-echo "mouse-1: Project menu"
   1573                 'local-map doom-modeline-project-map)))
   1574 
   1575 
   1576 ;;
   1577 ;; Workspace
   1578 ;;
   1579 
   1580 (doom-modeline-def-segment workspace-name
   1581   "The current workspace name or number.
   1582 Requires `eyebrowse-mode' to be enabled or `tab-bar-mode' tabs to be created."
   1583   (when doom-modeline-workspace-name
   1584     (when-let*
   1585         ((name (cond
   1586                 ((and (bound-and-true-p eyebrowse-mode)
   1587                       (length> (eyebrowse--get 'window-configs) 1))
   1588                  (setq mode-line-misc-info
   1589                        (assq-delete-all 'eyebrowse-mode mode-line-misc-info))
   1590                  (when-let*
   1591                      ((num (eyebrowse--get 'current-slot))
   1592                       (tag (nth 2 (assoc num (eyebrowse--get 'window-configs)))))
   1593                    (if (length> tag 0) tag (int-to-string num))))
   1594                 ((and (fboundp 'tab-bar-mode)
   1595                       (length> (frame-parameter nil 'tabs) 1))
   1596                  (let* ((current-tab (tab-bar--current-tab))
   1597                         (tab-index (tab-bar--current-tab-index))
   1598                         (explicit-name (alist-get 'explicit-name current-tab))
   1599                         (tab-name (alist-get 'name current-tab)))
   1600                    (if explicit-name tab-name (+ 1 tab-index)))))))
   1601       (unless (string-empty-p name)
   1602         (propertize (format " %s " name)
   1603                     'face (doom-modeline-face 'doom-modeline-workspace-name))))))
   1604 
   1605 
   1606 ;;
   1607 ;; Perspective
   1608 ;;
   1609 
   1610 (defvar-local doom-modeline--persp-name nil)
   1611 (defun doom-modeline-update-persp-name (&rest _)
   1612   "Update perspective name in mode-line."
   1613   (setq doom-modeline--persp-name
   1614         ;; Support `persp-mode', while not support `perspective'
   1615         (when (and doom-modeline-persp-name
   1616                    (bound-and-true-p persp-mode)
   1617                    (fboundp 'safe-persp-name)
   1618                    (fboundp 'get-current-persp))
   1619           (let* ((persp (get-current-persp))
   1620                  (name (safe-persp-name persp))
   1621                  (face (if (and persp
   1622                                 (not (persp-contain-buffer-p (current-buffer) persp)))
   1623                            'doom-modeline-persp-buffer-not-in-persp
   1624                          'doom-modeline-persp-name))
   1625                  (icon (doom-modeline-icon 'octicon "nf-oct-repo" "đŸ–ŋ" "#"
   1626                                            :face `(:inherit ,face :slant normal))))
   1627             (when (or doom-modeline-display-default-persp-name
   1628                       (not (string-equal persp-nil-name name)))
   1629               (concat " "
   1630                       (propertize (concat (and doom-modeline-persp-icon
   1631                                                (concat icon (doom-modeline-vspc)))
   1632                                           (propertize name 'face face))
   1633                                   'help-echo "mouse-1: Switch perspective
   1634 mouse-2: Show help for minor mode"
   1635                                   'mouse-face 'doom-modeline-highlight
   1636                                   'local-map (let ((map (make-sparse-keymap)))
   1637                                                (define-key map [mode-line mouse-1]
   1638                                                  #'persp-switch)
   1639                                                (define-key map [mode-line mouse-2]
   1640                                                  (lambda ()
   1641                                                    (interactive)
   1642                                                    (describe-function 'persp-mode)))
   1643                                                map))
   1644                       " "))))))
   1645 
   1646 (add-hook 'buffer-list-update-hook #'doom-modeline-update-persp-name)
   1647 (add-hook 'find-file-hook #'doom-modeline-update-persp-name)
   1648 (add-hook 'persp-activated-functions #'doom-modeline-update-persp-name)
   1649 (add-hook 'persp-renamed-functions #'doom-modeline-update-persp-name)
   1650 (advice-add #'lv-message :after #'doom-modeline-update-persp-name)
   1651 
   1652 (doom-modeline-def-segment persp-name
   1653   "The current perspective name."
   1654   (when (doom-modeline--segment-visible 'persp-name)
   1655     doom-modeline--persp-name))
   1656 
   1657 
   1658 ;;
   1659 ;; Misc info
   1660 ;;
   1661 
   1662 (doom-modeline-def-segment misc-info
   1663   "Mode line construct for miscellaneous information.
   1664 By default, this shows the information specified by `global-mode-string'."
   1665   (when (or doom-modeline-display-misc-in-all-mode-lines
   1666             (doom-modeline--segment-visible 'misc-info))
   1667     (doom-modeline-display-text
   1668      (string-replace "%" "%%" (format-mode-line mode-line-misc-info)))))
   1669 
   1670 
   1671 ;;
   1672 ;; Position
   1673 ;;
   1674 
   1675 (doom-modeline-def-segment buffer-position
   1676   "The buffer position information."
   1677   (let ((visible (doom-modeline--segment-visible 'buffer-position))
   1678         (sep (doom-modeline-spc))
   1679         (wsep (doom-modeline-wspc))
   1680         (face (doom-modeline-face))
   1681         (help-echo "Buffer percentage\n\
   1682 mouse-1: Display Line and Column Mode Menu")
   1683         (mouse-face 'doom-modeline-highlight)
   1684         (local-map mode-line-column-line-number-mode-map))
   1685     `(,wsep
   1686 
   1687       ;; Line and column
   1688       (:propertize
   1689        ((line-number-mode
   1690          (column-number-mode
   1691           (doom-modeline-column-zero-based
   1692            doom-modeline-position-column-line-format
   1693            ,(string-replace
   1694              "%c" "%C" (car doom-modeline-position-column-line-format)))
   1695           doom-modeline-position-line-format)
   1696          (column-number-mode
   1697           (doom-modeline-column-zero-based
   1698            doom-modeline-position-column-format
   1699            ,(string-replace
   1700              "%c" "%C" (car doom-modeline-position-column-format)))))
   1701         (doom-modeline-total-line-number
   1702          ,(and doom-modeline-total-line-number
   1703                (format "/%d" (line-number-at-pos (point-max))))))
   1704        face ,face
   1705        help-echo ,help-echo
   1706        mouse-face ,mouse-face
   1707        local-map ,local-map)
   1708 
   1709       ((or line-number-mode column-number-mode)
   1710        ,sep)
   1711 
   1712       ;; Position
   1713       (,visible
   1714        ,(cond
   1715          ((bound-and-true-p nyan-mode)
   1716           (concat sep (nyan-create) sep))
   1717          ((bound-and-true-p poke-line-mode)
   1718           (concat sep (poke-line-create) sep))
   1719          ((bound-and-true-p mlscroll-mode)
   1720           (concat sep
   1721                   (let ((mlscroll-right-align nil))
   1722                     (format-mode-line (mlscroll-mode-line)))
   1723                   sep))
   1724          ((bound-and-true-p sml-modeline-mode)
   1725           (concat sep (sml-modeline-create) sep))
   1726          (t "")))
   1727 
   1728       ;; Percent position
   1729       (doom-modeline-percent-position
   1730        ((:propertize ("" doom-modeline-percent-position)
   1731          face ,face
   1732          help-echo ,help-echo
   1733          mouse-face ,mouse-face
   1734          local-map ,local-map)
   1735         ,sep)))))
   1736 
   1737 ;;
   1738 ;; Party parrot
   1739 ;;
   1740 (doom-modeline-def-segment parrot
   1741   "The party parrot animated icon. Requires `parrot-mode' to be enabled."
   1742   (when (and (doom-modeline--segment-visible 'parrot)
   1743              (bound-and-true-p parrot-mode))
   1744     (concat (doom-modeline-wspc)
   1745             (parrot-create)
   1746             (doom-modeline-spc))))
   1747 
   1748 ;;
   1749 ;; Modals (evil, overwrite, god, ryo and xah-fly-keys, etc.)
   1750 ;;
   1751 
   1752 (defun doom-modeline--modal-icon (text face help-echo &optional icon unicode)
   1753   "Display the model icon with FACE and HELP-ECHO.
   1754 TEXT is alternative if icon is not available."
   1755   (propertize (doom-modeline-icon
   1756                'mdicon
   1757                (and doom-modeline-modal-icon
   1758                     (or (and doom-modeline-modal-modern-icon icon)
   1759                         "nf-md-record"))
   1760                (or (and doom-modeline-modal-modern-icon unicode) "●")
   1761                text
   1762                :face (doom-modeline-face face))
   1763               'help-echo help-echo))
   1764 
   1765 (defsubst doom-modeline--evil ()
   1766   "The current evil state. Requires `evil-mode' to be enabled."
   1767   (when (bound-and-true-p evil-local-mode)
   1768     (doom-modeline--modal-icon
   1769      (let ((tag (evil-state-property evil-state :tag t)))
   1770        (if (stringp tag) tag (funcall tag)))
   1771      (cond
   1772       ((evil-normal-state-p) 'doom-modeline-evil-normal-state)
   1773       ((evil-emacs-state-p) 'doom-modeline-evil-emacs-state)
   1774       ((evil-insert-state-p) 'doom-modeline-evil-insert-state)
   1775       ((evil-motion-state-p) 'doom-modeline-evil-motion-state)
   1776       ((evil-visual-state-p) 'doom-modeline-evil-visual-state)
   1777       ((evil-operator-state-p) 'doom-modeline-evil-operator-state)
   1778       ((evil-replace-state-p) 'doom-modeline-evil-replace-state)
   1779       (t 'doom-modeline-evil-user-state))
   1780      (evil-state-property evil-state :name t)
   1781      (cond
   1782       ((evil-normal-state-p) "nf-md-alpha_n_circle")
   1783       ((evil-emacs-state-p) "nf-md-alpha_e_circle")
   1784       ((evil-insert-state-p) "nf-md-alpha_i_circle")
   1785       ((evil-motion-state-p) "nf-md-alpha_m_circle")
   1786       ((evil-visual-state-p) "nf-md-alpha_v_circle")
   1787       ((evil-operator-state-p) "nf-md-alpha_o_circle")
   1788       ((evil-replace-state-p) "nf-md-alpha_r_circle")
   1789       (t "nf-md-alpha_u_circle"))
   1790      (cond
   1791       ((evil-normal-state-p) "🅝")
   1792       ((evil-emacs-state-p) "🅔")
   1793       ((evil-insert-state-p) "🅘")
   1794       ((evil-motion-state-p) "🅜")
   1795       ((evil-visual-state-p) "đŸ…Ĩ")
   1796       ((evil-operator-state-p) "🅞")
   1797       ((evil-replace-state-p) "🅡")
   1798       (t "🅤")))))
   1799 
   1800 (defsubst doom-modeline--overwrite ()
   1801   "The current overwrite state which is enabled by command `overwrite-mode'."
   1802   (when (and (bound-and-true-p overwrite-mode)
   1803              (not (bound-and-true-p evil-local-mode)))
   1804     (doom-modeline--modal-icon
   1805      "<W>" 'doom-modeline-overwrite "Overwrite mode"
   1806      "nf-md-marker" "đŸ…Ļ")))
   1807 
   1808 (defsubst doom-modeline--god ()
   1809   "The current god state which is enabled by the command `god-mode'."
   1810   (when (bound-and-true-p god-local-mode)
   1811     (doom-modeline--modal-icon
   1812      "<G>" 'doom-modeline-god "God mode"
   1813      "nf-md-account_circle" "🅖")))
   1814 
   1815 (defsubst doom-modeline--ryo ()
   1816   "The current ryo-modal state which is enabled by the command `ryo-modal-mode'."
   1817   (when (bound-and-true-p ryo-modal-mode)
   1818     (doom-modeline--modal-icon
   1819      "<R>" 'doom-modeline-ryo "Ryo modal"
   1820      "nf-md-star_circle" "âœĒ")))
   1821 
   1822 (defsubst doom-modeline--xah-fly-keys ()
   1823   "The current `xah-fly-keys' state."
   1824   (when (bound-and-true-p xah-fly-keys)
   1825     (if xah-fly-insert-state-p
   1826         (doom-modeline--modal-icon
   1827          "<I>" 'doom-modeline-fly-insert-state "Xah-fly insert mode"
   1828          "nf-md-airplane_edit" "🛧")
   1829       (doom-modeline--modal-icon
   1830        "<C>" 'doom-modeline-fly-normal-state "Xah-fly command mode"
   1831        "nf-md-airplane_cog" "🛧"))))
   1832 
   1833 (defsubst doom-modeline--boon ()
   1834   "The current Boon state. Requires `boon-mode' to be enabled."
   1835   (when (bound-and-true-p boon-local-mode)
   1836     (doom-modeline--modal-icon
   1837      (boon-state-string)
   1838      (cond
   1839       (boon-command-state 'doom-modeline-boon-command-state)
   1840       (boon-insert-state 'doom-modeline-boon-insert-state)
   1841       (boon-special-state 'doom-modeline-boon-special-state)
   1842       (boon-off-state 'doom-modeline-boon-off-state)
   1843       (t 'doom-modeline-boon-off-state))
   1844      (boon-modeline-string)
   1845      "nf-md-coffee" "đŸĩ")))
   1846 
   1847 (defsubst doom-modeline--meow ()
   1848   "The current Meow state. Requires `meow-mode' to be enabled."
   1849   (when (bound-and-true-p meow-mode)
   1850     (doom-modeline--modal-icon
   1851      (substring-no-properties meow--indicator)
   1852      (cond
   1853       ((meow-normal-mode-p) 'doom-modeline-meow-normal-state)
   1854       ((meow-insert-mode-p) 'doom-modeline-meow-insert-state)
   1855       ((meow-beacon-mode-p) 'doom-modeline-meow-beacon-state)
   1856       ((meow-motion-mode-p) 'doom-modeline-meow-motion-state)
   1857       ((meow-keypad-mode-p) 'doom-modeline-meow-keypad-state)
   1858       (t 'doom-modeline-meow-normal-state))
   1859      (symbol-name (meow--current-state))
   1860      (cond
   1861       ((meow-normal-mode-p) "nf-md-alpha_n_circle")
   1862       ((meow-insert-mode-p) "nf-md-alpha_i_circle")
   1863       ((meow-beacon-mode-p) "nf-md-alpha_b_circle")
   1864       ((meow-motion-mode-p) "nf-md-alpha_m_circle")
   1865       ((meow-keypad-mode-p) "nf-md-alpha_k_circle")
   1866       (t "nf-md-alpha_n_circle"))
   1867      (cond
   1868       ((meow-normal-mode-p) "🅝")
   1869       ((meow-insert-mode-p) "🅘")
   1870       ((meow-beacon-mode-p) "🅑")
   1871       ((meow-motion-mode-p) "🅜")
   1872       ((meow-keypad-mode-p) "🅚")
   1873       (t "🅝")))))
   1874 
   1875 (doom-modeline-def-segment modals
   1876   "Displays modal editing states.
   1877 
   1878 Including `evil', `overwrite', `god', `ryo' and `xha-fly-kyes', etc."
   1879   (when doom-modeline-modal
   1880     (let* ((evil (doom-modeline--evil))
   1881            (ow (doom-modeline--overwrite))
   1882            (god (doom-modeline--god))
   1883            (ryo (doom-modeline--ryo))
   1884            (xf (doom-modeline--xah-fly-keys))
   1885            (boon (doom-modeline--boon))
   1886            (meow (doom-modeline--meow))
   1887            (vsep (doom-modeline-vspc))
   1888            (sep (and (or evil ow god ryo xf boon meow) (doom-modeline-spc))))
   1889       (concat sep
   1890               (and evil (concat evil (and (or ow god ryo xf boon meow) vsep)))
   1891               (and ow (concat ow (and (or god ryo xf boon meow) vsep)))
   1892               (and god (concat god (and (or ryo xf boon meow) vsep)))
   1893               (and ryo (concat ryo (and (or xf boon meow) vsep)))
   1894               (and xf (concat xf (and (or boon meow) vsep)))
   1895               (and boon (concat boon (and meow vsep)))
   1896               meow
   1897               sep))))
   1898 
   1899 ;;
   1900 ;; Objed state
   1901 ;;
   1902 
   1903 (defvar doom-modeline--objed-active nil)
   1904 
   1905 (defun doom-modeline-update-objed (_ &optional reset)
   1906   "Update `objed' status, inactive when RESET is true."
   1907   (setq doom-modeline--objed-active (not reset)))
   1908 
   1909 (setq objed-modeline-setup-func #'doom-modeline-update-objed)
   1910 
   1911 (doom-modeline-def-segment objed-state ()
   1912   "The current objed state."
   1913   (when (and doom-modeline--objed-active
   1914              (doom-modeline--active))
   1915     (propertize (format " %s(%s) "
   1916                         (symbol-name objed--object)
   1917                         (char-to-string (aref (symbol-name objed--obj-state) 0)))
   1918                 'face 'doom-modeline-evil-emacs-state
   1919                 'help-echo (format "Objed object: %s (%s)"
   1920                                    (symbol-name objed--object)
   1921                                    (symbol-name objed--obj-state)))))
   1922 
   1923 
   1924 ;;
   1925 ;; Input method
   1926 ;;
   1927 
   1928 (doom-modeline-def-segment input-method
   1929   "The current input method."
   1930   (when-let* ((im (cond
   1931                    (current-input-method
   1932                     current-input-method-title)
   1933                    ((and (bound-and-true-p evil-local-mode)
   1934                          (bound-and-true-p evil-input-method))
   1935                     (nth 3 (assoc default-input-method input-method-alist)))
   1936                    (t nil)))
   1937               (sep (doom-modeline-spc)))
   1938     (concat
   1939      sep
   1940      (propertize im
   1941                  'face (doom-modeline-face
   1942                         (if (and (bound-and-true-p rime-mode)
   1943                                  (equal current-input-method "rime"))
   1944                             (if (and (rime--should-enable-p)
   1945                                      (not (rime--should-inline-ascii-p)))
   1946                                 'doom-modeline-input-method
   1947                               'doom-modeline-input-method-alt)
   1948                           'doom-modeline-input-method))
   1949                  'help-echo (concat
   1950                              "Current input method: "
   1951                              current-input-method
   1952                              "\n\
   1953 mouse-2: Disable input method\n\
   1954 mouse-3: Describe current input method")
   1955                  'mouse-face 'doom-modeline-highlight
   1956                  'local-map mode-line-input-method-map)
   1957      sep)))
   1958 
   1959 
   1960 ;;
   1961 ;; Info
   1962 ;;
   1963 
   1964 (doom-modeline-def-segment info-nodes
   1965   "The topic and nodes in the Info buffer."
   1966   (concat
   1967    " ("
   1968    ;; topic
   1969    (propertize (if (stringp Info-current-file)
   1970                    (replace-regexp-in-string
   1971                     "%" "%%"
   1972                     (file-name-sans-extension
   1973                      (file-name-nondirectory Info-current-file)))
   1974                  (format "*%S*" Info-current-file))
   1975                'face (doom-modeline-face 'doom-modeline-info))
   1976    ") "
   1977    ;; node
   1978    (when Info-current-node
   1979      (propertize (replace-regexp-in-string
   1980                   "%" "%%" Info-current-node)
   1981                  'face (doom-modeline-face 'doom-modeline-buffer-path)
   1982                  'help-echo
   1983                  "mouse-1: scroll forward, mouse-3: scroll back"
   1984                  'mouse-face 'doom-modeline-highlight
   1985                  'local-map Info-mode-line-node-keymap))))
   1986 
   1987 
   1988 ;;
   1989 ;; REPL
   1990 ;;
   1991 
   1992 (defun doom-modeline-repl-icon (text face)
   1993   "Display REPL icon (or TEXT in terminal) with FACE."
   1994   (doom-modeline-icon 'faicon "nf-fa-terminal" "$" text :face face))
   1995 
   1996 (defvar doom-modeline--cider nil)
   1997 
   1998 (defun doom-modeline-update-cider ()
   1999   "Update cider repl state."
   2000   (setq doom-modeline--cider
   2001         (let* ((connected (cider-connected-p))
   2002                (face (if connected 'doom-modeline-repl-success 'doom-modeline-repl-warning))
   2003                (repl-buffer (cider-current-repl nil nil))
   2004                (cider-info (when repl-buffer
   2005                              (cider--connection-info repl-buffer t)))
   2006                (icon (doom-modeline-repl-icon "REPL" face)))
   2007           (propertize icon
   2008                       'help-echo
   2009                       (if connected
   2010                           (format "CIDER Connected %s\nmouse-2: CIDER quit" cider-info)
   2011                         "CIDER Disconnected\nmouse-1: CIDER jack-in")
   2012                       'mouse-face 'doom-modeline-highlight
   2013                       'local-map (let ((map (make-sparse-keymap)))
   2014                                    (if connected
   2015                                        (define-key map [mode-line mouse-2]
   2016                                          #'cider-quit)
   2017                                      (define-key map [mode-line mouse-1]
   2018                                        #'cider-jack-in))
   2019                                    map)))))
   2020 
   2021 (add-hook 'cider-connected-hook #'doom-modeline-update-cider)
   2022 (add-hook 'cider-disconnected-hook #'doom-modeline-update-cider)
   2023 (add-hook 'cider-mode-hook #'doom-modeline-update-cider)
   2024 
   2025 (doom-modeline-def-segment repl
   2026   "The REPL state."
   2027   (when doom-modeline-repl
   2028     (when-let* ((icon (when (bound-and-true-p cider-mode)
   2029                         doom-modeline--cider))
   2030                 (sep (doom-modeline-spc)))
   2031       (concat
   2032        sep
   2033        (doom-modeline-display-icon icon)
   2034        sep))))
   2035 
   2036 
   2037 ;;
   2038 ;; LSP
   2039 ;;
   2040 
   2041 (defun doom-modeline-lsp-icon (text face)
   2042   "Display LSP icon (or TEXT in terminal) with FACE."
   2043   (if doom-modeline-lsp-icon
   2044       (doom-modeline-icon 'octicon "nf-oct-rocket" "🚀" text :face face)
   2045     (propertize text 'face face)))
   2046 
   2047 (defvar-local doom-modeline--lsp nil)
   2048 (defun doom-modeline-update-lsp (&rest _)
   2049   "Update `lsp-mode' state."
   2050   (setq doom-modeline--lsp
   2051         (let* ((workspaces (lsp-workspaces))
   2052                (face (if workspaces 'doom-modeline-lsp-success 'doom-modeline-lsp-warning))
   2053                (icon (doom-modeline-lsp-icon "LSP" face)))
   2054           (propertize icon
   2055                       'help-echo
   2056                       (if workspaces
   2057                           (concat "LSP connected "
   2058                                   (string-join
   2059                                    (mapcar (lambda (w)
   2060                                              (format "[%s]\n" (lsp--workspace-print w)))
   2061                                            workspaces))
   2062                                   "C-mouse-1: Switch to another workspace folder
   2063 mouse-1: Describe current session
   2064 mouse-2: Quit server
   2065 mouse-3: Reconnect to server")
   2066                         "LSP Disconnected
   2067 mouse-1: Reload to start server")
   2068                       'mouse-face 'doom-modeline-highlight
   2069                       'local-map (let ((map (make-sparse-keymap)))
   2070                                    (if workspaces
   2071                                        (progn
   2072                                          (define-key map [mode-line C-mouse-1]
   2073                                            #'lsp-workspace-folders-open)
   2074                                          (define-key map [mode-line mouse-1]
   2075                                            #'lsp-describe-session)
   2076                                          (define-key map [mode-line mouse-2]
   2077                                            #'lsp-workspace-shutdown)
   2078                                          (define-key map [mode-line mouse-3]
   2079                                            #'lsp-workspace-restart))
   2080                                      (progn
   2081                                        (define-key map [mode-line mouse-1]
   2082                                          (lambda ()
   2083                                            (interactive)
   2084                                            (ignore-errors (revert-buffer t t))))))
   2085                                    map)))))
   2086 (add-hook 'lsp-before-initialize-hook #'doom-modeline-update-lsp)
   2087 (add-hook 'lsp-after-initialize-hook #'doom-modeline-update-lsp)
   2088 (add-hook 'lsp-after-uninitialized-functions #'doom-modeline-update-lsp)
   2089 (add-hook 'lsp-before-open-hook #'doom-modeline-update-lsp)
   2090 (add-hook 'lsp-after-open-hook #'doom-modeline-update-lsp)
   2091 
   2092 (defun doom-modeline--eglot-pending-count (server)
   2093   "Get count of pending eglot requests to SERVER."
   2094   (if (fboundp 'jsonrpc-continuation-count)
   2095       (jsonrpc-continuation-count server)
   2096     (hash-table-count (jsonrpc--request-continuations server))))
   2097 
   2098 (defvar-local doom-modeline--eglot nil)
   2099 (defun doom-modeline-update-eglot ()
   2100   "Update eglot state."
   2101   (setq doom-modeline--eglot
   2102         (let* ((server (and (eglot-managed-p) (eglot-current-server)))
   2103                (nick (and server (eglot-project-nickname server)))
   2104                (pending (and server (doom-modeline--eglot-pending-count server)))
   2105                (last-error (and server (jsonrpc-last-error server)))
   2106                (face (cond (last-error 'doom-modeline-lsp-error)
   2107                            ((and pending (cl-plusp pending)) 'doom-modeline-lsp-warning)
   2108                            (nick 'doom-modeline-lsp-success)
   2109                            (t 'doom-modeline-lsp-warning)))
   2110                (server-info (and server (eglot--server-info server)))
   2111                (server-name (or (plist-get server-info :name)
   2112                                 (and server (jsonrpc-name server)) ""))
   2113                (major-modes (or (and server (eglot--major-modes server)) ""))
   2114                (icon (doom-modeline-lsp-icon eglot-menu-string face)))
   2115           (propertize icon
   2116                       'help-echo (format "Eglot connected [%s]\n%s %s
   2117 mouse-1: Display minor mode menu
   2118 mouse-3: LSP server control menu"
   2119                                          nick server-name major-modes)
   2120                       'mouse-face 'doom-modeline-highlight
   2121                       'local-map (let ((map (make-sparse-keymap)))
   2122                                    (define-key map [mode-line mouse-1] eglot-menu)
   2123                                    (define-key map [mode-line mouse-3] eglot-server-menu)
   2124                                    map)))))
   2125 (add-hook 'eglot-managed-mode-hook #'doom-modeline-update-eglot)
   2126 
   2127 (defvar-local doom-modeline--tags nil)
   2128 (defun doom-modeline-update-tags ()
   2129   "Update tags state."
   2130   (setq doom-modeline--tags
   2131         (propertize
   2132          (doom-modeline-lsp-icon "Tags" 'doom-modeline-lsp-success)
   2133          'help-echo "Tags: Citre mode
   2134 mouse-1: Toggle citre mode"
   2135          'mouse-face 'doom-modeline-highlight
   2136          'local-map (make-mode-line-mouse-map 'mouse-1 #'citre-mode))))
   2137 (add-hook 'citre-mode-hook #'doom-modeline-update-tags)
   2138 
   2139 (defun doom-modeline-update-lsp-icon ()
   2140   "Update lsp icon."
   2141   (cond ((bound-and-true-p lsp-mode)
   2142          (doom-modeline-update-lsp))
   2143         ((bound-and-true-p eglot--managed-mode)
   2144          (doom-modeline-update-eglot))
   2145         ((bound-and-true-p citre-mode)
   2146          (doom-modeline-update-tags))))
   2147 
   2148 (doom-modeline-add-variable-watcher
   2149  'doom-modeline-lsp-icon
   2150  (lambda (_sym val op _where)
   2151    (when (eq op 'set)
   2152      (setq doom-modeline-lsp-icon val)
   2153      (dolist (buf (buffer-list))
   2154        (with-current-buffer buf
   2155          (doom-modeline-update-lsp-icon))))))
   2156 
   2157 (doom-modeline-add-variable-watcher
   2158  'doom-modeline-icon
   2159  (lambda (_sym val op _where)
   2160    (when (eq op 'set)
   2161      (setq doom-modeline-icon val)
   2162      (dolist (buf (buffer-list))
   2163        (with-current-buffer buf
   2164          (doom-modeline-update-lsp-icon))))))
   2165 
   2166 (doom-modeline-add-variable-watcher
   2167  'doom-modeline-unicode-fallback
   2168  (lambda (_sym val op _where)
   2169    (when (eq op 'set)
   2170      (setq doom-modeline-unicode-fallback val)
   2171      (dolist (buf (buffer-list))
   2172        (with-current-buffer buf
   2173          (doom-modeline-update-lsp-icon))))))
   2174 
   2175 (doom-modeline-def-segment lsp
   2176   "The LSP server state."
   2177   (when doom-modeline-lsp
   2178     (when-let* ((icon (cond ((bound-and-true-p lsp-mode)
   2179                              doom-modeline--lsp)
   2180                             ((bound-and-true-p eglot--managed-mode)
   2181                              doom-modeline--eglot)
   2182                             ((bound-and-true-p citre-mode)
   2183                              doom-modeline--tags)))
   2184                 (sep (doom-modeline-spc)))
   2185       (concat
   2186        sep
   2187        (doom-modeline-display-icon icon)
   2188        sep))))
   2189 
   2190 (defun doom-modeline-override-eglot ()
   2191   "Override `eglot' mode-line."
   2192   (if (and doom-modeline-lsp
   2193            (bound-and-true-p doom-modeline-mode))
   2194       (setq mode-line-misc-info
   2195             (delq (assq 'eglot--managed-mode mode-line-misc-info) mode-line-misc-info))
   2196     (add-to-list 'mode-line-misc-info
   2197                  `(eglot--managed-mode (" [" eglot--mode-line-format "] ")))))
   2198 (add-hook 'eglot-managed-mode-hook #'doom-modeline-override-eglot)
   2199 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-eglot)
   2200 
   2201 (doom-modeline-add-variable-watcher
   2202  'doom-modeline-battery
   2203  (lambda (_sym val op _where)
   2204    (when (eq op 'set)
   2205      (setq doom-modeline-lsp val)
   2206      (doom-modeline-override-eglot))))
   2207 
   2208 
   2209 ;;
   2210 ;; GitHub
   2211 ;;
   2212 
   2213 (defvar doom-modeline--github-notification-number 0)
   2214 (defvar doom-modeline-before-github-fetch-notification-hook nil
   2215   "Hooks before fetching GitHub notifications.
   2216 Example:
   2217   (add-hook \\='doom-modeline-before-github-fetch-notification-hook
   2218           #\\='auth-source-pass-enable)")
   2219 
   2220 (defvar doom-modeline-after-github-fetch-notification-hook nil
   2221   "Hooks after fetching GitHub notifications.")
   2222 
   2223 (defun doom-modeline--github-fetch-notifications ()
   2224   "Fetch GitHub notifications."
   2225   (when (and doom-modeline-github
   2226              (require 'async nil t))
   2227     (async-start
   2228      `(lambda ()
   2229         ,(async-inject-variables
   2230           "\\`\\(load-path\\|auth-sources\\|doom-modeline-before-github-fetch-notification-hook\\)\\'")
   2231         (run-hooks 'doom-modeline-before-github-fetch-notification-hook)
   2232         (when (require 'ghub nil t)
   2233           (with-timeout (10)
   2234             (ignore-errors
   2235               (when-let* ((username (ghub--username ghub-default-host))
   2236                           (token (or (ghub--token ghub-default-host username 'forge t)
   2237                                      (ghub--token ghub-default-host username 'ghub t))))
   2238                 (ghub-get "/notifications"
   2239                           '((notifications . t))
   2240                           :host ghub-default-host
   2241                           :username username
   2242                           :auth token
   2243                           :unpaginate t
   2244                           :noerror t))))))
   2245      (lambda (result)
   2246        (message "")                     ; suppress message
   2247        (setq doom-modeline--github-notification-number (length result))
   2248        (run-hooks 'doom-modeline-after-github-fetch-notification-hook)))))
   2249 
   2250 (defvar doom-modeline--github-timer nil)
   2251 (defun doom-modeline-github-timer ()
   2252   "Start/Stop the timer for GitHub fetching."
   2253   (if (timerp doom-modeline--github-timer)
   2254       (cancel-timer doom-modeline--github-timer))
   2255   (setq doom-modeline--github-timer
   2256         (and doom-modeline-github
   2257              (run-with-idle-timer 30
   2258                                   doom-modeline-github-interval
   2259                                   #'doom-modeline--github-fetch-notifications))))
   2260 
   2261 (doom-modeline-add-variable-watcher
   2262  'doom-modeline-github
   2263  (lambda (_sym val op _where)
   2264    (when (eq op 'set)
   2265      (setq doom-modeline-github val)
   2266      (doom-modeline-github-timer))))
   2267 
   2268 (doom-modeline-github-timer)
   2269 
   2270 (doom-modeline-def-segment github
   2271   "The GitHub notifications."
   2272   (when (and doom-modeline-github
   2273              (doom-modeline--segment-visible 'github)
   2274              (numberp doom-modeline--github-notification-number))
   2275     (let ((sep (doom-modeline-spc)))
   2276       (concat
   2277        sep
   2278        (propertize
   2279         (concat
   2280          (doom-modeline-icon 'octicon "nf-oct-mark_github" "🔔" "&"
   2281                              :face 'doom-modeline-notification)
   2282          (and (> doom-modeline--github-notification-number 0) (doom-modeline-vspc))
   2283          (propertize
   2284           (cond
   2285            ((<= doom-modeline--github-notification-number 0) "")
   2286            ((> doom-modeline--github-notification-number 99) "99+")
   2287            (t (number-to-string doom-modeline--github-notification-number)))
   2288           'face '(:inherit
   2289                   (doom-modeline-unread-number doom-modeline-notification))))
   2290         'help-echo "Github Notifications
   2291 mouse-1: Show notifications
   2292 mouse-3: Fetch notifications"
   2293         'mouse-face 'doom-modeline-highlight
   2294         'local-map (let ((map (make-sparse-keymap)))
   2295                      (define-key map [mode-line mouse-1]
   2296                        (lambda ()
   2297                          "Open GitHub notifications page."
   2298                          (interactive)
   2299                          (run-with-idle-timer 300 nil #'doom-modeline--github-fetch-notifications)
   2300                          (browse-url "https://github.com/notifications")))
   2301                      (define-key map [mode-line mouse-3]
   2302                        (lambda ()
   2303                          "Fetching GitHub notifications."
   2304                          (interactive)
   2305                          (message "Fetching GitHub notifications...")
   2306                          (doom-modeline--github-fetch-notifications)))
   2307                      map))
   2308        sep))))
   2309 
   2310 
   2311 ;;
   2312 ;; Debug states
   2313 ;;
   2314 
   2315 ;; Highlight the doom-modeline while debugging.
   2316 (defvar-local doom-modeline--debug-cookie nil)
   2317 (defun doom-modeline--debug-visual (&rest _)
   2318   "Update the face of mode-line for debugging."
   2319   (mapc (lambda (buffer)
   2320           (with-current-buffer buffer
   2321             (setq doom-modeline--debug-cookie
   2322                   (face-remap-add-relative 'doom-modeline 'doom-modeline-debug-visual))
   2323             (force-mode-line-update)))
   2324         (buffer-list)))
   2325 
   2326 (defun doom-modeline--normal-visual (&rest _)
   2327   "Restore the face of mode-line."
   2328   (mapc (lambda (buffer)
   2329           (with-current-buffer buffer
   2330             (when doom-modeline--debug-cookie
   2331               (face-remap-remove-relative doom-modeline--debug-cookie)
   2332               (force-mode-line-update))))
   2333         (buffer-list)))
   2334 
   2335 (add-hook 'dap-session-created-hook #'doom-modeline--debug-visual)
   2336 (add-hook 'dap-terminated-hook #'doom-modeline--normal-visual)
   2337 
   2338 (defun doom-modeline-debug-icon (face)
   2339   "Display debug icon with FACE and ARGS."
   2340   (doom-modeline-icon 'codicon "nf-cod-debug" "🐛" "!" :face face))
   2341 
   2342 (defun doom-modeline--debug-dap ()
   2343   "The current `dap-mode' state."
   2344   (when (and (bound-and-true-p dap-mode)
   2345              (bound-and-true-p lsp-mode))
   2346     (when-let* ((session (dap--cur-session)))
   2347       (when (dap--session-running session)
   2348         (propertize (doom-modeline-debug-icon 'doom-modeline-info)
   2349                     'help-echo (format "DAP (%s - %s)
   2350 mouse-1: Display debug hydra
   2351 mouse-2: Display recent configurations
   2352 mouse-3: Disconnect session"
   2353                                        (dap--debug-session-name session)
   2354                                        (dap--debug-session-state session))
   2355                     'mouse-face 'doom-modeline-highlight
   2356                     'local-map (let ((map (make-sparse-keymap)))
   2357                                  (define-key map [mode-line mouse-1]
   2358                                              #'dap-hydra)
   2359                                  (define-key map [mode-line mouse-2]
   2360                                              #'dap-debug-recent)
   2361                                  (define-key map [mode-line mouse-3]
   2362                                              #'dap-disconnect)
   2363                                  map))))))
   2364 
   2365 (defvar-local doom-modeline--debug-dap nil)
   2366 (defun doom-modeline-update-debug-dap (&rest _)
   2367   "Update dap debug state."
   2368   (setq doom-modeline--debug-dap (doom-modeline--debug-dap)))
   2369 
   2370 (add-hook 'dap-session-created-hook #'doom-modeline-update-debug-dap)
   2371 (add-hook 'dap-session-changed-hook #'doom-modeline-update-debug-dap)
   2372 (add-hook 'dap-terminated-hook #'doom-modeline-update-debug-dap)
   2373 
   2374 (defsubst doom-modeline--debug-edebug ()
   2375   "The current `edebug' state."
   2376   (when (bound-and-true-p edebug-mode)
   2377     (propertize (doom-modeline-debug-icon 'doom-modeline-info)
   2378                 'help-echo (format "EDebug (%s)
   2379 mouse-1: Show help
   2380 mouse-2: Next
   2381 mouse-3: Stop debugging"
   2382                                    edebug-execution-mode)
   2383                 'mouse-face 'doom-modeline-highlight
   2384                 'local-map (let ((map (make-sparse-keymap)))
   2385                              (define-key map [mode-line mouse-1]
   2386                                #'edebug-help)
   2387                              (define-key map [mode-line mouse-2]
   2388                                #'edebug-next-mode)
   2389                              (define-key map [mode-line mouse-3]
   2390                                #'edebug-stop)
   2391                              map))))
   2392 
   2393 (defsubst doom-modeline--debug-on-error ()
   2394   "The current `debug-on-error' state."
   2395   (when debug-on-error
   2396     (propertize (doom-modeline-debug-icon 'doom-modeline-urgent)
   2397                 'help-echo "Debug on Error
   2398 mouse-1: Toggle Debug on Error"
   2399                 'mouse-face 'doom-modeline-highlight
   2400                 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-error))))
   2401 
   2402 (defsubst doom-modeline--debug-on-quit ()
   2403   "The current `debug-on-quit' state."
   2404   (when debug-on-quit
   2405     (propertize (doom-modeline-debug-icon 'doom-modeline-warning)
   2406                 'help-echo "Debug on Quit
   2407 mouse-1: Toggle Debug on Quit"
   2408                 'mouse-face 'doom-modeline-highlight
   2409                 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-quit))))
   2410 
   2411 (doom-modeline-def-segment debug
   2412   "The current debug state."
   2413   (when (doom-modeline--segment-visible 'debug)
   2414     (let* ((dap doom-modeline--debug-dap)
   2415            (edebug (doom-modeline--debug-edebug))
   2416            (on-error (doom-modeline--debug-on-error))
   2417            (on-quit (doom-modeline--debug-on-quit))
   2418            (vsep (doom-modeline-vspc))
   2419            (sep (and (or dap edebug on-error on-quit) (doom-modeline-spc))))
   2420       (concat sep
   2421               (and dap (concat dap (and (or edebug on-error on-quit) vsep)))
   2422               (and edebug (concat edebug (and (or on-error on-quit) vsep)))
   2423               (and on-error (concat on-error (and on-quit vsep)))
   2424               on-quit
   2425               sep))))
   2426 
   2427 
   2428 ;;
   2429 ;; PDF pages
   2430 ;;
   2431 
   2432 (defvar-local doom-modeline--pdf-pages nil)
   2433 (defun doom-modeline-update-pdf-pages ()
   2434   "Update PDF pages."
   2435   (setq doom-modeline--pdf-pages
   2436         (format "  P%d/%d "
   2437                 (or (eval `(pdf-view-current-page)) 0)
   2438                 (pdf-cache-number-of-pages))))
   2439 (add-hook 'pdf-view-change-page-hook #'doom-modeline-update-pdf-pages)
   2440 
   2441 (doom-modeline-def-segment pdf-pages
   2442   "Display PDF pages."
   2443   doom-modeline--pdf-pages)
   2444 
   2445 
   2446 ;;
   2447 ;; `mu4e' notifications
   2448 ;;
   2449 
   2450 (doom-modeline-def-segment mu4e
   2451   "Show notifications of any unread emails in `mu4e'."
   2452   (when (and doom-modeline-mu4e
   2453              (doom-modeline--segment-visible 'mu4e))
   2454     (let ((sep (doom-modeline-spc))
   2455           (vsep (doom-modeline-vspc))
   2456           (icon (doom-modeline-icon 'mdicon "nf-md-email" "📧" "#"
   2457                                     :face 'doom-modeline-notification)))
   2458       (cond ((and (bound-and-true-p mu4e-alert-mode-line)
   2459                   (numberp mu4e-alert-mode-line)
   2460                   ;; don't display if the unread mails count is zero
   2461                   (> mu4e-alert-mode-line 0))
   2462              (concat
   2463               sep
   2464               (propertize
   2465                (concat
   2466                 icon
   2467                 vsep
   2468                 (propertize
   2469                  (if (> mu4e-alert-mode-line doom-modeline-number-limit)
   2470                      (format "%d+" doom-modeline-number-limit)
   2471                    (number-to-string mu4e-alert-mode-line))
   2472                  'face '(:inherit
   2473                          (doom-modeline-unread-number doom-modeline-notification))))
   2474                'mouse-face 'doom-modeline-highlight
   2475                'keymap '(mode-line keymap
   2476                                    (mouse-1 . mu4e-alert-view-unread-mails)
   2477                                    (mouse-2 . mu4e-alert-view-unread-mails)
   2478                                    (mouse-3 . mu4e-alert-view-unread-mails))
   2479                'help-echo (concat (if (= mu4e-alert-mode-line 1)
   2480                                       "You have an unread email"
   2481                                     (format "You have %s unread emails" mu4e-alert-mode-line))
   2482                                   "\nClick here to view "
   2483                                   (if (= mu4e-alert-mode-line 1) "it" "them")))
   2484               sep))
   2485             ((bound-and-true-p mu4e-modeline-mode)
   2486              (concat sep icon vsep
   2487                      (propertize (mu4e--modeline-string)
   2488                                  'face 'doom-modeline-notification)
   2489                      sep))))))
   2490 
   2491 (defun doom-modeline-override-mu4e-alert (&rest _)
   2492   "Delete `mu4e-alert-mode-line' from global modeline string."
   2493   (when (and (featurep 'mu4e-alert)
   2494              (bound-and-true-p mu4e-alert-mode-line))
   2495     (if (and doom-modeline-mu4e
   2496              (bound-and-true-p doom-modeline-mode))
   2497         ;; Delete original modeline
   2498         (progn
   2499           (setq global-mode-string
   2500                 (delete '(:eval mu4e-alert-mode-line) global-mode-string))
   2501           (setq mu4e-alert-modeline-formatter #'identity))
   2502       ;; Recover default settings
   2503       (setq mu4e-alert-modeline-formatter #'mu4e-alert-default-mode-line-formatter))))
   2504 (advice-add #'mu4e-alert-enable-mode-line-display
   2505             :after #'doom-modeline-override-mu4e-alert)
   2506 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-alert)
   2507 
   2508 (defun doom-modeline-override-mu4e-modeline (&rest _)
   2509   "Delete `mu4e-alert-mode-line' from global modeline string."
   2510   (when (bound-and-true-p mu4e-modeline-mode)
   2511     (if (and doom-modeline-mu4e
   2512              (bound-and-true-p doom-modeline-mode))
   2513         ;; Delete original modeline
   2514         (setq global-mode-string
   2515               (delete mu4e--modeline-item global-mode-string))
   2516       ;; Recover default settings
   2517       (add-to-list 'global-mode-string mu4e--modeline-item))))
   2518 (add-hook 'mu4e-modeline-mode-hook #'doom-modeline-override-mu4e-modeline)
   2519 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-modeline)
   2520 
   2521 (doom-modeline-add-variable-watcher
   2522  'doom-modeline-mu4e
   2523  (lambda (_sym val op _where)
   2524    (when (eq op 'set)
   2525      (setq doom-modeline-mu4e val)
   2526      (doom-modeline-override-mu4e-alert)
   2527      (doom-modeline-override-mu4e-modeline))))
   2528 
   2529 
   2530 ;;
   2531 ;; `gnus' notifications
   2532 ;;
   2533 
   2534 (defvar doom-modeline--gnus-unread-mail 0)
   2535 (defvar doom-modeline--gnus-started nil
   2536   "Used to determine if gnus has started.")
   2537 (defun doom-modeline-update-gnus-status (&rest _)
   2538   "Get the total number of unread news of gnus group."
   2539   (setq doom-modeline--gnus-unread-mail
   2540         (when (and doom-modeline-gnus
   2541                    doom-modeline--gnus-started)
   2542           (let ((total-unread-news-number 0))
   2543             (mapc (lambda (g)
   2544                     (let* ((group (car g))
   2545                            (unread (eval `(gnus-group-unread ,group))))
   2546                       (when (and (not (seq-contains-p doom-modeline-gnus-excluded-groups group))
   2547                                  (numberp unread)
   2548                                  (> unread 0))
   2549                         (setq total-unread-news-number (+ total-unread-news-number unread)))))
   2550                   gnus-newsrc-alist)
   2551             total-unread-news-number))))
   2552 
   2553 ;; Update the modeline after changes have been made
   2554 (add-hook 'gnus-group-update-hook #'doom-modeline-update-gnus-status)
   2555 (add-hook 'gnus-summary-update-hook #'doom-modeline-update-gnus-status)
   2556 (add-hook 'gnus-group-update-group-hook #'doom-modeline-update-gnus-status)
   2557 (add-hook 'gnus-after-getting-new-news-hook #'doom-modeline-update-gnus-status)
   2558 
   2559 ;; Only start to listen to gnus when gnus is actually running
   2560 (defun doom-modeline-start-gnus-listener ()
   2561   "Start GNUS listener."
   2562   (when (and doom-modeline-gnus
   2563              (not doom-modeline--gnus-started))
   2564     (setq doom-modeline--gnus-started t)
   2565     ;; Scan gnus in the background if the timer is higher than 0
   2566     (doom-modeline-update-gnus-status)
   2567     (if (> doom-modeline-gnus-timer 0)
   2568         (gnus-demon-add-handler 'gnus-demon-scan-news doom-modeline-gnus-timer doom-modeline-gnus-idle))))
   2569 (add-hook 'gnus-started-hook #'doom-modeline-start-gnus-listener)
   2570 
   2571 ;; Stop the listener if gnus isn't running
   2572 (defun doom-modeline-stop-gnus-listener ()
   2573   "Stop GNUS listener."
   2574   (setq doom-modeline--gnus-started nil))
   2575 (add-hook 'gnus-exit-gnus-hook #'doom-modeline-stop-gnus-listener)
   2576 
   2577 (doom-modeline-def-segment gnus
   2578   "Show notifications of any unread emails in `gnus'."
   2579   (when (and (doom-modeline--segment-visible 'gnus)
   2580              doom-modeline-gnus
   2581              doom-modeline--gnus-started
   2582              ;; Don't display if the unread mails count is zero
   2583              (numberp doom-modeline--gnus-unread-mail)
   2584              (> doom-modeline--gnus-unread-mail 0))
   2585     (let ((sep (doom-modeline-spc))
   2586           (vsep (doom-modeline-vspc)))
   2587       (concat
   2588        sep
   2589        (propertize
   2590         (concat
   2591          (doom-modeline-icon 'mdicon "nf-md-email" "📧" "#"
   2592                              :face 'doom-modeline-notification)
   2593          vsep
   2594          (propertize
   2595           (if (> doom-modeline--gnus-unread-mail doom-modeline-number-limit)
   2596               (format "%d+" doom-modeline-number-limit)
   2597             (number-to-string doom-modeline--gnus-unread-mail))
   2598           'face '(:inherit
   2599                   (doom-modeline-unread-number doom-modeline-notification))))
   2600         'mouse-face 'doom-modeline-highlight
   2601         'help-echo (if (= doom-modeline--gnus-unread-mail 1)
   2602                        "You have an unread email"
   2603                      (format "You have %s unread emails" doom-modeline--gnus-unread-mail)))
   2604        sep))))
   2605 
   2606 
   2607 ;;
   2608 ;; IRC notifications
   2609 ;;
   2610 
   2611 (defun doom-modeline-shorten-irc (name)
   2612   "Shorten IRC buffer `name' according to IRC mode.
   2613 
   2614 Calls the mode specific function to return the shortened
   2615 version of `NAME' if applicable:
   2616 - Circe: `tracking-shorten'
   2617 - ERC: `erc-track-shorten-function'
   2618 - rcirc: `rcirc-shorten-buffer-name'
   2619 
   2620 The specific function will decide how to stylize the buffer name,
   2621 read the individual functions documentation for more."
   2622   (or (and (fboundp 'tracking-shorten)
   2623            (car (tracking-shorten (list name))))
   2624       (and (boundp 'erc-track-shorten-function)
   2625            (functionp erc-track-shorten-function)
   2626 	       (car (funcall erc-track-shorten-function (list name))))
   2627       (and (fboundp 'rcirc-short-buffer-name)
   2628            (rcirc-short-buffer-name name))
   2629       name))
   2630 
   2631 (defun doom-modeline--tracking-buffers (buffers)
   2632   "Logic to convert some irc BUFFERS to their font-awesome icon."
   2633   (mapconcat
   2634    (lambda (b)
   2635      (propertize
   2636       (funcall doom-modeline-irc-stylize b)
   2637       'face '(:inherit (doom-modeline-unread-number doom-modeline-notification))
   2638       'help-echo (format "IRC Notification: %s\nmouse-1: Switch to buffer" b)
   2639       'mouse-face 'doom-modeline-highlight
   2640       'local-map (make-mode-line-mouse-map
   2641                   'mouse-1
   2642                   (lambda ()
   2643                     (interactive)
   2644                     (when (buffer-live-p (get-buffer b))
   2645                       (switch-to-buffer b))))))
   2646    buffers
   2647    (doom-modeline-vspc)))
   2648 
   2649 (defun doom-modeline--circe-p ()
   2650   "Check if `circe' is in use."
   2651   (boundp 'tracking-mode-line-buffers))
   2652 
   2653 (defun doom-modeline--erc-p ()
   2654   "Check if `erc' is in use."
   2655   (boundp 'erc-modified-channels-alist))
   2656 
   2657 (defun doom-modeline--rcirc-p ()
   2658   "Check if `rcirc' is in use."
   2659   (bound-and-true-p rcirc-track-minor-mode))
   2660 
   2661 (defun doom-modeline--get-buffers ()
   2662   "Gets the buffers that have activity."
   2663   (cond
   2664    ((doom-modeline--circe-p)
   2665     tracking-buffers)
   2666    ((doom-modeline--erc-p)
   2667     (mapcar (lambda (l)
   2668               (buffer-name (car l)))
   2669             erc-modified-channels-alist))
   2670    ((doom-modeline--rcirc-p)
   2671     (mapcar (lambda (b)
   2672               (buffer-name b))
   2673             rcirc-activity))))
   2674 
   2675 ;; Create a modeline segment that contains all the irc tracked buffers
   2676 (doom-modeline-def-segment irc-buffers
   2677   "The list of shortened, unread irc buffers."
   2678   (when (and doom-modeline-irc
   2679              (doom-modeline--segment-visible 'irc-buffers))
   2680     (let* ((buffers (doom-modeline--get-buffers))
   2681            (number (length buffers))
   2682            (sep (doom-modeline-spc)))
   2683       (when (> number 0)
   2684         (concat
   2685          sep
   2686          (doom-modeline--tracking-buffers buffers)
   2687          sep)))))
   2688 
   2689 (doom-modeline-def-segment irc
   2690   "A notification icon for any unread irc buffer."
   2691   (when (and doom-modeline-irc
   2692              (doom-modeline--segment-visible 'irc))
   2693     (let* ((buffers (doom-modeline--get-buffers))
   2694            (number (length buffers))
   2695            (sep (doom-modeline-spc))
   2696            (vsep (doom-modeline-vspc)))
   2697       (when (> number 0)
   2698         (concat
   2699          sep
   2700 
   2701          (propertize (concat
   2702                       (doom-modeline-icon 'mdicon "nf-md-message_processing" "🗊" "#"
   2703                                           :face 'doom-modeline-notification)
   2704                       vsep
   2705                       ;; Display the number of unread buffers
   2706                       (propertize (number-to-string number)
   2707                                   'face '(:inherit
   2708                                           (doom-modeline-unread-number
   2709                                            doom-modeline-notification))))
   2710                      'help-echo (format "IRC Notifications: %s\n%s"
   2711                                         (mapconcat
   2712                                          (lambda (b) (funcall doom-modeline-irc-stylize b))
   2713                                          buffers
   2714                                          ", ")
   2715                                         (cond
   2716                                          ((doom-modeline--circe-p)
   2717                                           "mouse-1: Switch to previous unread buffer
   2718 mouse-3: Switch to next unread buffer")
   2719                                          ((doom-modeline--erc-p)
   2720                                           "mouse-1: Switch to buffer
   2721 mouse-3: Switch to next unread buffer")
   2722                                          ((doom-modeline--rcirc-p)
   2723                                           "mouse-1: Switch to server buffer
   2724 mouse-3: Switch to next unread buffer")))
   2725                      'mouse-face 'doom-modeline-highlight
   2726                      'local-map (let ((map (make-sparse-keymap)))
   2727                                   (cond
   2728                                    ((doom-modeline--circe-p)
   2729                                     (define-key map [mode-line mouse-1]
   2730                                       #'tracking-previous-buffer)
   2731                                     (define-key map [mode-line mouse-3]
   2732                                       #'tracking-next-buffer))
   2733                                    ((doom-modeline--erc-p)
   2734                                     (define-key map [mode-line mouse-1]
   2735                                       #'erc-switch-to-buffer)
   2736                                     (define-key map [mode-line mouse-3]
   2737                                       #'erc-track-switch-buffer))
   2738                                    ((doom-modeline--rcirc-p)
   2739                                     (define-key map [mode-line mouse-1]
   2740                                       #'rcirc-switch-to-server-buffer)
   2741                                     (define-key map [mode-line mouse-3]
   2742                                       #'rcirc-next-active-buffer)))
   2743                                   map))
   2744 
   2745          ;; Display the unread irc buffers as well
   2746          (when doom-modeline-irc-buffers
   2747            (concat sep (doom-modeline--tracking-buffers buffers)))
   2748 
   2749          sep)))))
   2750 
   2751 (defun doom-modeline-override-rcirc ()
   2752   "Override default `rcirc' mode-line."
   2753   (if (and doom-modeline-irc
   2754            (bound-and-true-p doom-modeline-mode))
   2755       (setq global-mode-string
   2756 		    (delq 'rcirc-activity-string global-mode-string))
   2757     (when (and rcirc-track-minor-mode
   2758                (not (memq 'rcirc-activity-string global-mode-string)))
   2759 	  (setq global-mode-string
   2760 		    (append global-mode-string '(rcirc-activity-string))))))
   2761 (add-hook 'rcirc-track-minor-mode-hook #'doom-modeline-override-rcirc)
   2762 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-rcirc)
   2763 
   2764 (doom-modeline-add-variable-watcher
   2765  'doom-modeline-irc
   2766  (lambda (_sym val op _where)
   2767    (when (eq op 'set)
   2768      (setq doom-modeline-irc val)
   2769      (doom-modeline-override-rcirc))))
   2770 
   2771 
   2772 ;;
   2773 ;; Battery status
   2774 ;;
   2775 
   2776 (defun doom-modeline-battery-icon (icon unicode text face)
   2777   "Displays the battery ICON with FACE.
   2778 
   2779 UNICODE and TEXT are fallbacks.
   2780 Uses `nerd-icons-mdicon' to fetch the icon."
   2781   (doom-modeline-icon 'mdicon icon unicode text :face face))
   2782 
   2783 (defvar doom-modeline--battery-status nil)
   2784 (defun doom-modeline-update-battery-status ()
   2785   "Update battery status."
   2786   (setq doom-modeline--battery-status
   2787         (when (and doom-modeline-battery
   2788                    (bound-and-true-p display-battery-mode))
   2789           (let* ((data (and battery-status-function
   2790                             (functionp battery-status-function)
   2791                             (funcall battery-status-function)))
   2792                  (status (cdr (assoc ?L data)))
   2793                  (charging? (or (string-equal "AC" status)
   2794                                 (string-equal "on-line" status)))
   2795                  (percentage (car (read-from-string (or (cdr (assq ?p data)) "ERR"))))
   2796                  (valid-percentage? (and (numberp percentage)
   2797                                          (>= percentage 0)
   2798                                          (<= percentage battery-mode-line-limit)))
   2799                  (face (if valid-percentage?
   2800                            (cond (charging? 'doom-modeline-battery-charging)
   2801                                  ((< percentage battery-load-critical) 'doom-modeline-battery-critical)
   2802                                  ((< percentage 25) 'doom-modeline-battery-warning)
   2803                                  ((< percentage 95) 'doom-modeline-battery-normal)
   2804                                  (t 'doom-modeline-battery-full))
   2805                          'doom-modeline-battery-error))
   2806                  (icon (if valid-percentage?
   2807                            (cond
   2808                             ((>= percentage 100)
   2809                              (doom-modeline-battery-icon (if charging?
   2810                                                              "nf-md-battery_charging_100"
   2811                                                            "nf-md-battery")
   2812                                                          "🔋" "-" face))
   2813                             ((>= percentage 90)
   2814                              (doom-modeline-battery-icon (if charging?
   2815                                                              "nf-md-battery_charging_90"
   2816                                                            "nf-md-battery_90")
   2817                                                          "🔋" "-" face))
   2818                             ((>= percentage 80)
   2819                              (doom-modeline-battery-icon (if charging?
   2820                                                              "nf-md-battery_charging_80"
   2821                                                            "nf-md-battery_80")
   2822                                                          "🔋" "-" face))
   2823                             ((>= percentage 70)
   2824                              (doom-modeline-battery-icon (if charging?
   2825                                                              "nf-md-battery_charging_70"
   2826                                                            "nf-md-battery_70")
   2827                                                          "🔋" "-" face))
   2828                             ((>= percentage 60)
   2829                              (doom-modeline-battery-icon (if charging?
   2830                                                              "nf-md-battery_charging_60"
   2831                                                            "nf-md-battery_60")
   2832                                                          "🔋" "-" face))
   2833                             ((>= percentage 50)
   2834                              (doom-modeline-battery-icon (if charging?
   2835                                                              "nf-md-battery_charging_50"
   2836                                                            "nf-md-battery_50")
   2837                                                          "🔋" "-" face))
   2838                             ((>= percentage 40)
   2839                              (doom-modeline-battery-icon (if charging?
   2840                                                              "nf-md-battery_charging_40"
   2841                                                            "nf-md-battery_40")
   2842                                                          "🔋" "-" face))
   2843                             ((>= percentage 30)
   2844                              (doom-modeline-battery-icon (if charging?
   2845                                                              "nf-md-battery_charging_30"
   2846                                                            "nf-md-battery_30")
   2847                                                          "🔋" "-" face))
   2848                             ((>= percentage 20)
   2849                              (doom-modeline-battery-icon (if charging?
   2850                                                              "nf-md-battery_charging_20"
   2851                                                            "nf-md-battery_20")
   2852                                                          "🔋" "-" face))
   2853                             ((>= percentage 10)
   2854                              (doom-modeline-battery-icon (if charging?
   2855                                                              "nf-md-battery_charging_10"
   2856                                                            "nf-md-battery_10")
   2857                                                          "đŸĒĢ" "-" face))
   2858                             (t (doom-modeline-battery-icon (if charging?
   2859                                                                "nf-md-battery_charging_outline"
   2860                                                              "nf-md-battery_outline")
   2861                                                            "đŸĒĢ" "!" face)))
   2862                          (doom-modeline-battery-icon "nf-md-battery_alert" "⚠" "N/A" face)))
   2863                  (text (if valid-percentage? (format "%d%s" percentage "%%") ""))
   2864                  (help-echo (if (and battery-echo-area-format data valid-percentage?)
   2865                                 (battery-format battery-echo-area-format data)
   2866                               "Battery status not available")))
   2867             (cons (propertize icon 'help-echo help-echo)
   2868                   (propertize text 'face face 'help-echo help-echo))))))
   2869 
   2870 (doom-modeline-add-variable-watcher
   2871  'doom-modeline-icon
   2872  (lambda (_sym val op _where)
   2873    (when (eq op 'set)
   2874      (setq doom-modeline-icon val)
   2875      (doom-modeline-update-battery-status))))
   2876 
   2877 (doom-modeline-add-variable-watcher
   2878  'doom-modeline-unicode-fallback
   2879  (lambda (_sym val op _where)
   2880    (when (eq op 'set)
   2881      (setq doom-modeline-unicode-fallback val)
   2882      (doom-modeline-update-battery-status))))
   2883 
   2884 (doom-modeline-def-segment battery
   2885   "Display battery status."
   2886   (when (and doom-modeline-battery
   2887              (bound-and-true-p display-battery-mode)
   2888              (doom-modeline--segment-visible 'battery))
   2889     (let ((sep (doom-modeline-spc))
   2890           (vsep (doom-modeline-vspc)))
   2891       (concat sep
   2892               (car doom-modeline--battery-status)
   2893               vsep
   2894               (cdr doom-modeline--battery-status)
   2895               sep))))
   2896 
   2897 (defun doom-modeline-override-battery ()
   2898   "Override default battery mode-line."
   2899   (if (and doom-modeline-battery
   2900            (bound-and-true-p doom-modeline-mode))
   2901       (progn
   2902         (advice-add #'battery-update :override #'doom-modeline-update-battery-status)
   2903         (setq global-mode-string
   2904 		      (delq 'battery-mode-line-string global-mode-string))
   2905         (and (bound-and-true-p display-battery-mode) (battery-update)))
   2906     (progn
   2907       (advice-remove #'battery-update #'doom-modeline-update-battery-status)
   2908       (when (and display-battery-mode battery-status-function battery-mode-line-format
   2909                  (not (memq 'battery-mode-line-string global-mode-string)))
   2910         (setq global-mode-string
   2911 		      (append global-mode-string '(battery-mode-line-string)))))))
   2912 (add-hook 'display-battery-mode-hook #'doom-modeline-override-battery)
   2913 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-battery)
   2914 
   2915 (doom-modeline-add-variable-watcher
   2916  'doom-modeline-battery
   2917  (lambda (_sym val op _where)
   2918    (when (eq op 'set)
   2919      (setq doom-modeline-battery val)
   2920      (doom-modeline-override-battery))))
   2921 
   2922 
   2923 ;;
   2924 ;; Package information
   2925 ;;
   2926 
   2927 (doom-modeline-def-segment package
   2928   "Show package information via `paradox'."
   2929   (concat
   2930    (doom-modeline-display-text
   2931     (format-mode-line 'mode-line-front-space))
   2932 
   2933    (when (and doom-modeline-icon doom-modeline-major-mode-icon)
   2934      (concat
   2935       (doom-modeline-spc)
   2936       (doom-modeline-icon 'faicon "nf-fa-archive" nil nil
   2937                           :face (doom-modeline-face
   2938                                  (if doom-modeline-major-mode-color-icon
   2939                                      'nerd-icons-silver
   2940                                    'mode-line)))))
   2941    (doom-modeline-display-text
   2942     (format-mode-line 'mode-line-buffer-identification))))
   2943 
   2944 
   2945 ;;
   2946 ;; Helm
   2947 ;;
   2948 
   2949 (defvar doom-modeline--helm-buffer-ids
   2950   '(("*helm*" . "HELM")
   2951     ("*helm M-x*" . "HELM M-x")
   2952     ("*swiper*" . "SWIPER")
   2953     ("*Projectile Perspectives*" . "HELM Projectile Perspectives")
   2954     ("*Projectile Layouts*" . "HELM Projectile Layouts")
   2955     ("*helm-ag*" . (lambda ()
   2956                      (format "HELM Ag: Using %s"
   2957                              (car (split-string helm-ag-base-command))))))
   2958   "Alist of custom helm buffer names to use.
   2959 The cdr can also be a function that returns a name to use.")
   2960 
   2961 (doom-modeline-def-segment helm-buffer-id
   2962   "Helm session identifier."
   2963   (when (bound-and-true-p helm-alive-p)
   2964     (let ((sep (doom-modeline-spc)))
   2965       (concat
   2966        sep
   2967        (when doom-modeline-icon
   2968          (concat
   2969           (doom-modeline-icon 'sucicon "nf-custom-emacs" nil nil
   2970                               :face (doom-modeline-face
   2971                                      (and doom-modeline-major-mode-color-icon
   2972                                           'nerd-icons-blue)))
   2973           sep))
   2974        (propertize
   2975         (let ((custom (cdr (assoc (buffer-name) doom-modeline--helm-buffer-ids)))
   2976               (case-fold-search t)
   2977               (name (replace-regexp-in-string "-" " " (buffer-name))))
   2978           (cond ((stringp custom) custom)
   2979                 ((functionp custom) (funcall custom))
   2980                 (t
   2981                  (string-match "\\*helm:? \\(mode \\)?\\([^\\*]+\\)\\*" name)
   2982                  (concat "HELM " (capitalize (match-string 2 name))))))
   2983         'face (doom-modeline-face 'doom-modeline-buffer-file))
   2984        sep))))
   2985 
   2986 (doom-modeline-def-segment helm-number
   2987   "Number of helm candidates."
   2988   (when (bound-and-true-p helm-alive-p)
   2989     (concat
   2990      (propertize (format " %d/%d"
   2991                          (helm-candidate-number-at-point)
   2992                          (helm-get-candidate-number t))
   2993                  'face (doom-modeline-face 'doom-modeline-buffer-path))
   2994      (propertize (format " (%d total) " (helm-get-candidate-number))
   2995                  'face (doom-modeline-face 'doom-modeline-info)))))
   2996 
   2997 (doom-modeline-def-segment helm-help
   2998   "Helm keybindings help."
   2999   (when (bound-and-true-p helm-alive-p)
   3000     (mapcar
   3001      (lambda (s)
   3002        (if (string-prefix-p "\\<" s)
   3003            (propertize (substitute-command-keys s)
   3004                        'face (doom-modeline-face
   3005                               'doom-modeline-buffer-file))
   3006          s))
   3007      '("\\<helm-map>\\[helm-help]" "(help) "
   3008        "\\<helm-map>\\[helm-select-action]" "(actions) "
   3009        "\\<helm-map>\\[helm-maybe-exit-minibuffer]/F1/F2..." "(action) "))))
   3010 
   3011 (doom-modeline-def-segment helm-prefix-argument
   3012   "Helm prefix argument."
   3013   (when (and (bound-and-true-p helm-alive-p)
   3014              helm--mode-line-display-prefarg)
   3015     (let ((arg (prefix-numeric-value (or prefix-arg current-prefix-arg))))
   3016       (unless (= arg 1)
   3017         (propertize (format "C-u %s" arg)
   3018                     'face (doom-modeline-face 'doom-modeline-info))))))
   3019 
   3020 (defvar doom-modeline--helm-current-source nil
   3021   "The currently active helm source.")
   3022 (doom-modeline-def-segment helm-follow
   3023   "Helm follow indicator."
   3024   (and (bound-and-true-p helm-alive-p)
   3025        doom-modeline--helm-current-source
   3026        (eq 1 (cdr (assq 'follow doom-modeline--helm-current-source)))
   3027        "HF"))
   3028 
   3029 ;;
   3030 ;; Git timemachine
   3031 ;;
   3032 
   3033 (doom-modeline-def-segment git-timemachine
   3034   (concat
   3035    (doom-modeline-spc)
   3036    (doom-modeline--buffer-mode-icon)
   3037    (doom-modeline--buffer-state-icon)
   3038    (propertize
   3039     "*%b*"
   3040     'face (doom-modeline-face 'doom-modeline-buffer-timemachine))))
   3041 
   3042 ;;
   3043 ;; Markdown/Org preview
   3044 ;;
   3045 
   3046 (doom-modeline-def-segment grip
   3047   (when (bound-and-true-p grip-mode)
   3048     (let ((sep (doom-modeline-spc)))
   3049       (concat
   3050        sep
   3051        (let ((face (doom-modeline-face
   3052                     (if grip--process
   3053                         (pcase (process-status grip--process)
   3054                           ('run 'doom-modeline-info)
   3055                           ('exit 'doom-modeline-warning)
   3056                           (_ 'doom-modeline-urgent))
   3057                       'doom-modeline-urgent))))
   3058          (propertize
   3059           (doom-modeline-icon 'codicon "nf-cod-open_preview" "🗐" "@" :face face)
   3060           'help-echo (format "Preview on %s
   3061 mouse-1: Preview in browser
   3062 mouse-2: Stop preview
   3063 mouse-3: Restart preview"
   3064                              (grip--preview-url))
   3065           'mouse-face 'doom-modeline-highlight
   3066           'local-map (let ((map (make-sparse-keymap)))
   3067                        (define-key map [mode-line mouse-1]
   3068                          #'grip-browse-preview)
   3069                        (define-key map [mode-line mouse-2]
   3070                          #'grip-stop-preview)
   3071                        (define-key map [mode-line mouse-3]
   3072                          #'grip-restart-preview)
   3073                        map)))
   3074        sep))))
   3075 
   3076 ;;
   3077 ;; Follow mode
   3078 ;;
   3079 
   3080 (doom-modeline-def-segment follow
   3081   (when (bound-and-true-p follow-mode)
   3082     (let* ((windows (follow-all-followers))
   3083            (nwindows (length windows))
   3084            (nfollowing (- (length (memq (selected-window) windows)) 1)))
   3085       (concat
   3086        (doom-modeline-spc)
   3087        (propertize (format "Follow %d/%d" (- nwindows nfollowing) nwindows)
   3088                    'face 'doom-modeline-buffer-minor-mode)))))
   3089 
   3090 ;;
   3091 ;; Display time
   3092 ;;
   3093 
   3094 (defconst doom-modeline--clock-hour-hand-ratio 0.45
   3095   "Length of the hour hand as a proportion of the radius.")
   3096 
   3097 (defconst doom-modeline--clock-minute-hand-ratio 0.7
   3098   "Length of the minute hand as a proportion of the radius.")
   3099 
   3100 (defun doom-modeline--create-clock-svg (hour minute radius color)
   3101   "Construct an SVG clock showing the time HOUR:MINUTE.
   3102 The clock will be of the specified RADIUS and COLOR."
   3103   (let ((thickness-factor (image-compute-scaling-factor 'auto))
   3104         (hour-x (* radius (sin (* (- 6 hour (/ minute 60.0)) (/ float-pi 6)))
   3105                    doom-modeline--clock-hour-hand-ratio))
   3106         (hour-y (* radius (cos (* (- 6 hour (/ minute 60.0)) (/ float-pi 6)))
   3107                    doom-modeline--clock-hour-hand-ratio))
   3108         (minute-x (* radius (sin (* (- 30 minute) (/ float-pi 30)))
   3109                      doom-modeline--clock-minute-hand-ratio))
   3110         (minute-y (* radius (cos (* (- 30 minute) (/ float-pi 30)))
   3111                      doom-modeline--clock-minute-hand-ratio))
   3112         (svg (svg-create (* 2 radius) (* 2 radius) :stroke color)))
   3113     (svg-circle svg radius radius (- radius thickness-factor)
   3114                 :fill "none" :stroke-width (* 2 thickness-factor))
   3115     (svg-circle svg radius radius thickness-factor
   3116                 :fill color :stroke "none")
   3117     (svg-line svg radius radius (+ radius hour-x) (+ radius hour-y)
   3118               :stroke-width (* 2 thickness-factor))
   3119     (svg-line svg radius radius (+ radius minute-x) (+ radius minute-y)
   3120               :stroke-width (* 1.5 thickness-factor))
   3121     svg))
   3122 
   3123 (defvar doom-modeline--clock-cache nil
   3124   "The last result of `doom-modeline--generate-clock'.")
   3125 
   3126 (defun doom-modeline--generate-clock ()
   3127   "Return a string containing the current time as an analogue clock svg.
   3128 When the svg library is not available, return nil."
   3129   (cdr
   3130    (or (and (equal (truncate (float-time)
   3131                              (* doom-modeline-time-clock-minute-resolution 60))
   3132                    (car doom-modeline--clock-cache))
   3133             doom-modeline--clock-cache)
   3134        (and (require 'svg nil t)
   3135             (setq doom-modeline--clock-cache
   3136                   (cons (truncate (float-time)
   3137                                   (* doom-modeline-time-clock-minute-resolution 60))
   3138                         (propertize
   3139                          " "
   3140                          'display
   3141                          (svg-image
   3142                           (doom-modeline--create-clock-svg
   3143                            (string-to-number (format-time-string "%-I")) ; hour
   3144                            (* (truncate (string-to-number (format-time-string "%-M"))
   3145                                         doom-modeline-time-clock-minute-resolution)
   3146                               doom-modeline-time-clock-minute-resolution) ; minute
   3147                            (if (integerp doom-modeline-time-clock-size) ; radius
   3148                                doom-modeline-time-clock-size
   3149                              (* doom-modeline-height 0.5 doom-modeline-time-clock-size))
   3150                            "currentColor")
   3151                           :scale 1 :ascent 'center)
   3152                          'face 'doom-modeline-time
   3153                          'help-echo (lambda (_window _object _pos)
   3154                                       (format-time-string "%c")))))))))
   3155 
   3156 (defun doom-modeline-time-icon ()
   3157   "Displays the time icon."
   3158   (or (and doom-modeline-time-live-icon
   3159            doom-modeline-time-analogue-clock
   3160            (display-graphic-p)
   3161            (doom-modeline--generate-clock))
   3162       (doom-modeline-icon
   3163        'mdicon
   3164        (if doom-modeline-time-live-icon
   3165            (pcase (% (caddr (decode-time)) 12)
   3166              (0 "nf-md-clock_time_twelve_outline")
   3167              (1 "nf-md-clock_time_one_outline")
   3168              (2 "nf-md-clock_time_two_outline")
   3169              (3 "nf-md-clock_time_three_outline")
   3170              (4 "nf-md-clock_time_four_outline")
   3171              (5 "nf-md-clock_time_five_outline")
   3172              (6 "nf-md-clock_time_six_outline")
   3173              (7 "nf-md-clock_time_seven_outline")
   3174              (8 "nf-md-clock_time_eight_outline")
   3175              (9 "nf-md-clock_time_nine_outline")
   3176              (10 "nf-md-clock_time_ten_outline")
   3177              (11 "nf-md-clock_time_eleven_outline"))
   3178          "nf-md-clock_outline")
   3179        "⏰"
   3180        ""
   3181        :face '(:inherit doom-modeline-time :weight normal))))
   3182 
   3183 (doom-modeline-def-segment time
   3184   (when (and doom-modeline-time
   3185              (bound-and-true-p display-time-mode)
   3186              (doom-modeline--segment-visible 'time))
   3187     (concat
   3188      (doom-modeline-spc)
   3189      (when doom-modeline-time-icon
   3190        (concat
   3191         (doom-modeline-time-icon)
   3192         (and (or doom-modeline-icon doom-modeline-unicode-fallback)
   3193              (doom-modeline-vspc))))
   3194      (propertize display-time-string
   3195                  'face (doom-modeline-face 'doom-modeline-time)))))
   3196 
   3197 (defun doom-modeline-override-time ()
   3198   "Override default `display-time' mode-line."
   3199   (or global-mode-string (setq global-mode-string '("")))
   3200   (if (and doom-modeline-time
   3201            (bound-and-true-p doom-modeline-mode))
   3202       (setq global-mode-string (delq 'display-time-string global-mode-string))
   3203     (or (memq 'display-time-string global-mode-string)
   3204 	    (setq global-mode-string
   3205 		      (append global-mode-string '(display-time-string))))))
   3206 (add-hook 'display-time-mode-hook #'doom-modeline-override-time)
   3207 (add-hook 'doom-modeline-mode-hook #'doom-modeline-override-time)
   3208 
   3209 (doom-modeline-add-variable-watcher
   3210  'doom-modeline-time
   3211  (lambda (_sym val op _where)
   3212    (when (eq op 'set)
   3213      (setq doom-modeline-time val)
   3214      (doom-modeline-override-time))))
   3215 
   3216 ;;
   3217 ;; Compilation
   3218 ;;
   3219 
   3220 (doom-modeline-def-segment compilation
   3221   (and (bound-and-true-p compilation-in-progress)
   3222        (propertize "[Compiling] "
   3223                    'face (doom-modeline-face 'doom-modeline-compilation)
   3224 	               'help-echo "Compiling; mouse-2: Goto Buffer"
   3225                    'mouse-face 'doom-modeline-highlight
   3226                    'local-map
   3227                    (make-mode-line-mouse-map
   3228                     'mouse-2
   3229                     #'compilation-goto-in-progress-buffer))))
   3230 
   3231 ;;
   3232 ;; Eldoc
   3233 ;;
   3234 
   3235 (doom-modeline-def-segment eldoc
   3236   (and (bound-and-true-p eldoc-mode)
   3237        '(eldoc-mode-line-string
   3238 		 (" " eldoc-mode-line-string " "))))
   3239 
   3240 (defun doom-modeline-eldoc-minibuffer-message (format-string &rest args)
   3241   "Display message specified by FORMAT-STRING and ARGS on the mode-line as needed.
   3242 This function displays the message produced by formatting ARGS
   3243 with FORMAT-STRING on the mode line when the current buffer is a minibuffer.
   3244 Otherwise, it displays the message like `message' would."
   3245   (if (minibufferp)
   3246       (progn
   3247 	    (add-hook 'minibuffer-exit-hook
   3248 		          (lambda () (setq eldoc-mode-line-string nil
   3249 			                  ;; https://debbugs.gnu.org/16920
   3250 			                  eldoc-last-message nil))
   3251 		          nil t)
   3252 	    (with-current-buffer
   3253 	        (window-buffer
   3254 	         (or (window-in-direction 'above (minibuffer-window))
   3255                  (minibuffer-selected-window)
   3256 		         (get-largest-window)))
   3257           (setq eldoc-mode-line-string
   3258                 (when (stringp format-string)
   3259                   (apply #'format-message format-string args)))
   3260           (force-mode-line-update)))
   3261     (apply #'message format-string args)))
   3262 
   3263 ;;
   3264 ;; Kubernetes
   3265 ;;
   3266 
   3267 (doom-modeline-def-segment k8s
   3268   (when (and (bound-and-true-p kele-mode) (doom-modeline--segment-visible 'k8s))
   3269     (let* ((ctx (kele-current-context-name :wait nil))
   3270            (ns (kele-current-namespace :wait nil))
   3271            (icon (doom-modeline-icon 'mdicon "nf-md-kubernetes" "K8s:" "K8s:"))
   3272            (sep (doom-modeline-spc))
   3273            (help-msg (let ((msgs (list (format "Current context: %s" ctx))))
   3274                        (when ns
   3275                          (setq msgs (append msgs (list (format "Current namespace: %s" ns)))))
   3276                        (string-join msgs "\n"))))
   3277       (propertize (concat
   3278                    icon sep ctx
   3279                    (when (and doom-modeline-k8s-show-namespace ns) (format "(%s)" ns))
   3280                    sep)
   3281                   'local-map (let ((map (make-sparse-keymap)))
   3282                                (define-key map [mode-line down-mouse-1] kele-menu-map)
   3283                                map)
   3284                   'mouse-face 'doom-modeline-highlight
   3285                   'help-echo help-msg))))
   3286 
   3287 (provide 'doom-modeline-segments)
   3288 
   3289 ;;; doom-modeline-segments.el ends here