config

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

doom-modeline-segments.el (137196B)


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