config

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

doom-modeline-segments.el (136064B)


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