config

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

doom-modeline-segments.el (136068B)


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