config

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

doom-modeline-segments.el (136458B)


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