config

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

doom-modeline-segments.el (137566B)


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