config

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

doom-modeline-segments.el (137283B)


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