config

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

doom-modeline-segments.el (135950B)


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