diff --git a/code/elpa/doom-modeline-20220412.853/doom-modeline-autoloads.el b/code/elpa/doom-modeline-20220412.853/doom-modeline-autoloads.el new file mode 100644 index 0000000..481641c --- /dev/null +++ b/code/elpa/doom-modeline-20220412.853/doom-modeline-autoloads.el @@ -0,0 +1,135 @@ +;;; doom-modeline-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "doom-modeline" "doom-modeline.el" (0 0 0 0)) +;;; Generated autoloads from doom-modeline.el + +(autoload 'doom-modeline-init "doom-modeline" "\ +Initialize doom mode-line." nil nil) + +(autoload 'doom-modeline-set-main-modeline "doom-modeline" "\ +Set main mode-line. +If DEFAULT is non-nil, set the default mode-line for all buffers. + +\(fn &optional DEFAULT)" nil nil) + +(autoload 'doom-modeline-set-minimal-modeline "doom-modeline" "\ +Set minimal mode-line." nil nil) + +(autoload 'doom-modeline-set-special-modeline "doom-modeline" "\ +Set special mode-line." nil nil) + +(autoload 'doom-modeline-set-project-modeline "doom-modeline" "\ +Set project mode-line." nil nil) + +(autoload 'doom-modeline-set-dashboard-modeline "doom-modeline" "\ +Set dashboard mode-line." nil nil) + +(autoload 'doom-modeline-set-vcs-modeline "doom-modeline" "\ +Set vcs mode-line." nil nil) + +(autoload 'doom-modeline-set-info-modeline "doom-modeline" "\ +Set Info mode-line." nil nil) + +(autoload 'doom-modeline-set-package-modeline "doom-modeline" "\ +Set package mode-line." nil nil) + +(autoload 'doom-modeline-set-media-modeline "doom-modeline" "\ +Set media mode-line." nil nil) + +(autoload 'doom-modeline-set-message-modeline "doom-modeline" "\ +Set message mode-line." nil nil) + +(autoload 'doom-modeline-set-pdf-modeline "doom-modeline" "\ +Set pdf mode-line." nil nil) + +(autoload 'doom-modeline-set-org-src-modeline "doom-modeline" "\ +Set org-src mode-line." nil nil) + +(autoload 'doom-modeline-set-helm-modeline "doom-modeline" "\ +Set helm mode-line. + +\(fn &rest _)" nil nil) + +(autoload 'doom-modeline-set-timemachine-modeline "doom-modeline" "\ +Set timemachine mode-line." nil nil) + +(defvar doom-modeline-mode nil "\ +Non-nil if Doom-Modeline mode is enabled. +See the `doom-modeline-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `doom-modeline-mode'.") + +(custom-autoload 'doom-modeline-mode "doom-modeline" nil) + +(autoload 'doom-modeline-mode "doom-modeline" "\ +Toggle doom-modeline on or off. + +This is a minor mode. If called interactively, toggle the +`Doom-Modeline mode' mode. If the prefix argument is positive, +enable the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `(default-value \\='doom-modeline-mode)'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +\(fn &optional ARG)" t nil) + +(register-definition-prefixes "doom-modeline" '("doom-modeline-mode-map")) + +;;;*** + +;;;### (autoloads nil "doom-modeline-core" "doom-modeline-core.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from doom-modeline-core.el + +(register-definition-prefixes "doom-modeline-core" '("doom-modeline")) + +;;;*** + +;;;### (autoloads nil "doom-modeline-env" "doom-modeline-env.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from doom-modeline-env.el + (autoload 'doom-modeline-env-setup-python "doom-modeline-env") + (autoload 'doom-modeline-env-setup-ruby "doom-modeline-env") + (autoload 'doom-modeline-env-setup-perl "doom-modeline-env") + (autoload 'doom-modeline-env-setup-go "doom-modeline-env") + (autoload 'doom-modeline-env-setup-elixir "doom-modeline-env") + (autoload 'doom-modeline-env-setup-rust "doom-modeline-env") + +(register-definition-prefixes "doom-modeline-env" '("doom-modeline-")) + +;;;*** + +;;;### (autoloads nil "doom-modeline-segments" "doom-modeline-segments.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from doom-modeline-segments.el + +(register-definition-prefixes "doom-modeline-segments" '("doom-modeline-")) + +;;;*** + +;;;### (autoloads nil nil ("doom-modeline-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; doom-modeline-autoloads.el ends here diff --git a/code/elpa/doom-modeline-20220412.853/doom-modeline-core.el b/code/elpa/doom-modeline-20220412.853/doom-modeline-core.el new file mode 100644 index 0000000..86360f1 --- /dev/null +++ b/code/elpa/doom-modeline-20220412.853/doom-modeline-core.el @@ -0,0 +1,1394 @@ +;;; doom-modeline-core.el --- The core libraries for doom-modeline -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2020 Vincent Zhang + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . +;; + +;;; Commentary: +;; +;; The core libraries for doom-modeline. +;; + +;;; Code: + +(require 'cl-lib) +(require 'subr-x) +(require 'dash) +(require 'all-the-icons) +(require 'shrink-path) + + +;; +;; Compatibility +;; + +(eval-and-compile + (when (< emacs-major-version 26) + ;; Define `if-let*' and `when-let*' variants for 25 users. + (unless (fboundp 'if-let*) (defalias 'if-let* #'if-let)) + (unless (fboundp 'when-let*) (defalias 'when-let* #'when-let)))) + +;; Don’t compact font caches during GC. +(when (eq system-type 'windows-nt) + (setq inhibit-compacting-font-caches t)) + +;;`file-local-name' is introduced in 25.2.2. +(unless (fboundp 'file-local-name) + (defun file-local-name (file) + "Return the local name component of FILE. +It returns a file name which can be used directly as argument of +`process-file', `start-file-process', or `shell-command'." + (or (file-remote-p file 'localname) file))) + +;; Set correct font width for `all-the-icons' for appropriate mode-line width. +;; @see https://emacs.stackexchange.com/questions/14420/how-can-i-fix-incorrect-character-width +(defun doom-modeline--set-char-widths (alist) + "Set correct widths of icons characters in ALIST." + (while (char-table-parent char-width-table) + (setq char-width-table (char-table-parent char-width-table))) + (dolist (pair alist) + (let ((width (car pair)) + (chars (cdr pair)) + (table (make-char-table nil))) + (dolist (char chars) + (set-char-table-range table char width)) + (optimize-char-table table) + (set-char-table-parent table char-width-table) + (setq char-width-table table)))) + +(defconst doom-modeline-rhs-icons-alist + '((2 . (;; VCS + ?\xf0ac ; git-compare + ?\xf023 ; git-merge + ?\xf03f ; arrow-down + ?\xf02d ; alert + ?\xf020 ; git-branch + + ;; Checker + ?\xe611 ; do_not_disturb_alt + ?\xe5ca ; check + ?\xe192 ; access_time + ?\xe624 ; sim_card_alert + ?\xe034 ; pause + ?\xe645 ; priority_high + + ;; Minor modes + ?\xf02f ; gear + + ;; Persp + ?\xe2c7 ; folder + + ;; Preview + ?\xe8a0 ; pageview + + ;; REPL + ?\xf155 ; dollar-sign + + ;; LSP + ?\xf135 ; rocket + + ;; GitHub + ?\xf09b ; github + + ;; Debug + ?\xf188 ; bug + + ;; Mail + ?\xe0be ; email + + ;; IRC + ?\xe0c9 ; message + + ;; Battery + ?\xe939 ; battery-charging + ?\xf244 ; battery-empty + ?\xf240 ; battery-full + ?\xf242 ; battery-half + ?\xf243 ; battery-quarter + ?\xf241 ; battery-three-quarters + )))) + +(defun doom-modeline-set-char-widths (&rest _) + "Set char widths for the unicode icons." + (doom-modeline--set-char-widths doom-modeline-rhs-icons-alist)) + +(if (and (daemonp) + (not (frame-parameter nil 'client))) + (add-hook 'after-make-frame-functions #'doom-modeline-set-char-widths) + (and (display-graphic-p) (doom-modeline-set-char-widths))) + + +;; +;; Customization +;; + +(defgroup doom-modeline nil + "A minimal and modern mode-line." + :group 'mode-line + :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) + +(defcustom doom-modeline-support-imenu nil + "If non-nil, cause imenu to see `doom-modeline' declarations. +This is done by adjusting `lisp-imenu-generic-expression' to +include support for finding `doom-modeline-def-*' forms. + +Must be set before loading doom-modeline." + :type 'boolean + :set (lambda (_sym val) + (if val + (add-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu) + (remove-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu))) + :group 'doom-modeline) + +(defcustom doom-modeline-height 25 + "How tall the mode-line should be. It's only respected in GUI. +If the actual char height is larger, it respects the actual char height. +If `doom-modeline-height' is <= 0 the modeline will have default height." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-bar-width 4 + "How wide the mode-line bar should be. It's only respected in GUI." + :type 'integer + :set (lambda (sym val) + (set sym (if (> val 0) val 1))) + :group 'doom-modeline) + +(defcustom doom-modeline-hud nil + "Whether to use hud instead of default bar. It's only respected in GUI." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-hud-min-height 2 + "Minimum height in pixels of the \"thumb\" of the hud. +Only respected in GUI." + :type 'integer + :set (lambda (sym val) + (set sym (if (> val 1) val 1))) + :group 'doom-modeline) + +(defcustom doom-modeline-window-width-limit 0.25 + "The limit of the window width. + +If `window-width' is smaller than the limit, some information won't be +displayed. It can be an integer or a float number. `nil' means no limit." + :type '(choice integer + float + (const :tag "Disable" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-project-detection 'auto + "How to detect the project root. + +nil means to use `default-directory'. + +The project management packages have some issues on detecting project root. +e.g. `projectile' doesn't handle symlink folders well, while `project' is +unable to handle sub-projects. +Specify another one if you encounter the issue." + :type '(choice (const :tag "Auto-detect" auto) + (const :tag "Find File in Project" ffip) + (const :tag "Projectile" projectile) + (const :tag "Built-in Project" project) + (const :tag "Disable" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-file-name-style 'auto + "Determines the style used by `doom-modeline-buffer-file-name'. + +Given ~/Projects/FOSS/emacs/lisp/comint.el + auto => emacs/lisp/comint.el (in a project) or comint.el + truncate-upto-project => ~/P/F/emacs/lisp/comint.el + truncate-from-project => ~/Projects/FOSS/emacs/l/comint.el + truncate-with-project => emacs/l/comint.el + truncate-except-project => ~/P/F/emacs/l/comint.el + truncate-upto-root => ~/P/F/e/lisp/comint.el + truncate-all => ~/P/F/e/l/comint.el + truncate-nil => ~/Projects/FOSS/emacs/lisp/comint.el + relative-from-project => emacs/lisp/comint.el + relative-to-project => lisp/comint.el + file-name => comint.el + buffer-name => comint.el<2> (uniquify buffer name)" + :type '(choice (const auto) + (const truncate-upto-project) + (const truncate-upto-project) + (const truncate-from-project) + (const truncate-with-project) + (const truncate-except-project) + (const truncate-upto-root) + (const truncate-all) + (const truncate-nil) + (const relative-from-project) + (const relative-to-project) + (const file-name) + (const buffer-name)) + :group'doom-modeline) + +(defcustom doom-modeline-icon t + "Whether display the icons in the mode-line. + +While using the server mode in GUI, should set the value explicitly." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-major-mode-icon t + "Whether display the icon for `major-mode'. + +It respects `doom-modeline-icon'." + :type 'boolean + :group'doom-modeline) + +(defcustom doom-modeline-major-mode-color-icon t + "Whether display the colorful icon for `major-mode'. + +It respects `all-the-icons-color-icons'." + :type 'boolean + :group'doom-modeline) + +(defcustom doom-modeline-buffer-state-icon t + "Whether display the icon for the buffer state. + +It respects `doom-modeline-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-modification-icon t + "Whether display the modification icon for the buffer. + +It respects `doom-modeline-icon' and `doom-modeline-buffer-state-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-unicode-fallback nil + "Whether to use unicode as a fallback (instead of ASCII) when not using icons." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-name t + "Whether display the buffer name." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-minor-modes nil + "Whether display the minor modes in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-enable-word-count nil + "If non-nil, a word count will be added to the selection-info modeline segment." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-continuous-word-count-modes + '(markdown-mode gfm-mode org-mode) + "Major modes in which to display word count continuously. + +It respects `doom-modeline-enable-word-count'." + :type '(repeat (symbol :tag "Major-Mode") ) + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-encoding t + "Whether display the buffer encoding." + :type '(choice (const :tag "Always" t) + (const :tag "When non-default" nondefault) + (const :tag "Never" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-default-coding-system 'utf-8 + "Default coding system for `doom-modeline-buffer-encoding' `nondefault'." + :type 'coding-system + :group 'doom-modeline) + +(defcustom doom-modeline-default-eol-type 0 + "Default EOL type for `doom-modeline-buffer-encoding' `nondefault'." + :type '(choice (const :tag "Unix-style LF" 0) + (const :tag "DOS-style CRLF" 1) + (const :tag "Mac-style CR" 2)) + :group 'doom-modeline) + +(defcustom doom-modeline-indent-info nil + "Whether display the indentation information." + :type 'boolean + :group 'doom-modeline) + +;; It is based upon `editorconfig-indentation-alist' but is used to read indentation levels instead +;; of setting them. (https://github.com/editorconfig/editorconfig-emacs) +(defcustom doom-modeline-indent-alist + '((apache-mode apache-indent-level) + (awk-mode c-basic-offset) + (bpftrace-mode c-basic-offset) + (c++-mode c-basic-offset) + (c-mode c-basic-offset) + (cmake-mode cmake-tab-width) + (coffee-mode coffee-tab-width) + (cperl-mode cperl-indent-level) + (crystal-mode crystal-indent-level) + (csharp-mode c-basic-offset) + (css-mode css-indent-offset) + (d-mode c-basic-offset) + (emacs-lisp-mode lisp-indent-offset) + (enh-ruby-mode enh-ruby-indent-level) + (erlang-mode erlang-indent-level) + (ess-mode ess-indent-offset) + (f90-mode f90-associate-indent + f90-continuation-indent + f90-critical-indent + f90-do-indent + f90-if-indent + f90-program-indent + f90-type-indent) + (feature-mode feature-indent-offset + feature-indent-level) + (fsharp-mode fsharp-continuation-offset + fsharp-indent-level + fsharp-indent-offset) + (groovy-mode groovy-indent-offset) + (haskell-mode haskell-indent-spaces + haskell-indent-offset + haskell-indentation-layout-offset + haskell-indentation-left-offset + haskell-indentation-starter-offset + haskell-indentation-where-post-offset + haskell-indentation-where-pre-offset + shm-indent-spaces) + (haxor-mode haxor-tab-width) + (idl-mode c-basic-offset) + (jade-mode jade-tab-width) + (java-mode c-basic-offset) + (js-mode js-indent-level) + (js-jsx-mode js-indent-level + sgml-basic-offset) + (js2-mode js2-basic-offset) + (js2-jsx-mode js2-basic-offset + sgml-basic-offset) + (js3-mode js3-indent-level) + (json-mode js-indent-level) + (julia-mode julia-indent-offset) + (kotlin-mode kotlin-tab-width) + (latex-mode tex-indent-basic) + (lisp-mode lisp-indent-offset) + (livescript-mode livescript-tab-width) + (lua-mode lua-indent-level) + (matlab-mode matlab-indent-level) + (mips-mode mips-tab-width) + (mustache-mode mustache-basic-offset) + (nasm-mode nasm-basic-offset) + (nginx-mode nginx-indent-level) + (nxml-mode nxml-child-indent) + (objc-mode c-basic-offset) + (octave-mode octave-block-offset) + (perl-mode perl-indent-level) + (php-mode c-basic-offset) + (pike-mode c-basic-offset) + (ps-mode ps-mode-tab) + (pug-mode pug-tab-width) + (puppet-mode puppet-indent-level) + (python-mode python-indent-offset) + (ruby-mode ruby-indent-level) + (rust-mode rust-indent-offset) + (rustic-mode rustic-indent-offset) + (scala-mode scala-indent:step) + (scss-mode css-indent-offset) + (sgml-mode sgml-basic-offset) + (sh-mode sh-basic-offset + sh-indentation) + (slim-mode slim-indent-offset) + (sml-mode sml-indent-level) + (tcl-mode tcl-indent-level + tcl-continued-indent-level) + (terra-mode terra-indent-level) + (typescript-mode typescript-indent-level) + (verilog-mode verilog-indent-level + verilog-indent-level-behavioral + verilog-indent-level-declaration + verilog-indent-level-module + verilog-cexp-indent + verilog-case-indent) + (web-mode web-mode-attr-indent-offset + web-mode-attr-value-indent-offset + web-mode-code-indent-offset + web-mode-css-indent-offset + web-mode-markup-indent-offset + web-mode-sql-indent-offset + web-mode-block-padding + web-mode-script-padding + web-mode-style-padding) + (yaml-mode yaml-indent-offset)) + "Indentation retrieving variables matched to major modes used + when `doom-modeline-indent-info' is non-nil. When multiple + variables are specified for a mode, they will be tried resolved + in the given order." + :type '(alist :key-type symbol :value-type sexp) + :group 'doom-modeline) + +(defcustom doom-modeline-checker-simple-format t + "If non-nil, only display one number for checker information if applicable." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-number-limit 99 + "The maximum number displayed for notifications." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-vcs-max-length 12 + "The maximum displayed length of the branch name of version control." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-workspace-name t + "Whether display the workspace name. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-persp-name t + "Whether display the perspective name. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-display-default-persp-name nil + "If non nil the default perspective name is displayed in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-persp-icon t + "If non nil the perspective name is displayed alongside a folder icon." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-repl t + "Whether display the `repl' state. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-lsp t + "Whether display the `lsp' state. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-github nil + "Whether display the GitHub notifications. + +It requires `ghub' and `async' packages." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-github-interval 1800 ; (* 30 60) + "The interval of checking GitHub." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-env-version t + "Whether display the environment version." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-modal-icon t + "Whether display the modal state icon. + +Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-mu4e nil + "Whether display the mu4e notifications. + +It requires `mu4e-alert' package." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-gnus nil + "Whether to display notifications from gnus. + +It requires `gnus' to be setup" + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-timer 2 + "The wait time in minutes before gnus fetches mail. + +If nil, don't set up a hook." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-idle nil + "Whether to wait an idle time to scan for news. + +When t, sets `doom-modeline-gnus-timer' as an idle timer. If a +number, Emacs must have been idle this given time, checked after +reach the defined timer, to fetch news. The time step can be +configured in `gnus-demon-timestep'." + :type '(choice + (boolean :tag "Set `doom-modeline-gnus-timer' as an idle timer") + (number :tag "Set a custom idle timer")) + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-excluded-groups nil + "A list of groups to be excluded from the unread count. +Groups' names list in `gnus-newsrc-alist'`" + :type '(repeat string) + :group 'doom-modeline) + +(defcustom doom-modeline-irc t + "Whether display the irc notifications. + +It requires `circe' or `erc' package." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-irc-buffers nil + "Whether display the unread irc buffers." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-irc-stylize 'identity + "Function to stylize the irc buffer names." + :type 'function + :group 'doom-modeline) + + +;; +;; Faces +;; + +(defgroup doom-modeline-faces nil + "The faces of `doom-modeline'." + :group 'doom-modeline + :group 'faces + :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) + +(defface doom-modeline-spc-face + '((t (:inherit mode-line))) + "Face used for the white space." + :group 'doom-modeline-faces) + +(defface doom-modeline-spc-inactive-face + '((t (:inherit mode-line-inactive))) + "Face used for the inactive white space." + :group 'doom-modeline-faces) + +(defface doom-modeline-vspc-face + '((t (:inherit variable-pitch))) + "Face used for the variable white space." + :group 'doom-modeline-faces) + +(defface doom-modeline-vspc-inactive-face + '((t (:inherit (mode-line-inactive doom-modeline-vspc-face)))) + "Face used for the variable white space." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-path + '((t (:inherit (mode-line-emphasis bold)))) + "Face used for the dirname part of the buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-file + '((t (:inherit (mode-line-buffer-id bold)))) + "Face used for the filename part of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-modified + '((t (:inherit (error bold) :background nil))) + "Face used for the 'unsaved' symbol in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-major-mode + '((t (:inherit (mode-line-emphasis bold)))) + "Face used for the major-mode segment in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-minor-mode + '((t (:inherit font-lock-doc-face :slant normal))) + "Face used for the minor-modes segment in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-parent-dir + '((t (:inherit (font-lock-comment-face bold)))) + "Face used for the project parent directory of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-dir + '((t (:inherit (font-lock-string-face bold)))) + "Face used for the project directory of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-root-dir + '((t (:inherit (mode-line-emphasis bold)))) + "Face used for the project part of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-highlight + '((t (:inherit mode-line-emphasis))) + "Face for bright segments of the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-panel + '((t (:inherit mode-line-highlight))) + "Face for 'X out of Y' segments, such as `anzu', `evil-substitute' and`iedit', etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-host + '((t (:inherit italic))) + "Face for remote hosts in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-input-method + '((t (:inherit (mode-line-emphasis bold)))) + "Face for input method in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-input-method-alt + '((t (:inherit (font-lock-doc-face bold) :slant normal))) + "Alternative face for input method in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-debug + '((t (:inherit (font-lock-doc-face bold) :slant normal))) + "Face for debug-level messages in the mode-line. Used by vcs, checker, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-info + '((t (:inherit (success bold)))) + "Face for info-level messages in the mode-line. Used by vcs, checker, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-warning + '((t (:inherit (warning bold)))) + "Face for warnings in the mode-line. Used by vcs, checker, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-urgent + '((t (:inherit (error bold)))) + "Face for errors in the mode-line. Used by vcs, checker, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-notification + '((t (:inherit doom-modeline-warning))) + "Face for notifications in the mode-line. Used by GitHub, mu4e, +etc. (also see the face `doom-modeline-unread-number')." + :group 'doom-modeline-faces) + +(defface doom-modeline-unread-number + '((t (:slant italic :weight normal))) + "Face for unread number in the mode-line. Used by GitHub, mu4e, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-bar + '((t (:inherit highlight))) + "The face used for the left-most bar in the mode-line of an active window." + :group 'doom-modeline-faces) + +(defface doom-modeline-bar-inactive + `((t (:background ,(face-foreground 'mode-line-inactive)))) + "The face used for the left-most bar in the mode-line of an inactive window." + :group 'doom-modeline-faces) + +(defface doom-modeline-debug-visual + `((((class color) (background light)) + (:background ,(face-foreground 'all-the-icons-orange))) + (((class color) (background dark)) + (:background ,(face-foreground 'all-the-icons-dorange)))) + "Face to use for the mode-line while debugging." + :group 'doom-modeline) + +(defface doom-modeline-evil-emacs-state + '((t (:inherit (font-lock-builtin-face bold)))) + "Face for the Emacs state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-insert-state + '((t (:inherit (font-lock-keyword-face bold)))) + "Face for the insert state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-motion-state + '((t :inherit (font-lock-doc-face bold) :slant normal)) + "Face for the motion state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-normal-state + '((t (:inherit doom-modeline-info))) + "Face for the normal state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-operator-state + '((t (:inherit doom-modeline-buffer-file))) + "Face for the operator state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-visual-state + '((t (:inherit doom-modeline-warning))) + "Face for the visual state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-replace-state + '((t (:inherit doom-modeline-urgent))) + "Face for the replace state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-persp-name + '((t (:inherit (font-lock-comment-face italic)))) + "Face for the persp name." + :group 'doom-modeline-faces) + +(defface doom-modeline-persp-buffer-not-in-persp + '((t (:inherit (font-lock-doc-face bold italic)))) + "Face for the buffers which are not in the persp." + :group 'doom-modeline-faces) + +(defface doom-modeline-repl-success + '((t (:inherit success :weight normal))) + "Face for REPL success state." + :group 'doom-modeline-faces) + +(defface doom-modeline-repl-warning + '((t (:inherit warning :weight normal))) + "Face for REPL warning state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-success + '((t (:inherit success :weight normal))) + "Face for LSP success state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-warning + '((t (:inherit warning :weight normal))) + "Face for LSP warning state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-error + '((t (:inherit error :weight normal))) + "Face for LSP error state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-running + '((t (:inherit compilation-mode-line-run :weight normal :slant normal))) + "Face for LSP running state." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-charging + '((t (:inherit success :weight normal))) + "Face for battery charging status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-full + '((t (:inherit success :weight normal))) + "Face for battery full status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-normal + '((t (:inherit mode-line :weight normal))) + "Face for battery normal status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-warning + '((t (:inherit warning :weight normal))) + "Face for battery warning status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-critical + '((t (:inherit error :weight normal))) + "Face for battery critical status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-error + '((t (:inherit error :weight normal))) + "Face for battery error status." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-timemachine + '((t (:inherit doom-modeline-buffer-file :slant italic))) + "Face for timemachine status." + :group 'doom-modeline-faces) + + +;; +;; Externals +;; + +(declare-function face-remap-remove-relative "face-remap") +(declare-function ffip-get-project-root-directory "ext:find-file-in-project") +(declare-function project-root "ext:project") +(declare-function projectile-project-root "ext:projectile") + + +;; +;; Utilities +;; + +(defun doom-modeline-add-font-lock () + "Fontify `doom-modeline-def-*' statements." + (font-lock-add-keywords + 'emacs-lisp-mode + '(("(\\(doom-modeline-def-.+\\)\\_> +\\(.*?\\)\\_>" + (1 font-lock-keyword-face) + (2 font-lock-constant-face))))) +(doom-modeline-add-font-lock) + +(defun doom-modeline-add-imenu () + "Add to `imenu' index." + (add-to-list + 'imenu-generic-expression + '("Modelines" + "^\\s-*(\\(doom-modeline-def-modeline\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\s'\\|\\\\.\\)+\\)" + 2)) + (add-to-list + 'imenu-generic-expression + '("Segments" + "^\\s-*(\\(doom-modeline-def-segment\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" + 2)) + (add-to-list + 'imenu-generic-expression + '("Envs" + "^\\s-*(\\(doom-modeline-def-env\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" + 2))) + + +;; +;; Core helpers +;; + +;; FIXME #183: Force to calculate mode-line height +;; @see https://github.com/seagle0128/doom-modeline/issues/183 +;; @see https://github.com/seagle0128/doom-modeline/issues/483 +(defun doom-modeline-redisplay (&rest _) + "Call `redisplay' to trigger mode-line height calculations. + +Certain functions, including e.g. `fit-window-to-buffer', base +their size calculations on values which are incorrect if the +mode-line has a height different from that of the `default' face +and certain other calculations have not yet taken place for the +window in question. + +These calculations can be triggered by calling `redisplay' +explicitly at the appropriate time and this functions purpose +is to make it easier to do so. + +This function is like `redisplay' with non-nil FORCE argument, +but it will only trigger a redisplay when there is a non nil +`mode-line-format' and the height of the mode-line is different +from that of the `default' face. This function is intended to be +used as an advice to window creation functions." + (when (and (bound-and-true-p doom-modeline-mode) + mode-line-format + (/= (frame-char-height) (window-mode-line-height))) + (redisplay t))) +(unless (>= emacs-major-version 29) + (advice-add #'fit-window-to-buffer :before #'doom-modeline-redisplay)) + +;; Keep `doom-modeline-current-window' up-to-date +(defun doom-modeline--get-current-window (&optional frame) + "Get the current window but should exclude the child windows." + (if (and (fboundp 'frame-parent) (frame-parent frame)) + (frame-selected-window (frame-parent frame)) + (frame-selected-window frame))) + +(defvar doom-modeline-current-window (doom-modeline--get-current-window)) + +(defun doom-modeline--active () + "Whether is an active window." + (unless (and (bound-and-true-p mini-frame-frame) + (and (frame-live-p mini-frame-frame) + (frame-visible-p mini-frame-frame))) + (and doom-modeline-current-window + (eq (doom-modeline--get-current-window) doom-modeline-current-window)))) + +(defun doom-modeline-set-selected-window (&rest _) + "Set `doom-modeline-current-window' appropriately." + (let ((win (doom-modeline--get-current-window))) + (setq doom-modeline-current-window + (if (minibuffer-window-active-p win) + (minibuffer-selected-window) + win)))) + +(defun doom-modeline-unset-selected-window () + "Unset `doom-modeline-current-window' appropriately." + (setq doom-modeline-current-window nil)) + +(add-hook 'pre-redisplay-functions #'doom-modeline-set-selected-window) + +;; Ensure modeline is inactive when Emacs is unfocused (and active otherwise) +(defvar doom-modeline-remap-face-cookie nil) +(defun doom-modeline-focus () + "Focus mode-line." + (when doom-modeline-remap-face-cookie + (require 'face-remap) + (face-remap-remove-relative doom-modeline-remap-face-cookie))) +(defun doom-modeline-unfocus () + "Unfocus mode-line." + (setq doom-modeline-remap-face-cookie + (face-remap-add-relative 'mode-line 'mode-line-inactive))) + +(with-no-warnings + (if (boundp 'after-focus-change-function) + (progn + (defun doom-modeline-focus-change (&rest _) + (if (frame-focus-state) + (doom-modeline-focus) + (doom-modeline-unfocus))) + (advice-add #'handle-switch-frame :after #'doom-modeline-focus-change) + (add-function :after after-focus-change-function #'doom-modeline-focus-change)) + (progn + (add-hook 'focus-in-hook #'doom-modeline-focus) + (add-hook 'focus-out-hook #'doom-modeline-unfocus)))) + + +;; +;; Core +;; + +(defvar doom-modeline-fn-alist ()) +(defvar doom-modeline-var-alist ()) + +(defmacro doom-modeline-def-segment (name &rest body) + "Defines a modeline segment NAME with BODY and byte compiles it." + (declare (indent defun) (doc-string 2)) + (let ((sym (intern (format "doom-modeline-segment--%s" name))) + (docstring (if (stringp (car body)) + (pop body) + (format "%s modeline segment" name)))) + (cond ((and (symbolp (car body)) + (not (cdr body))) + (add-to-list 'doom-modeline-var-alist (cons name (car body))) + `(add-to-list 'doom-modeline-var-alist (cons ',name ',(car body)))) + (t + (add-to-list 'doom-modeline-fn-alist (cons name sym)) + `(progn + (fset ',sym (lambda () ,docstring ,@body)) + (add-to-list 'doom-modeline-fn-alist (cons ',name ',sym)) + ,(unless (bound-and-true-p byte-compile-current-file) + `(let (byte-compile-warnings) + (byte-compile #',sym)))))))) + +(defun doom-modeline--prepare-segments (segments) + "Prepare mode-line `SEGMENTS'." + (let (forms it) + (dolist (seg segments) + (cond ((stringp seg) + (push seg forms)) + ((symbolp seg) + (cond ((setq it (cdr (assq seg doom-modeline-fn-alist))) + (push (list :eval (list it)) forms)) + ((setq it (cdr (assq seg doom-modeline-var-alist))) + (push it forms)) + ((error "%s is not a defined segment" seg)))) + ((error "%s is not a valid segment" seg)))) + (nreverse forms))) + +(defvar doom-modeline--font-width-cache nil) +(defun doom-modeline--font-width () + "Cache the font width." + (if (display-graphic-p) + (let ((attributes (face-all-attributes 'mode-line))) + (or (cdr (assoc attributes doom-modeline--font-width-cache)) + (let ((width (window-font-width nil 'mode-line))) + (push (cons attributes width) doom-modeline--font-width-cache) + width))) + 1)) + +;; Refresh the font width after setting frame parameters +;; to ensure the font width is correct. +(defun doom-modeline-refresh-font-width-cache (&rest _) + "Refresh the font width cache." + (setq doom-modeline--font-width-cache nil) + (doom-modeline--font-width)) +(add-hook 'window-setup-hook #'doom-modeline-refresh-font-width-cache) +(add-hook 'after-make-frame-functions #'doom-modeline-refresh-font-width-cache) +(add-hook 'after-setting-font-hook #'doom-modeline-refresh-font-width-cache) +(add-hook 'server-after-make-frame-hook #'doom-modeline-refresh-font-width-cache) + +(defun doom-modeline-def-modeline (name lhs &optional rhs) + "Defines a modeline format and byte-compiles it. +NAME is a symbol to identify it (used by `doom-modeline' for retrieval). +LHS and RHS are lists of symbols of modeline segments defined with +`doom-modeline-def-segment'. + +Example: + (doom-modeline-def-modeline 'minimal + '(bar matches \" \" buffer-info) + '(media-info major-mode)) + (doom-modeline-set-modeline 'minimal t)" + (let ((sym (intern (format "doom-modeline-format--%s" name))) + (lhs-forms (doom-modeline--prepare-segments lhs)) + (rhs-forms (doom-modeline--prepare-segments rhs))) + (defalias sym + (lambda () + (list lhs-forms + (propertize + " " + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive) + 'display `((space + :align-to + (- (+ right right-fringe right-margin scroll-bar) + ,(* (let ((width (doom-modeline--font-width))) + (or (and (= width 1) 1) + (/ width (frame-char-width) 1.0))) + (string-width + (format-mode-line (cons "" rhs-forms)))))))) + rhs-forms)) + (concat "Modeline:\n" + (format " %s\n %s" + (prin1-to-string lhs) + (prin1-to-string rhs)))))) +(put 'doom-modeline-def-modeline 'lisp-indent-function 'defun) + +(defun doom-modeline (key) + "Return a mode-line configuration associated with KEY (a symbol). +Throws an error if it doesn't exist." + (let ((fn (intern-soft (format "doom-modeline-format--%s" key)))) + (when (functionp fn) + `(:eval (,fn))))) + +(defun doom-modeline-set-modeline (key &optional default) + "Set the modeline format. Does nothing if the modeline KEY doesn't exist. +If DEFAULT is non-nil, set the default mode-line for all buffers." + (when-let ((modeline (doom-modeline key))) + (setf (if default + (default-value 'mode-line-format) + (buffer-local-value 'mode-line-format (current-buffer))) + (list "%e" modeline)))) + + +;; +;; Helpers +;; + +(defsubst doom-modeline-spc () + "Text style with whitespace." + (propertize " " 'face (if (doom-modeline--active) + 'doom-modeline-spc-face + 'doom-modeline-spc-inactive-face))) + +(defsubst doom-modeline-wspc () + "Text style with wide whitespace." + (propertize " " 'face (if (doom-modeline--active) + 'doom-modeline-spc-face + 'doom-modeline-spc-inactive-face))) + +(defsubst doom-modeline-vspc () + "Text style with icons in mode-line." + (propertize " " 'face (if (doom-modeline--active) + 'doom-modeline-vspc-face + 'doom-modeline-vspc-inactive-face))) + +(defun doom-modeline--font-height () + "Calculate the actual char height of the mode-line." + (let ((height (face-attribute 'mode-line :height))) + ;; WORKAROUND: Fix tall issue of 27 on Linux + ;; @see https://github.com/seagle0128/doom-modeline/issues/271 + (round + (* (if (or (<= doom-modeline-height 0) + (and (>= emacs-major-version 27) + (not (eq system-type 'darwin)))) + 1.0 + (if doom-modeline-icon 1.68 1.25)) + (cond ((integerp height) (/ height 10)) + ((floatp height) (* height (frame-char-height))) + (t (frame-char-height))))))) + +(defun doom-modeline--original-value (sym) + "Return the original value for SYM, if any. + +If SYM has an original value, return it in a list. Return nil +otherwise." + (let* ((orig-val-expr (get sym 'standard-value))) + (when (consp orig-val-expr) + (ignore-errors + (list + (eval (car orig-val-expr))))))) + +(defun doom-modeline-add-variable-watcher (symbol watch-function) + "Cause WATCH-FUNCTION to be called when SYMBOL is set if possible. + +See docs of `add-variable-watcher'." + (when (fboundp 'add-variable-watcher) + (add-variable-watcher symbol watch-function))) + +(defun doom-modeline-propertize-icon (icon &optional face) + "Propertize the ICON with the specified FACE. + +The face should be the first attribute, or the font family may be overridden. +So convert the face \":family XXX :height XXX :inherit XXX\" to +\":inherit XXX :family XXX :height XXX\". +See https://github.com/seagle0128/doom-modeline/issues/301." + (if (and doom-modeline-icon (display-graphic-p)) + (when-let ((props (get-text-property 0 'face icon))) + (cl-destructuring-bind (&key family height inherit &allow-other-keys) props + (propertize icon 'face `(:inherit ,(or face inherit props) + :family ,family + :height ,height)))) + (propertize icon 'face face))) + +(defun doom-modeline-icon (icon-set icon-name unicode text &rest args) + "Display icon of ICON-NAME with ARGS in mode-line. + +ICON-SET includes `octicon', `faicon', `material', `alltheicons' and `fileicon', +etc. +UNICODE is the unicode char fallback. TEXT is the ASCII char fallback. +ARGS is same as `all-the-icons-octicon' and others." + (let ((face (or (plist-get args :face) 'mode-line))) + (or + ;; Icons + (when (and (display-graphic-p) + doom-modeline-icon + icon-name + (not (string-empty-p icon-name))) + (when-let* ((func (all-the-icons--function-name icon-set)) + (icon (and (fboundp func) (apply func icon-name args)))) + (doom-modeline-propertize-icon icon face))) + ;; Unicode fallback + (and doom-modeline-unicode-fallback + unicode + (not (string-empty-p unicode)) + (char-displayable-p (string-to-char unicode)) + (propertize unicode 'face face)) + ;; ASCII text + (and text (propertize text 'face face)) + ""))) + +(defun doom-modeline--create-bar-image (face width height) + "Create the bar image. +Use FACE1 for the bar, FACE2 for the background. +WIDTH and HEIGHT are the image size in pixels." + (when (and (display-graphic-p) + (image-type-available-p 'pbm)) + (propertize + " " 'display + (let ((color (or (face-background face nil t) "None"))) + (ignore-errors + (create-image + (concat (format "P1\n%i %i\n" width height) + (make-string (* width height) ?1) + "\n") + 'pbm t :foreground color :ascent 'center)))))) + +(defun doom-modeline--create-hud-image + (face1 face2 width height top-margin bottom-margin) + "Create the hud image. +Use FACE1 for the bar, FACE2 for the background. +WIDTH and HEIGHT are the image size in pixels. +TOP-MARGIN and BOTTOM-MARGIN are the size of the margin above and below the bar, +respectively." + (when (and (display-graphic-p) + (image-type-available-p 'pbm)) + (let ((min-height (min height doom-modeline-hud-min-height))) + (unless (> (- height top-margin bottom-margin) min-height) + (let ((margin (- height min-height))) + (setq top-margin (/ (* margin top-margin) (+ top-margin bottom-margin)) + bottom-margin (- margin top-margin))))) + (propertize + " " 'display + (let ((color1 (or (face-background face1 nil t) "None")) + (color2 (or (face-background face2 nil t) "None"))) + (create-image + (concat + (format "P1\n%i %i\n" width height) + (make-string (* top-margin width) ?0) + (make-string (* (- height top-margin bottom-margin) width) ?1) + (make-string (* bottom-margin width) ?0) + "\n") + 'pbm t :foreground color1 :background color2 :ascent 'center))))) + +;; Check whether `window-total-width' is smaller than the limit +(defvar-local doom-modeline--limited-width-p nil) +(defun doom-modeline-window-size-change-function (&rest _) + "Function for `window-size-change-functions'." + (setq doom-modeline--limited-width-p + (cond + ((integerp doom-modeline-window-width-limit) + (<= (window-total-width) doom-modeline-window-width-limit)) + ((floatp doom-modeline-window-width-limit) + (<= (/ (window-total-width) (frame-width) 1.0) + doom-modeline-window-width-limit))))) + +(add-hook 'window-size-change-functions #'doom-modeline-window-size-change-function) +(add-hook 'buffer-list-update-hook #'doom-modeline-window-size-change-function) + +(defvar-local doom-modeline--project-root nil) +(defun doom-modeline--project-root () + "Get the path to the root of your project. +Return nil if no project was found." + (or doom-modeline--project-root + (setq doom-modeline--project-root + (pcase (if (eq doom-modeline-project-detection 'auto) + (cond + ((fboundp 'ffip-get-project-root-directory) 'ffip) + ((fboundp 'projectile-project-root) 'projectile) + ((fboundp 'project-current) 'project) + (t 'default)) + doom-modeline-project-detection) + ('ffip + (let ((inhibit-message t)) + (ffip-get-project-root-directory))) + ('projectile + (projectile-project-root)) + ('project + (when-let ((project (project-current))) + (expand-file-name (if (fboundp 'project-root) + (project-root project) + (cdr project))))))))) + +(defun doom-modeline-project-p () + "Check if the file is in a project." + (doom-modeline--project-root)) + +(defun doom-modeline-project-root () + "Get the path to the root of your project. +Return `default-directory' if no project was found." + (or (doom-modeline--project-root) default-directory)) + +(defun doom-modeline-buffer-file-name () + "Propertized variable `buffer-file-name' based on +`doom-modeline-buffer-file-name-style'." + (let* ((buffer-file-name (file-local-name (or (buffer-file-name (buffer-base-buffer)) ""))) + (buffer-file-truename (file-local-name + (or buffer-file-truename (file-truename buffer-file-name) ""))) + (file-name + (pcase doom-modeline-buffer-file-name-style + ('auto + (if (doom-modeline-project-p) + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide) + (propertize "%b" 'face 'doom-modeline-buffer-file))) + ('truncate-upto-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink)) + ('truncate-from-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil 'shrink)) + ('truncate-with-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shink 'hide)) + ('truncate-except-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shink)) + ('truncate-upto-root + (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename)) + ('truncate-all + (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename t)) + ('truncate-nil + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename)) + ('relative-to-project + (doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename)) + ('relative-from-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide)) + ('file-name + (propertize (file-name-nondirectory buffer-file-name) + 'face 'doom-modeline-buffer-file)) + ((or 'buffer-name _) + (propertize "%b" 'face 'doom-modeline-buffer-file))))) + (propertize (if (string-empty-p file-name) + (propertize "%b" 'face 'doom-modeline-buffer-file) + file-name) + 'mouse-face 'mode-line-highlight + 'help-echo (concat buffer-file-truename + (unless (string= (file-name-nondirectory buffer-file-truename) + (buffer-name)) + (concat "\n" (buffer-name))) + "\nmouse-1: Previous buffer\nmouse-3: Next buffer") + 'local-map mode-line-buffer-identification-keymap))) + +(defun doom-modeline--buffer-file-name-truncate (file-path true-file-path &optional truncate-tail) + "Propertized variable `buffer-file-name' that truncates every dir along path. +If TRUNCATE-TAIL is t also truncate the parent directory of the file." + (let ((dirs (shrink-path-prompt (file-name-directory true-file-path)))) + (if (null dirs) + (propertize "%b" 'face 'doom-modeline-buffer-file) + (let ((dirname (car dirs)) + (basename (cdr dirs))) + (concat (propertize (concat dirname + (if truncate-tail (substring basename 0 1) basename) + "/") + 'face 'doom-modeline-project-root-dir) + (propertize (file-name-nondirectory file-path) + 'face 'doom-modeline-buffer-file)))))) + +(defun doom-modeline--buffer-file-name-relative (_file-path true-file-path &optional include-project) + "Propertized variable `buffer-file-name' showing directories relative to +project's root only." + (let ((root (file-local-name (doom-modeline-project-root)))) + (if (null root) + (propertize "%b" 'face 'doom-modeline-buffer-file) + (let ((relative-dirs (file-relative-name (file-name-directory true-file-path) + (if include-project (concat root "../") root)))) + (and (equal "./" relative-dirs) (setq relative-dirs "")) + (concat (propertize relative-dirs 'face 'doom-modeline-buffer-path) + (propertize (file-name-nondirectory true-file-path) + 'face 'doom-modeline-buffer-file)))))) + +(defun doom-modeline--buffer-file-name (file-path + _true-file-path + &optional + truncate-project-root-parent + truncate-project-relative-path + hide-project-root-parent) + "Propertized variable `buffer-file-name' given by FILE-PATH. +If TRUNCATE-PROJECT-ROOT-PARENT is non-nil will be saved by truncating project +root parent down fish-shell style. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el + +If TRUNCATE-PROJECT-RELATIVE-PATH is non-nil will be saved by truncating project +relative path down fish-shell style. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => ~/Projects/FOSS/emacs/l/comint.el + +If HIDE-PROJECT-ROOT-PARENT is non-nil will hide project root parent. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => emacs/lisp/comint.el" + (let ((project-root (file-local-name (doom-modeline-project-root)))) + (concat + ;; Project root parent + (unless hide-project-root-parent + (when-let (root-path-parent + (file-name-directory (directory-file-name project-root))) + (propertize + (if (and truncate-project-root-parent + (not (string-empty-p root-path-parent)) + (not (string= root-path-parent "/"))) + (shrink-path--dirs-internal root-path-parent t) + (abbreviate-file-name root-path-parent)) + 'face 'doom-modeline-project-parent-dir))) + ;; Project directory + (propertize + (concat (file-name-nondirectory (directory-file-name project-root)) "/") + 'face 'doom-modeline-project-dir) + ;; relative path + (propertize + (when-let (relative-path (file-relative-name + (or (file-name-directory file-path) "./") + project-root)) + (if (string= relative-path "./") + "" + (if truncate-project-relative-path + (substring (shrink-path--dirs-internal relative-path t) 1) + relative-path))) + 'face 'doom-modeline-buffer-path) + ;; File name + (propertize (file-name-nondirectory file-path) + 'face 'doom-modeline-buffer-file)))) + +(provide 'doom-modeline-core) + +;;; doom-modeline-core.el ends here diff --git a/code/elpa/doom-modeline-20220412.853/doom-modeline-env.el b/code/elpa/doom-modeline-20220412.853/doom-modeline-env.el new file mode 100644 index 0000000..87c8c50 --- /dev/null +++ b/code/elpa/doom-modeline-20220412.853/doom-modeline-env.el @@ -0,0 +1,275 @@ +;;; doom-modeline-env.el --- A environment parser for doom-modeline -*- lexical-binding: t -*- + +;; Copyright (C) 2019-2020 Justin Barclay, Vincent Zhang + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . +;; +;;; Commentary: +;; +;; Parse programming environment. +;; + +;;; Code: + +(require 'subr-x) +(require 'doom-modeline-core) + + +;; Externals +(defvar python-shell-interpreter) + + +;; Customizations + +(defgroup doom-modeline-env nil + "The environment parser for doom-modeline." + :group 'doom-modeline + :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) + +(defcustom doom-modeline-env-load-string "..." + "What to display as the version while a new one is being loaded." + :type 'string + :group 'doom-modeline-env) + +(defcustom doom-modeline-before-update-env-hook nil + "Hooks that run before the modeline version string is updated." + :type 'hook + :group 'doom-modeline-env) + +(defcustom doom-modeline-after-update-env-hook nil + "Hooks that run after the modeline version string is updated." + :type 'hook + :group 'doom-modeline-env) + + +;; Variables + +;; Show version string for multi-version managers like rvm, rbenv, pyenv, etc. +(defvar-local doom-modeline-env--version nil + "The version to display with major-mode in mode-line. +Example: \"2.6.0\"") + +(defvar-local doom-modeline-env--command nil + "A program that we're looking to extract version information from. +Example: \"ruby\"") + +(defvar-local doom-modeline-env--command-args nil + "A list of arguments for the command to extract the version from. +Example: '(\"--version\") ") + +(defvar-local doom-modeline-env--parser nil + "A function that returns version number from a command --version (or similar). +Example: 'doom-modeline-env--ruby") + + +;; Functions & Macros + +(defun doom-modeline-update-env () + "Update environment info on mode-line." + (when (and doom-modeline-env-version + doom-modeline-env--command + (executable-find doom-modeline-env--command) + doom-modeline-env--command-args + doom-modeline-env--parser) + (let ((default-directory (doom-modeline-project-root)) + (buffer (current-buffer))) + (run-hooks 'doom-modeline-before-update-env-hook) + (setq doom-modeline-env--version doom-modeline-env-load-string) + (doom-modeline-env--get + doom-modeline-env--command + doom-modeline-env--command-args + (lambda (prog-version) + (with-current-buffer buffer + (setq doom-modeline-env--version + (funcall doom-modeline-env--parser prog-version)) + (run-hooks 'doom-modeline-after-update-env-hook))))))) + +(add-hook 'find-file-hook #'doom-modeline-update-env) +(with-no-warnings + (if (boundp 'after-focus-change-function) + (add-function + :after after-focus-change-function + (lambda () + (if (frame-focus-state) + (doom-modeline-update-env)))) + (add-hook 'focus-in-hook #'doom-modeline-update-env))) + +(defun doom-modeline-env--get (prog args callback) + "Start a sub process using PROG and apply the ARGS to the sub process. +Once it receives information from STDOUT, it closes off the subprocess and +passes on the information into the CALLBACK. +Example: + (doom-modeline-env--get + \"ruby\" + '(\"--version\") + (lambda (line) + (message (doom-modeline-parser--ruby line)))" + (let ((proc (apply 'start-process + ;; Flaten process-args into a single list so we can handle + ;; variadic length args + (append + (list "doom-modeline-env" nil prog) + args))) + (parser callback)) + (set-process-filter proc + (lambda (_proc line) + (ignore-errors + (funcall parser line)))))) + +(cl-defmacro doom-modeline-def-env (name &key hooks command parser) + "Defines a handler for updating & displaying a version string for a language. + +NAME is an unquoted symbol representing the handler's unique ID. +HOOKS is a list of hook symbols where this handler should be triggered. +COMMAND should be a function that returns a shell command and its arguments (as + a list). It is run on HOOKS. It takes no arguments. +PARSER should be a function for parsing COMMAND's output line-by-line, to + extract the version string." + (declare (indent defun)) + (unless (and hooks command parser) + (error "'%s' env is missing either :hooks, :command or :parser" name)) + (let ((parse-fn (intern (format "doom-modeline-env--%s-parse" name))) + (action-fn (intern (format "doom-modeline-env--%s-args" name))) + (setup-fn (intern (format "doom-modeline-env-setup-%s" name))) + (update-fn (intern (format "doom-modeline-env-update-%s" name))) + (enable-var (intern (format "doom-modeline-env-enable-%s" name))) + (command-var (intern (format "doom-modeline-env-%s-command" name))) + (parser-var (intern (format "doom-modeline-env-%s-parser-fn" name))) + (exe-var (intern (format "doom-modeline-env-%s-executable" name)))) + (macroexp-progn + `((defcustom ,enable-var t + ,(format "Whether to display the version string for %s buffers." name) + :type 'boolean + :group 'doom-modeline-env) + (defvar ,command-var ',action-fn + ,(concat "A function that returns the shell command and arguments (as a list) to\n" + "produce a version string.")) + (defvar ,parser-var ',parse-fn + ,(format "The function to parse each line of `%s'\'s output." command-var)) + (defcustom ,exe-var nil + ,(format (concat "What executable to use for the version indicator in %s buffers.\n\n" + "If nil, the default binary for this language is used.") + name) + :type 'string + :group 'doom-modeline-env) + (defalias ',parse-fn ,parser + (format "The line parser for %s buffers.\n\nUsed by `%s'." + ',name ',update-fn)) + (defalias ',action-fn ,command + (format "The command resolver for %s buffers.\n\nUsed by `%s'." + ',name ',update-fn)) + (defalias ',setup-fn + (lambda () + (if enable-local-variables + (add-hook 'hack-local-variables-hook #',update-fn nil t) + (,update-fn))) + (format "Prepares the modeline to later display the %s version string." + ',name)) + (defalias ',update-fn + (lambda () + (when ,enable-var + (when-let* ((command-list (funcall ,command-var)) + (exe (executable-find (car command-list)))) + (setq doom-modeline-env--command exe + doom-modeline-env--command-args (cdr command-list) + doom-modeline-env--parser ,parser-var) + (doom-modeline-update-env)))) + (format "Updates the %s version string in the modeline." ',name)) + (let ((hooks ',(eval hooks))) + (dolist (hook (if (listp hooks) hooks (list hooks))) + (add-hook hook #',setup-fn))))))) + + +;; Bootstrap +;; Versions, support Python, Ruby, Perl and Golang, etc. + +;;;###autoload (autoload 'doom-modeline-env-setup-python "doom-modeline-env") +(doom-modeline-def-env python + :hooks 'python-mode-hook + :command (lambda () (cond ((and (fboundp 'pipenv-project-p) + (pipenv-project-p)) + (list "pipenv" "run" + (or doom-modeline-env-python-executable + python-shell-interpreter + "python") + "--version")) + ((executable-find "pyenv") (list "pyenv" "version-name")) + ((list (or doom-modeline-env-python-executable + python-shell-interpreter + "python") + "--version")))) + :parser (lambda (line) (let ((version (split-string line))) + (if (>= (length version) 2) + (cadr version) + (car version))))) + +;;;###autoload (autoload 'doom-modeline-env-setup-ruby "doom-modeline-env") +(doom-modeline-def-env ruby + :hooks '(ruby-mode-hook enh-ruby-mode-hook) + :command (lambda () (list (or doom-modeline-env-ruby-executable "ruby") "--version")) + :parser (lambda (line) + (car (split-string + (cadr + (split-string line)) + "p")))) + +;;;###autoload (autoload 'doom-modeline-env-setup-perl "doom-modeline-env") +(doom-modeline-def-env perl + :hooks 'perl-mode-hook + :command (lambda () (list (or doom-modeline-env-perl-executable "perl") "--version")) + :parser (lambda (line) + (cadr + (split-string + (car + (split-string + (cadr + (split-string line "(")) + ")")) + "v")))) + +;;;###autoload (autoload 'doom-modeline-env-setup-go "doom-modeline-env") +(doom-modeline-def-env go + :hooks 'go-mode-hook + :command (lambda () (list (or doom-modeline-env-go-executable "go") "version")) + :parser (lambda (line) + (cadr + (split-string + (cadr + (cdr + (split-string line))) + "go")))) + +;;;###autoload (autoload 'doom-modeline-env-setup-elixir "doom-modeline-env") +(doom-modeline-def-env elixir + :hooks 'elixir-mode-hook + :command (lambda () (list (or doom-modeline-env-elixir-executable "elixir") "--version")) + :parser (lambda (line) (cadr (split-string line)))) + +;;;###autoload (autoload 'doom-modeline-env-setup-rust "doom-modeline-env") +(doom-modeline-def-env rust + :hooks 'rust-mode-hook + :command (lambda () (list (or doom-modeline-env-rust-executable "rustc") "--version")) + :parser (lambda (line) + (car + (split-string + (cadr + (split-string line)) + "-")))) + +(provide 'doom-modeline-env) + +;;; doom-modeline-env.el ends here diff --git a/code/elpa/doom-modeline-20220412.853/doom-modeline-pkg.el b/code/elpa/doom-modeline-20220412.853/doom-modeline-pkg.el new file mode 100644 index 0000000..c289f03 --- /dev/null +++ b/code/elpa/doom-modeline-20220412.853/doom-modeline-pkg.el @@ -0,0 +1,15 @@ +(define-package "doom-modeline" "20220412.853" "A minimal and modern mode-line" + '((emacs "25.1") + (all-the-icons "2.2.0") + (shrink-path "0.2.0") + (dash "2.11.0")) + :commit "7d8eb7c44087a62d8dd6e8ba1afc26facd914fbc" :authors + '(("Vincent Zhang" . "seagle0128@gmail.com")) + :maintainer + '("Vincent Zhang" . "seagle0128@gmail.com") + :keywords + '("faces" "mode-line") + :url "https://github.com/seagle0128/doom-modeline") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/code/elpa/doom-modeline-20220412.853/doom-modeline-segments.el b/code/elpa/doom-modeline-20220412.853/doom-modeline-segments.el new file mode 100644 index 0000000..d0970d1 --- /dev/null +++ b/code/elpa/doom-modeline-20220412.853/doom-modeline-segments.el @@ -0,0 +1,2969 @@ +;;; doom-modeline-segments.el --- The segments for doom-modeline -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2020 Vincent Zhang + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . +;; + +;;; Commentary: +;; +;; The segments for doom-modeline. +;; Use `doom-modeline-def-segment' to create a new segment. +;; + +;;; Code: + +(require 'all-the-icons) +(require 'cl-lib) +(require 'seq) +(require 'subr-x) +(require 'doom-modeline-core) +(require 'doom-modeline-env) + + +;; +;; Externals +;; + +(defvar Info-current-file) +(defvar Info-current-node) +(defvar Info-mode-line-node-keymap) +(defvar anzu--cached-count) +(defvar anzu--current-position) +(defvar anzu--overflow-p) +(defvar anzu--state) +(defvar anzu--total-matched) +(defvar anzu-cons-mode-line-p) +(defvar aw-keys) +(defvar battery-echo-area-format) +(defvar battery-load-critical) +(defvar battery-mode-line-format) +(defvar battery-mode-line-limit) +(defvar battery-status-function) +(defvar boon-command-state) +(defvar boon-insert-state) +(defvar boon-off-state) +(defvar boon-special-state) +(defvar edebug-execution-mode) +(defvar eglot--managed-mode) +(defvar erc-modified-channels-alist) +(defvar evil-ex-active-highlights-alist) +(defvar evil-ex-argument) +(defvar evil-ex-range) +(defvar evil-mc-frozen) +(defvar evil-state) +(defvar evil-visual-beginning) +(defvar evil-visual-end) +(defvar evil-visual-selection) +(defvar flycheck-current-errors) +(defvar flycheck-mode-menu-map) +(defvar flymake--mode-line-format) +(defvar flymake--state) +(defvar flymake-menu) +(defvar gnus-newsrc-alist) +(defvar gnus-newsrc-hashtb) +(defvar grip--process) +(defvar helm--mode-line-display-prefarg) +(defvar iedit-occurrences-overlays) +(defvar meow--indicator) +(defvar minions-direct) +(defvar minions-mode-line-lighter) +(defvar minions-mode-line-minor-modes-map) +(defvar mlscroll-minimum-current-width) +(defvar mlscroll-right-align) +(defvar mu4e-alert-mode-line) +(defvar mu4e-alert-modeline-formatter) +(defvar nyan-minimum-window-width) +(defvar objed--obj-state) +(defvar objed--object) +(defvar objed-modeline-setup-func) +(defvar persp-nil-name) +(defvar phi-replace--mode-line-format) +(defvar phi-search--selection) +(defvar phi-search-mode-line-format) +(defvar poke-line-minimum-window-width) +(defvar rcirc-activity) +(defvar sml-modeline-len) +(defvar symbol-overlay-keywords-alist) +(defvar symbol-overlay-temp-symbol) +(defvar text-scale-mode-amount) +(defvar tracking-buffers) +(defvar winum-auto-setup-mode-line) +(defvar xah-fly-insert-state-p) + +(declare-function anzu--reset-status "ext:anzu") +(declare-function anzu--where-is-here "ext:anzu") +(declare-function async-inject-variables "ext:async") +(declare-function async-start "ext:async") +(declare-function avy-traverse "ext:avy") +(declare-function avy-tree "ext:avy") +(declare-function aw-update "ext:ace-window") +(declare-function aw-window-list "ext:ace-window") +(declare-function battery-format "battery") +(declare-function battery-update "battery") +(declare-function boon-modeline-string "ext:boon") +(declare-function boon-state-string "ext:boon") +(declare-function cider--connection-info "ext:cider") +(declare-function cider-connected-p "ext:cider") +(declare-function cider-current-repl "ext:cider") +(declare-function cider-jack-in "ext:cider") +(declare-function cider-quit "ext:cider") +(declare-function citre-mode "ext:citre-basic-tools") +(declare-function dap--cur-session "ext:dap-mode") +(declare-function dap--debug-session-name "ext:dap-mode") +(declare-function dap--debug-session-state "ext:dap-mode") +(declare-function dap--session-running "ext:dap-mode") +(declare-function dap-debug-recent "ext:dap-mode") +(declare-function dap-disconnect "ext:dap-mode") +(declare-function dap-hydra "ext:dap-hydra") +(declare-function edebug-help "edebug") +(declare-function edebug-next-mode "edebug") +(declare-function edebug-stop "edebug") +(declare-function eglot "ext:eglot") +(declare-function eglot--major-mode "ext:eglot" t t) +(declare-function eglot--project-nickname "ext:eglot" t t) +(declare-function eglot--spinner "ext:eglot" t t) +(declare-function eglot-clear-status "ext:eglot") +(declare-function eglot-current-server "ext:eglot") +(declare-function eglot-events-buffer "ext:eglot") +(declare-function eglot-forget-pending-continuations "ext:eglot") +(declare-function eglot-managed-p "ext:glot") +(declare-function eglot-reconnect "ext:eglot") +(declare-function eglot-shutdown "ext:eglot") +(declare-function eglot-stderr-buffer "ext:eglot") +(declare-function erc-switch-to-buffer "erc") +(declare-function erc-track-switch-buffer "erc-track") +(declare-function evil-delimited-arguments "ext:evil-common") +(declare-function evil-emacs-state-p "ext:evil-states" t t) +(declare-function evil-force-normal-state "ext:evil-commands" t t) +(declare-function evil-insert-state-p "ext:evil-states" t t) +(declare-function evil-motion-state-p "ext:evil-states" t t) +(declare-function evil-normal-state-p "ext:evil-states" t t) +(declare-function evil-operator-state-p "ext:evil-states" t t) +(declare-function evil-replace-state-p "ext:evil-states" t t) +(declare-function evil-state-property "ext:evil-common") +(declare-function evil-visual-state-p "ext:evil-states" t t) +(declare-function eyebrowse--get "ext:eyebrowse") +(declare-function face-remap-remove-relative "face-remap") +(declare-function fancy-narrow-active-p "ext:fancy-narrow") +(declare-function flycheck-buffer "ext:flycheck") +(declare-function flycheck-count-errors "ext:flycheck") +(declare-function flycheck-error-level-compilation-level "ext:flycheck") +(declare-function flycheck-list-errors "ext:flycheck") +(declare-function flycheck-next-error "ext:flycheck") +(declare-function flycheck-previous-error "ext:flycheck") +(declare-function flymake--diag-type "ext:flymake" t t) +(declare-function flymake--handle-report "ext:flymake") +(declare-function flymake--lookup-type-property "ext:flymake") +(declare-function flymake--state-diags "ext:flymake" t t) +(declare-function flymake-disabled-backends "ext:flymake") +(declare-function flymake-goto-next-error "ext:flymake") +(declare-function flymake-goto-prev-error "ext:flymake") +(declare-function flymake-reporting-backends "ext:flymake") +(declare-function flymake-running-backends "ext:flymake") +(declare-function flymake-show-buffer-diagnostics "ext:flymake") +(declare-function flymake-show-diagnostics-buffer "ext:flymake") +(declare-function flymake-start "ext:flymake") +(declare-function follow-all-followers "follow") +(declare-function gnus-demon-add-handler "gnus-demon") +(declare-function grip--preview-url "ext:grip-mode") +(declare-function grip-browse-preview "ext:grip-mode") +(declare-function grip-restart-preview "ext:grip-mode") +(declare-function grip-stop-preview "ext:grip-mode") +(declare-function helm-candidate-number-at-point "ext:helm-core") +(declare-function helm-get-candidate-number "ext:helm-core") +(declare-function iedit-find-current-occurrence-overlay "ext:iedit-lib") +(declare-function iedit-prev-occurrence "ext:iedit-lib") +(declare-function image-get-display-property "image-mode") +(declare-function jsonrpc--request-continuations "ext:jsonrpc" t t) +(declare-function jsonrpc-last-error "ext:jsonrpc" t t) +(declare-function lsp--workspace-print "ext:lsp-mode") +(declare-function lsp-describe-session "ext:lsp-mode") +(declare-function lsp-workspace-folders-open "ext:lsp-mode") +(declare-function lsp-workspace-restart "ext:lsp-mode") +(declare-function lsp-workspace-shutdown "ext:lsp-mode") +(declare-function lsp-workspaces "ext:lsp-mode") +(declare-function lv-message "ext:lv") +(declare-function mc/num-cursors "ext:multiple-cursors-core") +(declare-function mlscroll-mode-line "ext:mlscroll") +(declare-function mu4e-alert-default-mode-line-formatter "ext:mu4e-alert") +(declare-function mu4e-alert-enable-mode-line-display "ext:mu4e-alert") +(declare-function nyan-create "ext:nyan-mode") +(declare-function org-edit-src-save "ext:org-src") +(declare-function parrot-create "ext:parrot") +(declare-function pdf-cache-number-of-pages "ext:pdf-cache" t t) +(declare-function persp-add-buffer "ext:persp-mode") +(declare-function persp-contain-buffer-p "ext:persp-mode") +(declare-function persp-switch "ext:persp-mode") +(declare-function phi-search--initialize "ext:phi-search") +(declare-function poke-line-create "ext:poke-line") +(declare-function popup-create "ext:popup") +(declare-function popup-delete "ext:popup") +(declare-function rcirc-next-active-buffer "rcirc") +(declare-function rcirc-short-buffer-name "rcirc") +(declare-function rcirc-switch-to-server-buffer "rcirc") +(declare-function rcirc-window-configuration-change "rcirc") +(declare-function rime--should-enable-p "ext:rime") +(declare-function rime--should-inline-ascii-p "ext:rime") +(declare-function sml-modeline-create "ext:sml-modeline") +(declare-function symbol-overlay-assoc "ext:symbol-overlay") +(declare-function symbol-overlay-get-list "ext:symbol-overlay") +(declare-function symbol-overlay-get-symbol "ext:symbol-overlay") +(declare-function symbol-overlay-rename "ext:symbol-overlay") +(declare-function tab-bar--current-tab "tab-bar") +(declare-function tab-bar--current-tab-index "tab-bar") +(declare-function tracking-next-buffer "ext:tracking") +(declare-function tracking-previous-buffer "ext:tracking") +(declare-function tracking-shorten "ext:tracking") +(declare-function undo-tree-redo-1 "ext:undo-tree") +(declare-function undo-tree-undo-1 "ext:undo-tree") +(declare-function warning-numeric-level "warnings") +(declare-function window-numbering-clear-mode-line "ext:window-numbering") +(declare-function window-numbering-get-number-string "ext:window-numbering") +(declare-function window-numbering-install-mode-line "ext:window-numbering") +(declare-function winum--clear-mode-line "ext:winum") +(declare-function winum--install-mode-line "ext:winum") +(declare-function winum-get-number-string "ext:winum") + + + +;; +;; Buffer information +;; + +(defvar-local doom-modeline--buffer-file-icon nil) +(defun doom-modeline-update-buffer-file-icon (&rest _) + "Update file icon in mode-line." + (setq doom-modeline--buffer-file-icon + (when (and (display-graphic-p) + doom-modeline-icon + doom-modeline-major-mode-icon) + (let ((icon (all-the-icons-icon-for-buffer))) + (propertize (if (or (null icon) (symbolp icon)) + (doom-modeline-icon 'faicon "file-o" nil nil + :face 'all-the-icons-dsilver + :height 0.9 + :v-adjust 0.0) + icon) + 'help-echo (format "Major-mode: %s" (format-mode-line mode-name)) + 'display '(raise -0.135)))))) +(add-hook 'find-file-hook #'doom-modeline-update-buffer-file-icon) +(add-hook 'after-change-major-mode-hook #'doom-modeline-update-buffer-file-icon) +(add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-buffer-file-icon)))))) + +(defun doom-modeline-buffer-file-state-icon (icon unicode text face) + "Displays an ICON of buffer state with FACE. +UNICODE and TEXT are the alternatives if it is not applicable. +Uses `all-the-icons-material' to fetch the icon." + (doom-modeline-icon 'material icon unicode text + :face face + :height 1.1 + :v-adjust -0.225)) + +(defvar-local doom-modeline--buffer-file-state-icon nil) +(defun doom-modeline-update-buffer-file-state-icon (&rest _) + "Update the buffer or file state in mode-line." + (setq doom-modeline--buffer-file-state-icon + (when doom-modeline-buffer-state-icon + (ignore-errors + (concat + (cond (buffer-read-only + (doom-modeline-buffer-file-state-icon + "lock" "πŸ”’" "%1*" `(:inherit doom-modeline-warning + :weight ,(if doom-modeline-icon + 'normal + 'bold)))) + ((and buffer-file-name (buffer-modified-p) + doom-modeline-buffer-modification-icon) + (doom-modeline-buffer-file-state-icon + "save" "πŸ’Ύ" "%1*" `(:inherit doom-modeline-buffer-modified + :weight ,(if doom-modeline-icon + 'normal + 'bold)))) + ((and buffer-file-name + (not (file-remote-p buffer-file-name)) ; Avoid freezing while connection is lost + (not (file-exists-p buffer-file-name))) + (doom-modeline-buffer-file-state-icon + "do_not_disturb_alt" "🚫" "!" 'doom-modeline-urgent)) + (t "")) + (when (or (buffer-narrowed-p) + (and (bound-and-true-p fancy-narrow-mode) + (fancy-narrow-active-p)) + (bound-and-true-p dired-narrow-mode)) + (doom-modeline-buffer-file-state-icon + "vertical_align_center" "↕" "><" 'doom-modeline-warning))))))) + +(defvar-local doom-modeline--buffer-file-name nil) +(defun doom-modeline-update-buffer-file-name (&rest _) + "Update buffer file name in mode-line." + (setq doom-modeline--buffer-file-name + (ignore-errors + (save-match-data + (if buffer-file-name + (doom-modeline-buffer-file-name) + (propertize "%b" + 'face 'doom-modeline-buffer-file + 'mouse-face 'mode-line-highlight + 'help-echo "Buffer name +mouse-1: Previous buffer\nmouse-3: Next buffer" + 'local-map mode-line-buffer-identification-keymap)))))) +(add-hook 'find-file-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'after-save-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'evil-insert-state-exit-hook #'doom-modeline-update-buffer-file-name) +(advice-add #'not-modified :after #'doom-modeline-update-buffer-file-name) +(advice-add #'rename-buffer :after #'doom-modeline-update-buffer-file-name) +(advice-add #'set-visited-file-name :after #'doom-modeline-update-buffer-file-name) +(advice-add #'pop-to-buffer :after #'doom-modeline-update-buffer-file-name) +(advice-add #'undo :after #'doom-modeline-update-buffer-file-name) +(advice-add #'undo-tree-undo-1 :after #'doom-modeline-update-buffer-file-name) +(advice-add #'undo-tree-redo-1 :after #'doom-modeline-update-buffer-file-name) +(advice-add #'fill-paragraph :after #'doom-modeline-update-buffer-file-name) +(advice-add #'popup-create :after #'doom-modeline-update-buffer-file-name) +(advice-add #'popup-delete :after #'doom-modeline-update-buffer-file-name) +(advice-add #'org-edit-src-save :after #'doom-modeline-update-buffer-file-name) +(advice-add #'symbol-overlay-rename :after #'doom-modeline-update-buffer-file-name) + +(doom-modeline-add-variable-watcher + 'doom-modeline-buffer-file-name-style + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-buffer-file-name-style val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when buffer-file-name + (doom-modeline-update-buffer-file-name))))))) + +(defsubst doom-modeline--buffer-mode-icon () + "The icon of the current major mode." + (when (and doom-modeline-icon doom-modeline-major-mode-icon) + (when-let ((icon (or doom-modeline--buffer-file-icon + (doom-modeline-update-buffer-file-icon)))) + (concat + (let ((active (doom-modeline--active))) + (if (and active doom-modeline-major-mode-color-icon) + icon + (doom-modeline-propertize-icon icon (if active + 'mode-line + 'mode-line-inactive)))) + (doom-modeline-vspc))))) + +(defsubst doom-modeline--buffer-state-icon () + "The icon of the current buffer state." + (when doom-modeline-buffer-state-icon + (when-let ((icon (doom-modeline-update-buffer-file-state-icon))) + (concat + (if (doom-modeline--active) + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)) + (doom-modeline-vspc))))) + +(defsubst doom-modeline--buffer-name () + "The current buffer name." + (when doom-modeline-buffer-name + (if (and (not (eq doom-modeline-buffer-file-name-style 'file-name)) + doom-modeline--limited-width-p) + ;; Only display the buffer name if the window is small, and doesn't need to + ;; respect file-name style. + (propertize "%b" + 'face (cond ((and buffer-file-name (buffer-modified-p)) + 'doom-modeline-buffer-modified) + ((doom-modeline--active) 'doom-modeline-buffer-file) + (t 'mode-line-inactive)) + 'mouse-face 'mode-line-highlight + 'help-echo "Buffer name +mouse-1: Previous buffer\nmouse-3: Next buffer" + 'local-map mode-line-buffer-identification-keymap) + (when-let ((name (or doom-modeline--buffer-file-name + (doom-modeline-update-buffer-file-name)))) + (if (doom-modeline--active) + ;; Check if the buffer is modified + (if (and buffer-file-name (buffer-modified-p)) + (propertize name 'face 'doom-modeline-buffer-modified) + name) + (propertize name 'face 'mode-line-inactive)))))) + +(doom-modeline-def-segment buffer-info + "Combined information about the current buffer, including the current working +directory, the file name, and its state (modified, read-only or non-existent)." + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (doom-modeline--buffer-name))) + +(doom-modeline-def-segment buffer-info-simple + "Display only the current buffer's name, but with fontification." + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (propertize "%b" + 'face (cond ((and buffer-file-name (buffer-modified-p)) + 'doom-modeline-buffer-modified) + ((doom-modeline--active) 'doom-modeline-buffer-file) + (t 'mode-line-inactive)) + 'mouse-face 'mode-line-highlight + 'help-echo "Buffer name +mouse-1: Previous buffer\nmouse-3: Next buffer" + 'local-map mode-line-buffer-identification-keymap))) + +(doom-modeline-def-segment buffer-default-directory + "Displays `default-directory' with the icon and state . This is for special +buffers like the scratch buffer where knowing the current project directory is +important." + (let ((face (cond ((buffer-modified-p) + 'doom-modeline-buffer-modified) + ((doom-modeline--active) 'doom-modeline-buffer-path) + (t 'mode-line-inactive)))) + (concat (doom-modeline-spc) + (and doom-modeline-major-mode-icon + (concat (doom-modeline-icon + 'octicon "file-directory" "πŸ–Ώ" "" + :face face :v-adjust -0.05 :height 1.25) + (doom-modeline-vspc))) + (doom-modeline--buffer-state-icon) + (propertize (abbreviate-file-name default-directory) 'face face)))) + +(doom-modeline-def-segment buffer-default-directory-simple + "Displays `default-directory'. This is for special buffers like the scratch +buffer where knowing the current project directory is important." + (let ((face (if (doom-modeline--active) 'doom-modeline-buffer-path 'mode-line-inactive))) + (concat (doom-modeline-spc) + (and doom-modeline-major-mode-icon + (concat (doom-modeline-icon + 'octicon "file-directory" "πŸ–Ώ" "" + :face face :v-adjust -0.05 :height 1.25) + (doom-modeline-vspc))) + (propertize (abbreviate-file-name default-directory) 'face face)))) + + +;; +;; Encoding +;; + +(doom-modeline-def-segment buffer-encoding + "Displays the eol and the encoding style of the buffer the same way Atom does." + (when doom-modeline-buffer-encoding + (let ((face (if (doom-modeline--active) 'mode-line 'mode-line-inactive)) + (mouse-face 'mode-line-highlight)) + (concat + (doom-modeline-spc) + + ;; eol type + (let ((eol (coding-system-eol-type buffer-file-coding-system))) + (when (or (eq doom-modeline-buffer-encoding t) + (and (eq doom-modeline-buffer-encoding 'nondefault) + (not (equal eol doom-modeline-default-eol-type)))) + (propertize + (pcase eol + (0 "LF ") + (1 "CRLF ") + (2 "CR ") + (_ "")) + 'face face + 'mouse-face mouse-face + 'help-echo (format "End-of-line style: %s\nmouse-1: Cycle" + (pcase eol + (0 "Unix-style LF") + (1 "DOS-style CRLF") + (2 "Mac-style CR") + (_ "Undecided"))) + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] 'mode-line-change-eol) + map)))) + + ;; coding system + (let* ((sys (coding-system-plist buffer-file-coding-system)) + (cat (plist-get sys :category)) + (sym (if (memq cat + '(coding-category-undecided coding-category-utf-8)) + 'utf-8 + (plist-get sys :name)))) + (when (or (eq doom-modeline-buffer-encoding t) + (and (eq doom-modeline-buffer-encoding 'nondefault) + (not (eq cat 'coding-category-undecided)) + (not (eq sym doom-modeline-default-coding-system)))) + (propertize + (upcase (symbol-name sym)) + 'face face + 'mouse-face mouse-face + 'help-echo 'mode-line-mule-info-help-echo + 'local-map mode-line-coding-system-map))) + + (doom-modeline-spc))))) + + +;; +;; Indentation +;; + +(doom-modeline-def-segment indent-info + "Displays the indentation information." + (when doom-modeline-indent-info + (let ((do-propertize + (lambda (mode size) + (propertize + (format " %s %d " mode size) + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive))))) + (if indent-tabs-mode + (funcall do-propertize "TAB" tab-width) + (let ((lookup-var + (seq-find (lambda (var) + (and var (boundp var) (symbol-value var))) + (cdr (assoc major-mode doom-modeline-indent-alist)) nil))) + (funcall do-propertize "SPC" + (if lookup-var + (symbol-value lookup-var) + tab-width))))))) + +;; +;; Remote host +;; + +(doom-modeline-def-segment remote-host + "Hostname for remote buffers." + (when default-directory + (when-let ((host (file-remote-p default-directory 'host))) + (propertize + (concat "@" host) + 'face (if (doom-modeline--active) 'doom-modeline-host 'mode-line-inactive))))) + + +;; +;; Major mode +;; + +(doom-modeline-def-segment major-mode + "The major mode, including environment and text-scale info." + (propertize + (concat + (doom-modeline-spc) + (propertize (format-mode-line + (or (and (boundp 'delighted-modes) + (cadr (assq major-mode delighted-modes))) + mode-name)) + 'help-echo "Major mode\n\ + mouse-1: Display major mode menu\n\ + mouse-2: Show help for major mode\n\ + mouse-3: Toggle minor modes" + 'mouse-face 'mode-line-highlight + 'local-map mode-line-major-mode-keymap) + (when (and doom-modeline-env-version doom-modeline-env--version) + (format " %s" doom-modeline-env--version)) + (and (boundp 'text-scale-mode-amount) + (/= text-scale-mode-amount 0) + (format + (if (> text-scale-mode-amount 0) + " (%+d)" + " (%-d)") + text-scale-mode-amount)) + (doom-modeline-spc)) + 'face (if (doom-modeline--active) + 'doom-modeline-buffer-major-mode + 'mode-line-inactive))) + + +;; +;; Process +;; + +(doom-modeline-def-segment process + "The process info." + (if (doom-modeline--active) + mode-line-process + (propertize (format-mode-line mode-line-process) + 'face 'mode-line-inactive))) + + +;; +;; Minor modes +;; + +(doom-modeline-def-segment minor-modes + (when doom-modeline-minor-modes + (let ((face (if (doom-modeline--active) + 'doom-modeline-buffer-minor-mode + 'mode-line-inactive)) + (mouse-face 'mode-line-highlight) + (help-echo "Minor mode + mouse-1: Display minor mode menu + mouse-2: Show help for minor mode + mouse-3: Toggle minor modes")) + (if (bound-and-true-p minions-mode) + `((:propertize ("" ,(--filter (memq (car it) minions-direct) + minor-mode-alist)) + face ,face + mouse-face ,mouse-face + help-echo ,help-echo + local-map ,mode-line-minor-mode-keymap) + ,(doom-modeline-spc) + (:propertize ("" ,(doom-modeline-icon 'octicon "gear" "βš™" + minions-mode-line-lighter + :face face :v-adjust -0.05)) + mouse-face ,mouse-face + help-echo "Minions +mouse-1: Display minor modes menu" + local-map ,minions-mode-line-minor-modes-map) + ,(doom-modeline-spc)) + `((:propertize ("" minor-mode-alist) + face ,face + mouse-face ,mouse-face + help-echo ,help-echo + local-map ,mode-line-minor-mode-keymap) + ,(doom-modeline-spc)))))) + + +;; +;; VCS +;; + +(defun doom-modeline-vcs-icon (icon &optional unicode text face voffset) + "Displays the vcs ICON with FACE and VOFFSET. + +UNICODE and TEXT are fallbacks. +Uses `all-the-icons-octicon' to fetch the icon." + (doom-modeline-icon 'octicon icon unicode text + :face face :v-adjust (or voffset -0.1))) + +(defvar-local doom-modeline--vcs-icon nil) +(defun doom-modeline-update-vcs-icon (&rest _) + "Update icon of vcs state in mode-line." + (setq doom-modeline--vcs-icon + (when (and vc-mode buffer-file-name) + (let* ((backend (vc-backend buffer-file-name)) + (state (vc-state (file-local-name buffer-file-name) backend))) + (cond ((memq state '(edited added)) + (doom-modeline-vcs-icon "git-compare" "⇆" "*" 'doom-modeline-info -0.05)) + ((eq state 'needs-merge) + (doom-modeline-vcs-icon "git-merge" "β›™" "?" 'doom-modeline-info)) + ((eq state 'needs-update) + (doom-modeline-vcs-icon "arrow-down" "↓" "!" 'doom-modeline-warning)) + ((memq state '(removed conflict unregistered)) + (doom-modeline-vcs-icon "alert" "⚠" "!" 'doom-modeline-urgent)) + (t + (doom-modeline-vcs-icon "git-branch" "ξ‚ " "@" 'doom-modeline-info -0.05))))))) +(add-hook 'find-file-hook #'doom-modeline-update-vcs-icon) +(add-hook 'after-save-hook #'doom-modeline-update-vcs-icon) +(advice-add #'vc-refresh-state :after #'doom-modeline-update-vcs-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-vcs-icon)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-vcs-icon)))))) + +(defvar-local doom-modeline--vcs-text nil) +(defun doom-modeline-update-vcs-text (&rest _) + "Update text of vcs state in mode-line." + (setq doom-modeline--vcs-text + (when (and vc-mode buffer-file-name) + (let* ((backend (vc-backend buffer-file-name)) + (state (vc-state (file-local-name buffer-file-name) backend)) + (str (if vc-display-status + (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)) + ""))) + (propertize (if (> (length str) doom-modeline-vcs-max-length) + (concat + (substring str 0 (- doom-modeline-vcs-max-length 3)) + "...") + str) + 'mouse-face 'mode-line-highlight + 'face (cond ((eq state 'needs-update) + 'doom-modeline-warning) + ((memq state '(removed conflict unregistered)) + 'doom-modeline-urgent) + (t 'doom-modeline-info))))))) +(add-hook 'find-file-hook #'doom-modeline-update-vcs-text) +(add-hook 'after-save-hook #'doom-modeline-update-vcs-text) +(advice-add #'vc-refresh-state :after #'doom-modeline-update-vcs-text) + +(doom-modeline-def-segment vcs + "Displays the current branch, colored based on its state." + (let ((active (doom-modeline--active))) + (when-let ((icon doom-modeline--vcs-icon) + (text doom-modeline--vcs-text)) + (concat + (doom-modeline-spc) + (propertize + (concat + (if active + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)) + (doom-modeline-vspc)) + 'mouse-face 'mode-line-highlight + 'help-echo (get-text-property 1 'help-echo vc-mode) + 'local-map (get-text-property 1 'local-map vc-mode)) + (if active + text + (propertize text 'face 'mode-line-inactive)) + (doom-modeline-spc))))) + + +;; +;; Checker +;; + +(defun doom-modeline-checker-icon (icon unicode text face) + "Displays the checker ICON with FACE. + +UNICODE and TEXT are fallbacks. +Uses `all-the-icons-material' to fetch the icon." + (doom-modeline-icon 'material icon unicode text + :face face :height 1.1 :v-adjust -0.225)) + +(defun doom-modeline-checker-text (text &optional face) + "Displays TEXT with FACE." + (propertize text 'face (or face 'mode-line))) + +;; Flycheck + +(defun doom-modeline--flycheck-count-errors () + "Count the number of ERRORS, grouped by level. + +Return an alist, where each ITEM is a cons cell whose `car' is an +error level, and whose `cdr' is the number of errors of that +level." + (let ((info 0) (warning 0) (error 0)) + (mapc + (lambda (item) + (let ((count (cdr item))) + (pcase (flycheck-error-level-compilation-level (car item)) + (0 (cl-incf info count)) + (1 (cl-incf warning count)) + (2 (cl-incf error count))))) + (flycheck-count-errors flycheck-current-errors)) + `((info . ,info) (warning . ,warning) (error . ,error)))) + +(defvar-local doom-modeline--flycheck-icon nil) +(defun doom-modeline-update-flycheck-icon (&optional status) + "Update flycheck icon via STATUS." + (setq doom-modeline--flycheck-icon + (when-let + ((icon + (pcase status + ('finished (if flycheck-current-errors + (let-alist (doom-modeline--flycheck-count-errors) + (doom-modeline-checker-icon + "block" "🚫" "!" + (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info)))) + (doom-modeline-checker-icon "check" "βœ“" "-" 'doom-modeline-info))) + ('running (doom-modeline-checker-icon "access_time" "⏱" "*" 'doom-modeline-debug)) + ('no-checker (doom-modeline-checker-icon "sim_card_alert" "⚠" "-" 'doom-modeline-debug)) + ('errored (doom-modeline-checker-icon "sim_card_alert" "⚠" "-" 'doom-modeline-urgent)) + ('interrupted (doom-modeline-checker-icon "pause" "⏸" "=" 'doom-modeline-debug)) + ('suspicious (doom-modeline-checker-icon "priority_high" "❗" "!" 'doom-modeline-urgent)) + (_ nil)))) + (propertize icon + 'help-echo (concat "Flycheck\n" + (pcase status + ('finished "mouse-1: Display minor mode menu +mouse-2: Show help for minor mode") + ('running "Running...") + ('no-checker "No Checker") + ('errored "Error") + ('interrupted "Interrupted") + ('suspicious "Suspicious"))) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line down-mouse-1] + flycheck-mode-menu-map) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'flycheck-mode))) + map))))) +(add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck-icon) +(add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flycheck-mode) + (flycheck-buffer))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flycheck-mode) + (flycheck-buffer))))))) + +(defvar-local doom-modeline--flycheck-text nil) +(defun doom-modeline-update-flycheck-text (&optional status) + "Update flycheck text via STATUS." + (setq doom-modeline--flycheck-text + (when-let + ((text + (pcase status + ('finished (when flycheck-current-errors + (let-alist (doom-modeline--flycheck-count-errors) + (if doom-modeline-checker-simple-format + (doom-modeline-checker-text + (number-to-string (+ .error .warning .info)) + (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info))) + (format "%s/%s/%s" + (doom-modeline-checker-text (number-to-string .error) + 'doom-modeline-urgent) + (doom-modeline-checker-text (number-to-string .warning) + 'doom-modeline-warning) + (doom-modeline-checker-text (number-to-string .info) + 'doom-modeline-info)))))) + ('running nil) + ('no-checker nil) + ('errored (doom-modeline-checker-text "Error" 'doom-modeline-urgent)) + ('interrupted (doom-modeline-checker-text "Interrupted" 'doom-modeline-debug)) + ('suspicious (doom-modeline-checker-text "Suspicious" 'doom-modeline-urgent)) + (_ nil)))) + (propertize + text + 'help-echo (pcase status + ('finished + (concat + (when flycheck-current-errors + (let-alist (doom-modeline--flycheck-count-errors) + (format "error: %d, warning: %d, info: %d\n" .error .warning .info))) + "mouse-1: Show all errors +mouse-3: Next error" + (if (featurep 'mwheel) + "\nwheel-up/wheel-down: Previous/next error"))) + ('running "Running...") + ('no-checker "No Checker") + ('errored "Error") + ('interrupted "Interrupted") + ('suspicious "Suspicious")) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'flycheck-list-errors) + (define-key map [mode-line mouse-3] + #'flycheck-next-error) + (when (featurep 'mwheel) + (define-key map [mode-line mouse-wheel-down-event] + (lambda (event) + (interactive "e") + (with-selected-window (posn-window (event-start event)) + (flycheck-previous-error 1)))) + (define-key map [mode-line mouse-wheel-up-event] + (lambda (event) + (interactive "e") + (with-selected-window (posn-window (event-start event)) + (flycheck-next-error 1)))) + map)))))) +(add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck-text) +(add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck-text) + +;; Flymake + +;; Compatibility +;; @see https://github.com/emacs-mirror/emacs/commit/6e100869012da9244679696634cab6b9cac96303. +(with-eval-after-load 'flymake + (unless (boundp 'flymake--state) + (defvaralias 'flymake--state 'flymake--backend-state)) + (unless (fboundp 'flymake--state-diags) + (defalias 'flymake--state-diags 'flymake--backend-state-diags))) + +(defvar-local doom-modeline--flymake-icon nil) +(defun doom-modeline-update-flymake-icon (&rest _) + "Update flymake icon." + (setq flymake--mode-line-format nil) ; remove the lighter of minor mode + (setq doom-modeline--flymake-icon + (let* ((known (hash-table-keys flymake--state)) + (running (flymake-running-backends)) + (disabled (flymake-disabled-backends)) + (reported (flymake-reporting-backends)) + (all-disabled (and disabled (null running))) + (some-waiting (cl-set-difference running reported))) + (when-let + ((icon + (cond + (some-waiting (doom-modeline-checker-icon "access_time" "⏰" "*" 'doom-modeline-debug)) + ((null known) (doom-modeline-checker-icon "sim_card_alert" "❓" "?" 'doom-modeline-debug)) + (all-disabled (doom-modeline-checker-icon "sim_card_alert" "❗" "!" 'doom-modeline-urgent)) + (t (let ((.error 0) + (.warning 0) + (.note 0)) + (progn + (cl-loop + with warning-level = (warning-numeric-level :warning) + with note-level = (warning-numeric-level :debug) + for state being the hash-values of flymake--state + do (cl-loop + with diags = (flymake--state-diags state) + for diag in diags do + (let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity + (warning-numeric-level :error)))) + (cond ((> severity warning-level) (cl-incf .error)) + ((> severity note-level) (cl-incf .warning)) + (t (cl-incf .note)))))) + (if (> (+ .error .warning .note) 0) + (doom-modeline-checker-icon "do_not_disturb_alt" "🚫" "!" + (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info))) + (doom-modeline-checker-icon "check" "βœ”" "-" 'doom-modeline-info)))))))) + (propertize + icon + 'help-echo (concat "Flymake\n" + (cond + (some-waiting "Running...") + ((null known) "No Checker") + (all-disabled "All Checkers Disabled") + (t (format "%d/%d backends running +mouse-1: Display minor mode menu +mouse-2: Show help for minor mode" + (length running) (length known))))) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line down-mouse-1] + flymake-menu) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'flymake-mode))) + map)))))) +(advice-add #'flymake--handle-report :after #'doom-modeline-update-flymake-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flymake-mode) + (flymake-start))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flymake-mode) + (flymake-start))))))) + +(defvar-local doom-modeline--flymake-text nil) +(defun doom-modeline-update-flymake-text (&rest _) + "Update flymake text." + (setq flymake--mode-line-format nil) ; remove the lighter of minor mode + (setq doom-modeline--flymake-text + (let* ((known (hash-table-keys flymake--state)) + (running (flymake-running-backends)) + (disabled (flymake-disabled-backends)) + (reported (flymake-reporting-backends)) + (all-disabled (and disabled (null running))) + (some-waiting (cl-set-difference running reported)) + (warning-level (warning-numeric-level :warning)) + (note-level (warning-numeric-level :debug)) + (.error 0) + (.warning 0) + (.note 0)) + (maphash (lambda (_b state) + (cl-loop + with diags = (flymake--state-diags state) + for diag in diags do + (let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity + (warning-numeric-level :error)))) + (cond ((> severity warning-level) (cl-incf .error)) + ((> severity note-level) (cl-incf .warning)) + (t (cl-incf .note)))))) + flymake--state) + (when-let + ((text + (cond + (some-waiting doom-modeline--flymake-text) + ((null known) nil) + (all-disabled nil) + (t (let ((num (+ .error .warning .note))) + (when (> num 0) + (if doom-modeline-checker-simple-format + (doom-modeline-checker-text (number-to-string num) + (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info))) + (format "%s/%s/%s" + (doom-modeline-checker-text (number-to-string .error) + 'doom-modeline-urgent) + (doom-modeline-checker-text (number-to-string .warning) + 'doom-modeline-warning) + (doom-modeline-checker-text (number-to-string .note) + 'doom-modeline-info))))))))) + (propertize + text + 'help-echo (cond + (some-waiting "Running...") + ((null known) "No Checker") + (all-disabled "All Checkers Disabled") + (t (format "error: %d, warning: %d, note: %d +mouse-1: List all problems%s" + .error .warning .note + (if (featurep 'mwheel) + "\nwheel-up/wheel-down: Previous/next problem")))) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'flymake-show-diagnostics-buffer) + (when (featurep 'mwheel) + (define-key map (vector 'mode-line + mouse-wheel-down-event) + (lambda (event) + (interactive "e") + (with-selected-window (posn-window (event-start event)) + (flymake-goto-prev-error 1 nil t)))) + (define-key map (vector 'mode-line + mouse-wheel-up-event) + (lambda (event) + (interactive "e") + (with-selected-window (posn-window (event-start event)) + (flymake-goto-next-error 1 nil t)))) + map))))))) +(advice-add #'flymake--handle-report :after #'doom-modeline-update-flymake-text) + +(doom-modeline-def-segment checker + "Displays color-coded error status in the current buffer with pretty icons." + (let ((active (doom-modeline--active)) + (seg (cond ((and (bound-and-true-p flymake-mode) + (bound-and-true-p flymake--state)) ; only support 26+ + `(,doom-modeline--flymake-icon . ,doom-modeline--flymake-text)) + ((bound-and-true-p flycheck-mode) + `(,doom-modeline--flycheck-icon . ,doom-modeline--flycheck-text))))) + (let ((icon (car seg)) + (text (cdr seg))) + (concat + (when icon + (concat + (doom-modeline-spc) + (if active + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)))) + (when text + (concat + (if icon (doom-modeline-vspc) (doom-modeline-spc)) + (if active + text + (propertize text 'face 'mode-line-inactive)))) + (doom-modeline-spc))))) + + +;; +;; Word Count +;; + +(doom-modeline-def-segment word-count + "The buffer word count. +Displayed when in a major mode in `doom-modeline-continuous-word-count-modes'. +Respects `doom-modeline-enable-word-count'." + (when (and doom-modeline-enable-word-count + (member major-mode doom-modeline-continuous-word-count-modes)) + (propertize (format " %dW" (count-words (point-min) (point-max))) + 'face (if (doom-modeline--active) + 'mode-line + 'mode-line-inactive)))) + + +;; +;; Selection +;; + +(defsubst doom-modeline-column (pos) + "Get the column of the position `POS'." + (save-excursion (goto-char pos) + (current-column))) + +(doom-modeline-def-segment selection-info + "Information about the current selection, such as how many characters and +lines are selected, or the NxM dimensions of a block selection." + (when (and (or mark-active (and (bound-and-true-p evil-local-mode) + (eq evil-state 'visual))) + (doom-modeline--active)) + (cl-destructuring-bind (beg . end) + (if (and (bound-and-true-p evil-local-mode) (eq evil-state 'visual)) + (cons evil-visual-beginning evil-visual-end) + (cons (region-beginning) (region-end))) + (propertize + (let ((lines (count-lines beg (min end (point-max))))) + (concat (doom-modeline-spc) + (cond ((or (bound-and-true-p rectangle-mark-mode) + (and (bound-and-true-p evil-visual-selection) + (eq 'block evil-visual-selection))) + (let ((cols (abs (- (doom-modeline-column end) + (doom-modeline-column beg))))) + (format "%dx%dB" lines cols))) + ((and (bound-and-true-p evil-visual-selection) + (eq evil-visual-selection 'line)) + (format "%dL" lines)) + ((> lines 1) + (format "%dC %dL" (- end beg) lines)) + (t + (format "%dC" (- end beg)))) + (when doom-modeline-enable-word-count + (format " %dW" (count-words beg end))) + (doom-modeline-spc))) + 'face 'doom-modeline-highlight)))) + + +;; +;; Matches (macro, anzu, evil-substitute, iedit, symbol-overlay and multi-cursors) +;; + +(defsubst doom-modeline--macro-recording () + "Display current Emacs or evil macro being recorded." + (when (and (doom-modeline--active) + (or defining-kbd-macro executing-kbd-macro)) + (let ((sep (propertize " " 'face 'doom-modeline-panel )) + (vsep (propertize " " 'face + '(:inherit (doom-modeline-panel variable-pitch))))) + (concat + sep + (doom-modeline-icon 'material "fiber_manual_record" "●" + (if (bound-and-true-p evil-this-macro) + (char-to-string evil-this-macro) + "Macro") + :face 'doom-modeline-panel + :v-adjust -0.225) + vsep + (doom-modeline-icon 'octicon "triangle-right" "β–Ά" ">" + :face 'doom-modeline-panel + :v-adjust -0.05) + sep)))) + +;; `anzu' and `evil-anzu' expose current/total state that can be displayed in the +;; mode-line. +(defun doom-modeline-fix-anzu-count (positions here) + "Calulate anzu count via POSITIONS and HERE." + (cl-loop for (start . end) in positions + collect t into before + when (and (>= here start) (<= here end)) + return (length before) + finally return 0)) + +(advice-add #'anzu--where-is-here :override #'doom-modeline-fix-anzu-count) + +(setq anzu-cons-mode-line-p nil) ; manage modeline segment ourselves +;; Ensure anzu state is cleared when searches & iedit are done +(with-eval-after-load 'anzu + (add-hook 'isearch-mode-end-hook #'anzu--reset-status t) + (add-hook 'iedit-mode-end-hook #'anzu--reset-status) + (advice-add #'evil-force-normal-state :after #'anzu--reset-status) + ;; Fix matches segment mirroring across all buffers + (mapc #'make-variable-buffer-local + '(anzu--total-matched + anzu--current-position anzu--state anzu--cached-count + anzu--cached-positions anzu--last-command + anzu--last-isearch-string anzu--overflow-p))) + +(defsubst doom-modeline--anzu () + "Show the match index and total number thereof. +Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with +`evil-search'." + (when (and (bound-and-true-p anzu--state) + (not (bound-and-true-p iedit-mode))) + (propertize + (let ((here anzu--current-position) + (total anzu--total-matched)) + (cond ((eq anzu--state 'replace-query) + (format " %d replace " anzu--cached-count)) + ((eq anzu--state 'replace) + (format " %d/%d " here total)) + (anzu--overflow-p + (format " %s+ " total)) + (t + (format " %s/%d " here total)))) + 'face (if (doom-modeline--active) 'doom-modeline-panel 'mode-line-inactive)))) + +(defsubst doom-modeline--evil-substitute () + "Show number of matches for evil-ex substitutions and highlights in real time." + (when (and (bound-and-true-p evil-local-mode) + (or (assq 'evil-ex-substitute evil-ex-active-highlights-alist) + (assq 'evil-ex-global-match evil-ex-active-highlights-alist) + (assq 'evil-ex-buffer-match evil-ex-active-highlights-alist))) + (propertize + (let ((range (if evil-ex-range + (cons (car evil-ex-range) (cadr evil-ex-range)) + (cons (line-beginning-position) (line-end-position)))) + (pattern (car-safe (evil-delimited-arguments evil-ex-argument 2)))) + (if pattern + (format " %s matches " (how-many pattern (car range) (cdr range))) + " - ")) + 'face (if (doom-modeline--active) 'doom-modeline-panel 'mode-line-inactive)))) + +(defun doom-modeline-themes--overlay-sort (a b) + "Sort overlay A and B." + (< (overlay-start a) (overlay-start b))) + +(defsubst doom-modeline--iedit () + "Show the number of iedit regions matches + what match you're on." + (when (and (bound-and-true-p iedit-mode) + (bound-and-true-p iedit-occurrences-overlays)) + (propertize + (let ((this-oc (or (let ((inhibit-message t)) + (iedit-find-current-occurrence-overlay)) + (save-excursion (iedit-prev-occurrence) + (iedit-find-current-occurrence-overlay)))) + (length (length iedit-occurrences-overlays))) + (format " %s/%d " + (if this-oc + (- length + (length (memq this-oc (sort (append iedit-occurrences-overlays nil) + #'doom-modeline-themes--overlay-sort))) + -1) + "-") + length)) + 'face (if (doom-modeline--active) 'doom-modeline-panel 'mode-line-inactive)))) + +(defsubst doom-modeline--symbol-overlay () + "Show the number of matches for symbol overlay." + (when-let ((active (doom-modeline--active))) + (when (and (bound-and-true-p symbol-overlay-keywords-alist) + (not (bound-and-true-p symbol-overlay-temp-symbol)) + (not (bound-and-true-p iedit-mode))) + (let* ((keyword (symbol-overlay-assoc (symbol-overlay-get-symbol t))) + (symbol (car keyword)) + (before (symbol-overlay-get-list -1 symbol)) + (after (symbol-overlay-get-list 1 symbol)) + (count (length before))) + (if (symbol-overlay-assoc symbol) + (propertize + (format (concat " %d/%d " (and (cadr keyword) "in scope ")) + (+ count 1) + (+ count (length after))) + 'face (if active 'doom-modeline-panel 'mode-line-inactive))))))) + +(defsubst doom-modeline--multiple-cursors () + "Show the number of multiple cursors." + (cl-destructuring-bind (count . face) + (cond ((bound-and-true-p multiple-cursors-mode) + (cons (mc/num-cursors) + (if (doom-modeline--active) + 'doom-modeline-panel + 'mode-line-inactive))) + ((bound-and-true-p evil-mc-cursor-list) + (cons (length evil-mc-cursor-list) + (cond ((not (doom-modeline--active)) 'mode-line-inactive) + (evil-mc-frozen 'doom-modeline-bar) + ('doom-modeline-panel)))) + ((cons nil nil))) + (when count + (concat (propertize " " 'face face) + (or (doom-modeline-icon 'faicon "i-cursor" nil nil + :face face :v-adjust -0.0575) + (propertize "I" + 'face `(:inherit ,face :height 1.4 :weight normal) + 'display '(raise -0.1))) + (propertize (doom-modeline-vspc) + 'face `(:inherit (variable-pitch ,face))) + (propertize (format "%d " count) + 'face face))))) + +(defsubst doom-modeline--phi-search () + "Show the number of matches for `phi-search' and `phi-replace'." + (when-let ((active (doom-modeline--active))) + (when (bound-and-true-p phi-search--overlays) + (let ((total (length phi-search--overlays)) + (selection phi-search--selection)) + (when selection + (propertize + (format " %d/%d " (1+ selection) total) + 'face (if active 'doom-modeline-panel 'mode-line-inactive))))))) + +(defun doom-modeline--override-phi-search-mode-line (orig-fun &rest args) + "Override the mode-line of `phi-search' and `phi-replace'." + (if (bound-and-true-p doom-modeline-mode) + (apply orig-fun mode-line-format (cdr args)) + (apply orig-fun args))) +(advice-add #'phi-search--initialize :around #'doom-modeline--override-phi-search-mode-line) + +(defsubst doom-modeline--buffer-size () + "Show buffer size." + (when size-indication-mode + (concat (doom-modeline-spc) + (propertize "%I" + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive) + 'help-echo "Buffer size +mouse-1: Display Line and Column Mode Menu" + 'mouse-face 'mode-line-highlight + 'local-map mode-line-column-line-number-mode-map) + (doom-modeline-spc)))) + +(doom-modeline-def-segment matches + "Displays: 1. the currently recording macro, 2. A current/total for the +current search term (with `anzu'), 3. The number of substitutions being +conducted with `evil-ex-substitute', and/or 4. The number of active `iedit' +regions, 5. The current/total for the highlight term (with `symbol-overlay'), +6. The number of active `multiple-cursors'." + (let ((meta (concat (doom-modeline--macro-recording) + (doom-modeline--anzu) + (doom-modeline--phi-search) + (doom-modeline--evil-substitute) + (doom-modeline--iedit) + (doom-modeline--symbol-overlay) + (doom-modeline--multiple-cursors)))) + (or (and (not (string-empty-p meta)) meta) + (doom-modeline--buffer-size)))) + +(doom-modeline-def-segment buffer-size + "Display buffer size." + (doom-modeline--buffer-size)) + +;; +;; Media +;; + +(doom-modeline-def-segment media-info + "Metadata regarding the current file, such as dimensions for images." + ;; TODO Include other information + (cond ((eq major-mode 'image-mode) + (cl-destructuring-bind (width . height) + (when (fboundp 'image-size) + (image-size (image-get-display-property) :pixels)) + (propertize + (format " %dx%d " width height) + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive)))))) + + +;; +;; Bars +;; + +(defvar doom-modeline--bar-active nil) +(defvar doom-modeline--bar-inactive nil) + +(defsubst doom-modeline--bar () + "The default bar regulates the height of the mode-line in GUI." + (unless (and doom-modeline--bar-active doom-modeline--bar-inactive) + (let ((width doom-modeline-bar-width) + (height (max doom-modeline-height + (doom-modeline--font-height)))) + (when (and (numberp width) (numberp height)) + (setq doom-modeline--bar-active + (doom-modeline--create-bar-image 'doom-modeline-bar width height) + doom-modeline--bar-inactive + (doom-modeline--create-bar-image + 'doom-modeline-bar-inactive width height))))) + (if (doom-modeline--active) + doom-modeline--bar-active + doom-modeline--bar-inactive)) + +(defun doom-modeline-refresh-bars () + "Refresh mode-line bars on next redraw." + (setq doom-modeline--bar-active nil + doom-modeline--bar-inactive nil)) + +(cl-defstruct doom-modeline--hud-cache active inactive top-margin bottom-margin) + +(defsubst doom-modeline--hud () + "Powerline's hud segment reimplemented in the style of Doom's bar segment." + (let* ((ws (window-start)) + (we (window-end)) + (bs (buffer-size)) + (height (max doom-modeline-height + (doom-modeline--font-height))) + (top-margin (if (zerop bs) + 0 + (/ (* height (1- ws)) bs))) + (bottom-margin (if (zerop bs) + 0 + (max 0 (/ (* height (- bs we 1)) bs)))) + (cache (or (window-parameter nil 'doom-modeline--hud-cache) + (set-window-parameter nil 'doom-modeline--hud-cache + (make-doom-modeline--hud-cache))))) + (unless (and (doom-modeline--hud-cache-active cache) + (doom-modeline--hud-cache-inactive cache) + (= top-margin (doom-modeline--hud-cache-top-margin cache)) + (= bottom-margin + (doom-modeline--hud-cache-bottom-margin cache))) + (setf (doom-modeline--hud-cache-active cache) + (doom-modeline--create-hud-image + 'doom-modeline-bar 'default doom-modeline-bar-width + height top-margin bottom-margin) + (doom-modeline--hud-cache-inactive cache) + (doom-modeline--create-hud-image + 'doom-modeline-bar-inactive 'default doom-modeline-bar-width + height top-margin bottom-margin) + (doom-modeline--hud-cache-top-margin cache) top-margin + (doom-modeline--hud-cache-bottom-margin cache) bottom-margin)) + (if (doom-modeline--active) + (doom-modeline--hud-cache-active cache) + (doom-modeline--hud-cache-inactive cache)))) + +(defun doom-modeline-invalidate-huds () + "Invalidate all cached hud images." + (dolist (frame (frame-list)) + (dolist (window (window-list frame)) + (set-window-parameter window 'doom-modeline--hud-cache nil)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-height + (lambda (_sym val op _where) + (when (and (eq op 'set) (integerp val)) + (doom-modeline-refresh-bars) + (doom-modeline-invalidate-huds)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-bar-width + (lambda (_sym val op _where) + (when (and (eq op 'set) (integerp val)) + (doom-modeline-refresh-bars) + (doom-modeline-invalidate-huds)))) + +(add-hook 'after-setting-font-hook #'doom-modeline-refresh-bars) +(add-hook 'after-setting-font-hook #'doom-modeline-invalidate-huds) + +(doom-modeline-def-segment bar + "The bar regulates the height of the mode-line in GUI." + (if doom-modeline-hud + (doom-modeline--hud) + (doom-modeline--bar))) + +(doom-modeline-def-segment hud + "Powerline's hud segment reimplemented in the style of Doom's bar segment." + (doom-modeline--hud)) + + +;; +;; Window number +;; + +;; HACK: `ace-window-display-mode' should respect the ignore buffers. +(defun doom-modeline-aw-update () + "Update ace-window-path window parameter for all windows. +Ensure all windows are labeled so the user can select a specific +one. The ignored buffers are excluded unless `aw-ignore-on' is nil." + (let ((ignore-window-parameters t)) + (avy-traverse + (avy-tree (aw-window-list) aw-keys) + (lambda (path leaf) + (set-window-parameter + leaf 'ace-window-path + (propertize + (apply #'string (reverse path)) + 'face 'aw-mode-line-face)))))) +(advice-add #'aw-update :override #'doom-modeline-aw-update) + +;; Remove original window number of `ace-window-display-mode'. +(add-hook 'ace-window-display-mode-hook + (lambda () + (setq-default mode-line-format + (assq-delete-all 'ace-window-display-mode + (default-value 'mode-line-format))))) + +(advice-add #'window-numbering-install-mode-line :override #'ignore) +(advice-add #'window-numbering-clear-mode-line :override #'ignore) +(advice-add #'winum--install-mode-line :override #'ignore) +(advice-add #'winum--clear-mode-line :override #'ignore) + +(doom-modeline-def-segment window-number + "The current window number." + (let ((num (cond + ((bound-and-true-p ace-window-display-mode) + (aw-update) + (window-parameter (selected-window) 'ace-window-path)) + ((bound-and-true-p winum-mode) + (setq winum-auto-setup-mode-line nil) + (winum-get-number-string)) + ((bound-and-true-p window-numbering-mode) + (window-numbering-get-number-string)) + (t "")))) + (if (and (< 0 (length num)) + (< 1 (length (cl-mapcan + (lambda (frame) + ;; Exclude minibuffer and child frames + (unless (and (fboundp 'frame-parent) + (frame-parent frame)) + (window-list frame 'never))) + (visible-frame-list))))) + (propertize (format " %s " num) + 'face (if (doom-modeline--active) + 'doom-modeline-buffer-major-mode + 'mode-line-inactive)) + (doom-modeline-spc)))) + + +;; +;; Workspace +;; + +(doom-modeline-def-segment workspace-name + "The current workspace name or number. +Requires `eyebrowse-mode' to be enabled or `tab-bar-mode' tabs to be created." + (when doom-modeline-workspace-name + (when-let + ((name (cond + ((and (bound-and-true-p eyebrowse-mode) + (< 1 (length (eyebrowse--get 'window-configs)))) + (assq-delete-all 'eyebrowse-mode mode-line-misc-info) + (when-let* + ((num (eyebrowse--get 'current-slot)) + (tag (nth 2 (assoc num (eyebrowse--get 'window-configs))))) + (if (< 0 (length tag)) tag (int-to-string num)))) + ((and (fboundp 'tab-bar-mode) + (< 1 (length (frame-parameter nil 'tabs)))) + (let* ((current-tab (tab-bar--current-tab)) + (tab-index (tab-bar--current-tab-index)) + (explicit-name (alist-get 'explicit-name current-tab)) + (tab-name (alist-get 'name current-tab))) + (if explicit-name tab-name (+ 1 tab-index))))))) + (propertize (format " %s " name) 'face + (if (doom-modeline--active) + 'doom-modeline-buffer-major-mode + 'mode-line-inactive))))) + + +;; +;; Perspective +;; + +(defvar-local doom-modeline--persp-name nil) +(defun doom-modeline-update-persp-name (&rest _) + "Update perspective name in mode-line." + (setq doom-modeline--persp-name + ;; Support `persp-mode', while not support `perspective' + (when (and doom-modeline-persp-name + (bound-and-true-p persp-mode) + (fboundp 'safe-persp-name) + (fboundp 'get-current-persp)) + (let* ((persp (get-current-persp)) + (name (safe-persp-name persp)) + (face (if (and persp + (not (persp-contain-buffer-p (current-buffer) persp))) + 'doom-modeline-persp-buffer-not-in-persp + 'doom-modeline-persp-name)) + (icon (doom-modeline-icon 'material "folder" "πŸ–Ώ" "#" + :face `(:inherit ,face :slant normal) + :height 1.1 + :v-adjust -0.225))) + (when (or doom-modeline-display-default-persp-name + (not (string-equal persp-nil-name name))) + (concat (doom-modeline-spc) + (propertize (concat (and doom-modeline-persp-icon + (concat icon (doom-modeline-vspc))) + (propertize name 'face face)) + 'help-echo "mouse-1: Switch perspective +mouse-2: Show help for minor mode" + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'persp-switch) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'persp-mode))) + map)) + (doom-modeline-spc))))))) + +(add-hook 'buffer-list-update-hook #'doom-modeline-update-persp-name) +(add-hook 'find-file-hook #'doom-modeline-update-persp-name) +(add-hook 'persp-activated-functions #'doom-modeline-update-persp-name) +(add-hook 'persp-renamed-functions #'doom-modeline-update-persp-name) +(advice-add #'lv-message :after #'doom-modeline-update-persp-name) + +(doom-modeline-def-segment persp-name + "The current perspective name." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p)) + doom-modeline--persp-name)) + + +;; +;; Misc info +;; + +(doom-modeline-def-segment misc-info + "Mode line construct for miscellaneous information. +By default, this shows the information specified by `global-mode-string'." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p)) + '("" mode-line-misc-info))) + + +;; +;; Position +;; + +;; Be compatible with Emacs 25. +(defvar doom-modeline-column-zero-based + (if (boundp 'column-number-indicator-zero-based) + column-number-indicator-zero-based + t) + "When non-nil, mode line displays column numbers zero-based. +See `column-number-indicator-zero-based'.") + +(defvar doom-modeline-percent-position + (if (boundp 'mode-line-percent-position) + mode-line-percent-position + '(-3 "%p")) + "Specification of \"percentage offset\" of window through buffer. +See `mode-line-percent-position'.") + +(doom-modeline-add-variable-watcher + 'column-number-indicator-zero-based + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-column-zero-based val)))) + +(doom-modeline-add-variable-watcher + 'mode-line-percent-position + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-percent-position val)))) + +(doom-modeline-def-segment buffer-position + "The buffer position information." + (let* ((active (doom-modeline--active)) + (lc '(line-number-mode + (column-number-mode + (doom-modeline-column-zero-based "%l:%c" "%l:%C") + "%l") + (column-number-mode (doom-modeline-column-zero-based ":%c" ":%C")))) + (face (if active 'mode-line 'mode-line-inactive)) + (mouse-face 'mode-line-highlight) + (local-map mode-line-column-line-number-mode-map)) + (concat + (doom-modeline-wspc) + + ;; Line and column + (propertize (format-mode-line lc) + 'face face + 'help-echo "Buffer position\n\ +mouse-1: Display Line and Column Mode Menu" + 'mouse-face mouse-face + 'local-map local-map) + + ;; Position + (cond ((and active + (bound-and-true-p nyan-mode) + (not doom-modeline--limited-width-p) + (>= (window-width) nyan-minimum-window-width)) + (concat + (doom-modeline-wspc) + (propertize (nyan-create) 'mouse-face mouse-face))) + ((and active + (bound-and-true-p poke-line-mode) + (not doom-modeline--limited-width-p) + (>= (window-width) poke-line-minimum-window-width)) + (concat + (doom-modeline-wspc) + (propertize (poke-line-create) 'mouse-face mouse-face))) + ((and active + (bound-and-true-p mlscroll-mode) + (not doom-modeline--limited-width-p) + (>= (window-width) mlscroll-minimum-current-width)) + (concat + (doom-modeline-wspc) + (let ((mlscroll-right-align nil)) + (format-mode-line (mlscroll-mode-line))))) + ((and active + (bound-and-true-p sml-modeline-mode) + (not doom-modeline--limited-width-p) + (>= (window-width) sml-modeline-len)) + (concat + (doom-modeline-wspc) + (propertize (sml-modeline-create) 'mouse-face mouse-face))) + (t "")) + + ;; Percent position + (when doom-modeline-percent-position + (concat + (doom-modeline-spc) + (propertize (format-mode-line '("" doom-modeline-percent-position "%%")) + 'face face + 'help-echo "Buffer percentage\n\ +mouse-1: Display Line and Column Mode Menu" + 'mouse-face mouse-face + 'local-map local-map))) + + (when (or line-number-mode column-number-mode doom-modeline-percent-position) + (doom-modeline-spc))))) + +;; +;; Party parrot +;; +(doom-modeline-def-segment parrot + "The party parrot animated icon. Requires `parrot-mode' to be enabled." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p) + (bound-and-true-p parrot-mode)) + (concat (doom-modeline-wspc) + (parrot-create) + (doom-modeline-spc)))) + +;; +;; Modals (evil, overwrite, god, ryo and xah-fly-keys, etc.) +;; + +(defun doom-modeline--modal-icon (text face help-echo) + "Display the model icon with FACE and HELP-ECHO. +TEXT is alternative if icon is not available." + (propertize (doom-modeline-icon + 'material + (when doom-modeline-modal-icon "fiber_manual_record") + "●" + text + :face (if (doom-modeline--active) face 'mode-line-inactive) + :v-adjust -0.225) + 'help-echo help-echo)) + +(defsubst doom-modeline--evil () + "The current evil state. Requires `evil-mode' to be enabled." + (when (bound-and-true-p evil-local-mode) + (doom-modeline--modal-icon + (let ((tag (evil-state-property evil-state :tag t))) + (if (stringp tag) tag (funcall tag))) + (cond + ((evil-normal-state-p) 'doom-modeline-evil-normal-state) + ((evil-emacs-state-p) 'doom-modeline-evil-emacs-state) + ((evil-insert-state-p) 'doom-modeline-evil-insert-state) + ((evil-motion-state-p) 'doom-modeline-evil-motion-state) + ((evil-visual-state-p) 'doom-modeline-evil-visual-state) + ((evil-operator-state-p) 'doom-modeline-evil-operator-state) + ((evil-replace-state-p) 'doom-modeline-evil-replace-state) + (t 'doom-modeline-evil-normal-state)) + (evil-state-property evil-state :name t)))) + +(defsubst doom-modeline--overwrite () + "The current overwrite state which is enabled by command `overwrite-mode'." + (when (and (bound-and-true-p overwrite-mode) + (not (bound-and-true-p evil-local-mode))) + (doom-modeline--modal-icon " " 'doom-modeline-urgent "Overwrite mode"))) + +(defsubst doom-modeline--god () + "The current god state which is enabled by the command `god-mode'." + (when (bound-and-true-p god-local-mode) + (doom-modeline--modal-icon " " 'doom-modeline-evil-normal-state "God mode"))) + +(defsubst doom-modeline--ryo () + "The current ryo-modal state which is enabled by the command `ryo-modal-mode'." + (when (bound-and-true-p ryo-modal-mode) + (doom-modeline--modal-icon "" 'doom-modeline-evil-normal-state "Ryo modal"))) + +(defsubst doom-modeline--xah-fly-keys () + "The current `xah-fly-keys' state." + (when (bound-and-true-p xah-fly-keys) + (if xah-fly-insert-state-p + (doom-modeline--modal-icon " " + 'doom-modeline-evil-insert-state + (format "Xah-fly insert mode")) + (doom-modeline--modal-icon " " + 'doom-modeline-evil-normal-state + (format "Xah-fly command mode"))))) + +(defsubst doom-modeline--boon () + "The current Boon state. Requires `boon-mode' to be enabled." + (when (bound-and-true-p boon-local-mode) + (doom-modeline--modal-icon + (boon-state-string) + (cond + (boon-command-state 'doom-modeline-evil-normal-state) + (boon-insert-state 'doom-modeline-evil-insert-state) + (boon-special-state 'doom-modeline-evil-emacs-state) + (boon-off-state 'doom-modeline-evil-operator-state) + (t 'doom-modeline-evil-operator-state)) + (boon-modeline-string)))) + +(defsubst doom-modeline--meow () + "The current Meow state. Requires `meow-mode' to be enabled." + (when (bound-and-true-p meow-mode) + meow--indicator)) + +(doom-modeline-def-segment modals + "Displays modal editing states, including `evil', `overwrite', `god', `ryo' +and `xha-fly-kyes', etc." + (let* ((evil (doom-modeline--evil)) + (ow (doom-modeline--overwrite)) + (god (doom-modeline--god)) + (ryo (doom-modeline--ryo)) + (xf (doom-modeline--xah-fly-keys)) + (boon (doom-modeline--boon)) + (vsep (doom-modeline-vspc)) + (meow (doom-modeline--meow)) + (sep (and (or evil ow god ryo xf boon) (doom-modeline-spc)))) + (concat sep + (and evil (concat evil (and (or ow god ryo xf boon meow) vsep))) + (and ow (concat ow (and (or god ryo xf boon meow) vsep))) + (and god (concat god (and (or ryo xf boon meow) vsep))) + (and ryo (concat ryo (and (or xf boon meow) vsep))) + (and xf (concat xf (and (or boon meow) vsep))) + (and boon (concat boon (and meow vsep))) + meow + sep))) + +;; +;; Objed state +;; + +(defvar doom-modeline--objed-active nil) + +(defun doom-modeline-update-objed (_ &optional reset) + "Update `objed' status, inactive when RESET is true." + (setq doom-modeline--objed-active (not reset))) + +(setq objed-modeline-setup-func #'doom-modeline-update-objed) + +(doom-modeline-def-segment objed-state () + "The current objed state." + (when (and doom-modeline--objed-active + (doom-modeline--active)) + (propertize (format " %s(%s) " + (symbol-name objed--object) + (char-to-string (aref (symbol-name objed--obj-state) 0))) + 'face 'doom-modeline-evil-emacs-state + 'help-echo (format "Objed object: %s (%s)" + (symbol-name objed--object) + (symbol-name objed--obj-state))))) + + +;; +;; Input method +;; + +(doom-modeline-def-segment input-method + "The current input method." + (propertize (cond (current-input-method + (concat (doom-modeline-spc) + current-input-method-title + (doom-modeline-spc))) + ((and (bound-and-true-p evil-local-mode) + (bound-and-true-p evil-input-method)) + (concat + (doom-modeline-spc) + (nth 3 (assoc default-input-method input-method-alist)) + (doom-modeline-spc))) + (t "")) + 'face (if (doom-modeline--active) + (if (and (bound-and-true-p rime-mode) + (equal current-input-method "rime")) + (if (and (rime--should-enable-p) + (not (rime--should-inline-ascii-p))) + 'doom-modeline-input-method + 'doom-modeline-input-method-alt) + 'doom-modeline-input-method) + 'mode-line-inactive) + 'help-echo (concat + "Current input method: " + current-input-method + "\n\ +mouse-2: Disable input method\n\ +mouse-3: Describe current input method") + 'mouse-face 'mode-line-highlight + 'local-map mode-line-input-method-map)) + + +;; +;; Info +;; + +(doom-modeline-def-segment info-nodes + "The topic and nodes in the Info buffer." + (let ((active (doom-modeline--active))) + (concat + (propertize " (" 'face (if active 'mode-line 'mode-line-inactive)) + ;; topic + (propertize (if (stringp Info-current-file) + (replace-regexp-in-string + "%" "%%" + (file-name-sans-extension + (file-name-nondirectory Info-current-file))) + (format "*%S*" Info-current-file)) + 'face (if active 'doom-modeline-info 'mode-line-inactive)) + (propertize ") " 'face (if active 'mode-line 'mode-line-inactive)) + ;; node + (when Info-current-node + (propertize (replace-regexp-in-string + "%" "%%" Info-current-node) + 'face (if active 'doom-modeline-buffer-path 'mode-line-inactive) + 'help-echo + "mouse-1: scroll forward, mouse-3: scroll back" + 'mouse-face 'mode-line-highlight + 'local-map Info-mode-line-node-keymap))))) + + +;; +;; REPL +;; + +(defun doom-modeline-repl-icon (text face) + "Display REPL icon (or TEXT in terminal) with FACE." + (doom-modeline-icon 'faicon "terminal" "$" text + :face face :height 1.0 :v-adjust -0.0575)) + +(defvar doom-modeline--cider nil) + +(defun doom-modeline-update-cider () + "Update cider repl state." + (setq doom-modeline--cider + (let* ((connected (cider-connected-p)) + (face (if connected 'doom-modeline-repl-success 'doom-modeline-repl-warning)) + (repl-buffer (cider-current-repl nil nil)) + (cider-info (when repl-buffer + (cider--connection-info repl-buffer t))) + (icon (doom-modeline-repl-icon "REPL" face))) + (propertize icon + 'help-echo + (if connected + (format "CIDER Connected %s\nmouse-2: CIDER quit" cider-info) + "CIDER Disconnected\nmouse-1: CIDER jack-in") + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (if connected + (define-key map [mode-line mouse-2] + #'cider-quit) + (define-key map [mode-line mouse-1] + #'cider-jack-in)) + map))))) + +(add-hook 'cider-connected-hook #'doom-modeline-update-cider) +(add-hook 'cider-disconnected-hook #'doom-modeline-update-cider) +(add-hook 'cider-mode-hook #'doom-modeline-update-cider) + +(doom-modeline-def-segment repl + "The REPL state." + (when doom-modeline-repl + (when-let (icon (when (bound-and-true-p cider-mode) + doom-modeline--cider)) + (concat + (doom-modeline-spc) + (if (doom-modeline--active) + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)) + (doom-modeline-spc))))) + + +;; +;; LSP +;; + +(defun doom-modeline-lsp-icon (text face) + "Display LSP icon (or TEXT in terminal) with FACE." + (doom-modeline-icon 'faicon "rocket" "πŸš€" text + :face face :height 1.0 :v-adjust -0.0575)) + +(defvar-local doom-modeline--lsp nil) +(defun doom-modeline-update-lsp (&rest _) + "Update `lsp-mode' state." + (setq doom-modeline--lsp + (let* ((workspaces (lsp-workspaces)) + (face (if workspaces 'doom-modeline-lsp-success 'doom-modeline-lsp-warning)) + (icon (doom-modeline-lsp-icon "LSP" face))) + (propertize icon + 'help-echo + (if workspaces + (concat "LSP Connected " + (string-join + (mapcar (lambda (w) + (format "[%s]\n" (lsp--workspace-print w))) + workspaces)) + "C-mouse-1: Switch to another workspace folder +mouse-1: Describe current session +mouse-2: Quit server +mouse-3: Reconnect to server") + "LSP Disconnected +mouse-1: Reload to start server") + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (if workspaces + (progn + (define-key map [mode-line C-mouse-1] + #'lsp-workspace-folders-open) + (define-key map [mode-line mouse-1] + #'lsp-describe-session) + (define-key map [mode-line mouse-2] + #'lsp-workspace-shutdown) + (define-key map [mode-line mouse-3] + #'lsp-workspace-restart)) + (progn + (define-key map [mode-line mouse-1] + (lambda () + (interactive) + (ignore-errors (revert-buffer t t)))))) + map))))) +(add-hook 'lsp-before-initialize-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-initialize-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-uninitialized-functions #'doom-modeline-update-lsp) +(add-hook 'lsp-before-open-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-open-hook #'doom-modeline-update-lsp) + +(defvar-local doom-modeline--eglot nil) +(defun doom-modeline-update-eglot () + "Update `eglot' state." + (setq doom-modeline--eglot + (pcase-let* ((server (and (eglot-managed-p) (eglot-current-server))) + (nick (and server (eglot--project-nickname server))) + (pending (and server (hash-table-count + (jsonrpc--request-continuations server)))) + (`(,_id ,doing ,done-p ,detail) (and server (eglot--spinner server))) + (last-error (and server (jsonrpc-last-error server))) + (face (cond (last-error 'doom-modeline-lsp-error) + ((and doing (not done-p)) 'doom-modeline-lsp-running) + ((and pending (cl-plusp pending)) 'doom-modeline-lsp-warning) + (nick 'doom-modeline-lsp-success) + (t 'doom-modeline-lsp-warning))) + (icon (doom-modeline-lsp-icon "EGLOT" face))) + (propertize icon + 'help-echo (cond + (last-error + (format "EGLOT\nAn error occured: %s +mouse-3: Clear this status" (plist-get last-error :message))) + ((and doing (not done-p)) + (format "EGLOT\n%s%s" doing + (if detail (format "%s" detail) ""))) + ((and pending (cl-plusp pending)) + (format "EGLOT\n%d outstanding requests" pending)) + (nick (format "EGLOT Connected (%s/%s) +C-mouse-1: Go to server errors +mouse-1: Go to server events +mouse-2: Quit server +mouse-3: Reconnect to server" nick (eglot--major-mode server))) + (t "EGLOT Disconnected +mouse-1: Start server")) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (cond (last-error + (define-key map [mode-line mouse-3] + #'eglot-clear-status)) + ((and pending (cl-plusp pending)) + (define-key map [mode-line mouse-3] + #'eglot-forget-pending-continuations)) + (nick + (define-key map [mode-line C-mouse-1] + #'eglot-stderr-buffer) + (define-key map [mode-line mouse-1] + #'eglot-events-buffer) + (define-key map [mode-line mouse-2] + #'eglot-shutdown) + (define-key map [mode-line mouse-3] + #'eglot-reconnect)) + (t (define-key map [mode-line mouse-1] + #'eglot))) + map))))) +(add-hook 'eglot-managed-mode-hook #'doom-modeline-update-eglot) + +(defvar-local doom-modeline--tags nil) +(defun doom-modeline-update-tags () + "Update tags state." + (setq doom-modeline--tags + (propertize + (doom-modeline-lsp-icon "LSP" 'doom-modeline-lsp-success) + 'help-echo "TAGS: Citre mode +mouse-1: Toggle citre mode" + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'citre-mode)))) +(add-hook 'citre-mode-hook #'doom-modeline-update-tags) + +(defun doom-modeline-update-lsp-icon () + "Update lsp icon." + (cond ((bound-and-true-p lsp-mode) + (doom-modeline-update-lsp)) + ((bound-and-true-p eglot--managed-mode) + (doom-modeline-update-eglot)) + ((bound-and-true-p citre-mode) + (doom-modeline-update-tags)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-lsp-icon)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-lsp-icon)))))) + +(doom-modeline-def-segment lsp + "The LSP server state." + (when (and doom-modeline-lsp + (not doom-modeline--limited-width-p)) + (let ((active (doom-modeline--active)) + (icon (cond ((bound-and-true-p lsp-mode) + doom-modeline--lsp) + ((bound-and-true-p eglot--managed-mode) + doom-modeline--eglot) + ((bound-and-true-p citre-mode) + doom-modeline--tags)))) + (when icon + (concat + (doom-modeline-spc) + (if active + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)) + (doom-modeline-spc)))))) + +(defun doom-modeline-override-eglot-modeline () + "Override `eglot' mode-line." + (if (bound-and-true-p doom-modeline-mode) + (setq mode-line-misc-info + (delq (assq 'eglot--managed-mode mode-line-misc-info) mode-line-misc-info)) + (add-to-list 'mode-line-misc-info + `(eglot--managed-mode (" [" eglot--mode-line-format "] "))))) +(add-hook 'eglot-managed-mode-hook #'doom-modeline-override-eglot-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-eglot-modeline) + + +;; +;; GitHub +;; + +(defvar doom-modeline--github-notification-number 0) +(defvar doom-modeline-before-github-fetch-notification-hook nil + "Hooks before fetching GitHub notifications. +Example: + (add-hook 'doom-modeline-before-github-fetch-notification-hook + #'auth-source-pass-enable)") +(defun doom-modeline--github-fetch-notifications () + "Fetch GitHub notifications." + (when (and doom-modeline-github + (require 'async nil t)) + (async-start + `(lambda () + ,(async-inject-variables + "\\`\\(load-path\\|auth-sources\\|doom-modeline-before-github-fetch-notification-hook\\)\\'") + (run-hooks 'doom-modeline-before-github-fetch-notification-hook) + (when (require 'ghub nil t) + (with-timeout (10) + (ignore-errors + (when-let* ((username (ghub--username ghub-default-host)) + (token (ghub--token ghub-default-host username 'ghub t))) + (ghub-get "/notifications" nil + :query '((notifications . "true")) + :username username + :auth token + :noerror t)))))) + (lambda (result) + (message "") ; suppress message + (setq doom-modeline--github-notification-number (length result)))))) + +(defvar doom-modeline--github-timer nil) +(defun doom-modeline-github-timer () + "Start/Stop the timer for GitHub fetching." + (if (timerp doom-modeline--github-timer) + (cancel-timer doom-modeline--github-timer)) + (setq doom-modeline--github-timer + (and doom-modeline-github + (run-with-idle-timer 30 + doom-modeline-github-interval + #'doom-modeline--github-fetch-notifications)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-github + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-github val) + (doom-modeline-github-timer)))) + +(doom-modeline-github-timer) + +(doom-modeline-def-segment github + "The GitHub notifications." + (when (and doom-modeline-github + (doom-modeline--active) + (not doom-modeline--limited-width-p) + (numberp doom-modeline--github-notification-number) + (> doom-modeline--github-notification-number 0)) + (concat + (doom-modeline-spc) + (propertize + (concat + (doom-modeline-icon 'faicon "github" "πŸ””" "#" + :face 'doom-modeline-notification + :v-adjust -0.0575) + (doom-modeline-vspc) + ;; GitHub API is paged, and the limit is 50 + (propertize + (if (>= doom-modeline--github-notification-number 50) + "50+" + (number-to-string doom-modeline--github-notification-number)) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'help-echo "Github Notifications +mouse-1: Show notifications +mouse-3: Fetch notifications" + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + (lambda () + "Open GitHub notifications page." + (interactive) + (run-with-idle-timer 300 nil #'doom-modeline--github-fetch-notifications) + (browse-url "https://github.com/notifications"))) + (define-key map [mode-line mouse-3] + (lambda () + "Fetching GitHub notifications." + (interactive) + (message "Fetching GitHub notifications...") + (doom-modeline--github-fetch-notifications))) + map)) + (doom-modeline-spc)))) + + +;; +;; Debug states +;; + +;; Highlight the mode-line while debugging. +(defvar-local doom-modeline--debug-cookie nil) +(defun doom-modeline--debug-visual (&rest _) + "Update the face of mode-line for debugging." + (mapc (lambda (buffer) + (with-current-buffer buffer + (setq doom-modeline--debug-cookie + (face-remap-add-relative 'mode-line 'doom-modeline-debug-visual)) + (force-mode-line-update))) + (buffer-list))) + +(defun doom-modeline--normal-visual (&rest _) + "Restore the face of mode-line." + (mapc (lambda (buffer) + (with-current-buffer buffer + (when doom-modeline--debug-cookie + (face-remap-remove-relative doom-modeline--debug-cookie) + (force-mode-line-update)))) + (buffer-list))) + +(add-hook 'dap-session-created-hook #'doom-modeline--debug-visual) +(add-hook 'dap-terminated-hook #'doom-modeline--normal-visual) + +(defun doom-modeline-debug-icon (face &rest args) + "Display debug icon with FACE and ARGS." + (doom-modeline-icon 'faicon "bug" "πŸ›" "!" :face face :v-adjust -0.0575 args)) + +(defun doom-modeline--debug-dap () + "The current `dap-mode' state." + (when (and (bound-and-true-p dap-mode) + (bound-and-true-p lsp-mode)) + (when-let ((session (dap--cur-session))) + (when (dap--session-running session) + (propertize (doom-modeline-debug-icon 'doom-modeline-info) + 'help-echo (format "DAP (%s - %s) +mouse-1: Display debug hydra +mouse-2: Display recent configurations +mouse-3: Disconnect session" + (dap--debug-session-name session) + (dap--debug-session-state session)) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'dap-hydra) + (define-key map [mode-line mouse-2] + #'dap-debug-recent) + (define-key map [mode-line mouse-3] + #'dap-disconnect) + map)))))) + +(defvar-local doom-modeline--debug-dap nil) +(defun doom-modeline-update-debug-dap (&rest _) + "Update dap debug state." + (setq doom-modeline--debug-dap (doom-modeline--debug-dap))) + +(add-hook 'dap-session-created-hook #'doom-modeline-update-debug-dap) +(add-hook 'dap-session-changed-hook #'doom-modeline-update-debug-dap) +(add-hook 'dap-terminated-hook #'doom-modeline-update-debug-dap) + +(defsubst doom-modeline--debug-edebug () + "The current `edebug' state." + (when (bound-and-true-p edebug-mode) + (propertize (doom-modeline-debug-icon 'doom-modeline-info) + 'help-echo (format "EDebug (%s) +mouse-1: Show help +mouse-2: Next +mouse-3: Stop debugging" + edebug-execution-mode) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'edebug-help) + (define-key map [mode-line mouse-2] + #'edebug-next-mode) + (define-key map [mode-line mouse-3] + #'edebug-stop) + map)))) + +(defsubst doom-modeline--debug-on-error () + "The current `debug-on-error' state." + (when debug-on-error + (propertize (doom-modeline-debug-icon 'doom-modeline-urgent) + 'help-echo "Debug on Error +mouse-1: Toggle Debug on Error" + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-error)))) + +(defsubst doom-modeline--debug-on-quit () + "The current `debug-on-quit' state." + (when debug-on-quit + (propertize (doom-modeline-debug-icon 'doom-modeline-warning) + 'help-echo "Debug on Quit +mouse-1: Toggle Debug on Quit" + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-quit)))) + +(doom-modeline-def-segment debug + "The current debug state." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p)) + (let* ((dap doom-modeline--debug-dap) + (edebug (doom-modeline--debug-edebug)) + (on-error (doom-modeline--debug-on-error)) + (on-quit (doom-modeline--debug-on-quit)) + (vsep (doom-modeline-vspc)) + (sep (and (or dap edebug on-error on-quit) (doom-modeline-spc)))) + (concat sep + (and dap (concat dap (and (or edebug on-error on-quit) vsep))) + (and edebug (concat edebug (and (or on-error on-quit) vsep))) + (and on-error (concat on-error (and on-quit vsep))) + on-quit + sep)))) + + +;; +;; PDF pages +;; + +(defvar-local doom-modeline--pdf-pages nil) +(defun doom-modeline-update-pdf-pages () + "Update PDF pages." + (setq doom-modeline--pdf-pages + (format " P%d/%d " + (or (eval `(pdf-view-current-page)) 0) + (pdf-cache-number-of-pages)))) +(add-hook 'pdf-view-change-page-hook #'doom-modeline-update-pdf-pages) + +(doom-modeline-def-segment pdf-pages + "Display PDF pages." + (propertize doom-modeline--pdf-pages + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive))) + + +;; +;; `mu4e-alert' notifications +;; + +(doom-modeline-def-segment mu4e + "Show notifications of any unread emails in `mu4e'." + (when (and doom-modeline-mu4e + (doom-modeline--active) + (not doom-modeline--limited-width-p) + (bound-and-true-p mu4e-alert-mode-line) + (numberp mu4e-alert-mode-line) + ;; don't display if the unread mails count is zero + (> mu4e-alert-mode-line 0)) + (concat + (doom-modeline-spc) + (propertize + (concat + (doom-modeline-icon 'material "email" "πŸ“§" "#" + :face 'doom-modeline-notification + :height 1.1 :v-adjust -0.2) + (doom-modeline-vspc) + (propertize + (if (> mu4e-alert-mode-line doom-modeline-number-limit) + (format "%d+" doom-modeline-number-limit) + (number-to-string mu4e-alert-mode-line)) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'mouse-face 'mode-line-highlight + 'keymap '(mode-line keymap + (mouse-1 . mu4e-alert-view-unread-mails) + (mouse-2 . mu4e-alert-view-unread-mails) + (mouse-3 . mu4e-alert-view-unread-mails)) + 'help-echo (concat (if (= mu4e-alert-mode-line 1) + "You have an unread email" + (format "You have %s unread emails" mu4e-alert-mode-line)) + "\nClick here to view " + (if (= mu4e-alert-mode-line 1) "it" "them"))) + (doom-modeline-spc)))) + +(defun doom-modeline-override-mu4e-alert-modeline (&rest _) + "Delete `mu4e-alert-mode-line' from global modeline string." + (when (featurep 'mu4e-alert) + (if (and doom-modeline-mu4e + (bound-and-true-p doom-modeline-mode)) + ;; Delete original modeline + (progn + (setq global-mode-string + (delete '(:eval mu4e-alert-mode-line) global-mode-string)) + (setq mu4e-alert-modeline-formatter #'identity)) + ;; Recover default settings + (setq mu4e-alert-modeline-formatter #'mu4e-alert-default-mode-line-formatter)))) +(advice-add #'mu4e-alert-enable-mode-line-display + :after #'doom-modeline-override-mu4e-alert-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-alert-modeline) + + +;; +;; `gnus' notifications +;; + +(defvar doom-modeline--gnus-unread-mail 0) +(defvar doom-modeline--gnus-started nil + "Used to determine if gnus has started.") +(defun doom-modeline-update-gnus-status (&rest _) + "Get the total number of unread news of gnus group." + (setq doom-modeline--gnus-unread-mail + (when (and doom-modeline-gnus + doom-modeline--gnus-started) + (let ((total-unread-news-number 0)) + (mapc (lambda (g) + (let* ((group (car g)) + (unread (eval `(gnus-group-unread ,group)))) + (when (and (not (seq-contains-p doom-modeline-gnus-excluded-groups group)) + (numberp unread) + (> unread 0)) + (setq total-unread-news-number (+ total-unread-news-number unread))))) + gnus-newsrc-alist) + total-unread-news-number)))) + +;; Update the modeline after changes have been made +(add-hook 'gnus-group-update-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-summary-update-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-group-update-group-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-after-getting-new-news-hook #'doom-modeline-update-gnus-status) + +;; Only start to listen to gnus when gnus is actually running +(defun doom-modeline-start-gnus-listener () + "Start GNUS listener." + (when (and doom-modeline-gnus + (not doom-modeline--gnus-started)) + (setq doom-modeline--gnus-started t) + ;; Scan gnus in the background if the timer is higher than 0 + (doom-modeline-update-gnus-status) + (if (> doom-modeline-gnus-timer 0) + (gnus-demon-add-handler 'gnus-demon-scan-news doom-modeline-gnus-timer doom-modeline-gnus-idle)))) +(add-hook 'gnus-started-hook #'doom-modeline-start-gnus-listener) + +;; Stop the listener if gnus isn't running +(defun doom-modeline-stop-gnus-listener () + "Stop GNUS listener." + (setq doom-modeline--gnus-started nil)) +(add-hook 'gnus-exit-gnus-hook #'doom-modeline-stop-gnus-listener) + +(doom-modeline-def-segment gnus + "Show notifications of any unread emails in `gnus'." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p) + doom-modeline-gnus + doom-modeline--gnus-started + ;; Don't display if the unread mails count is zero + (numberp doom-modeline--gnus-unread-mail) + (> doom-modeline--gnus-unread-mail 0)) + (concat + (doom-modeline-spc) + (propertize + (concat + (doom-modeline-icon 'material "email" "πŸ“§" "#" + :face 'doom-modeline-notification + :height 1.1 :v-adjust -0.2) + (doom-modeline-vspc) + (propertize + (if (> doom-modeline--gnus-unread-mail doom-modeline-number-limit) + (format "%d+" doom-modeline-number-limit) + (number-to-string doom-modeline--gnus-unread-mail)) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'mouse-face 'mode-line-highlight + 'help-echo (if (= doom-modeline--gnus-unread-mail 1) + "You have an unread email" + (format "You have %s unread emails" doom-modeline--gnus-unread-mail))) + (doom-modeline-spc)))) + + +;; +;; IRC notifications +;; + +(defun doom-modeline--shorten-irc (name) + "Wrapper for `tracking-shorten' and `erc-track-shorten-function' with NAME. + +One key difference is that when `tracking-shorten' and +`erc-track-shorten-function' returns nil we will instead return the original +value of name. This is necessary in cases where the user has stylized the name +to be an icon and we don't want to remove that so we just return the original." + (or (and (boundp 'tracking-shorten) + (car (tracking-shorten (list name)))) + (and (boundp 'erc-track-shorten-function) + (functionp erc-track-shorten-function) + (car (funcall erc-track-shorten-function (list name)))) + (and (boundp 'rcirc-short-buffer-name) + (rcirc-short-buffer-name name)) + name)) + +(defun doom-modeline--tracking-buffers (buffers) + "Logic to convert some irc BUFFERS to their font-awesome icon." + (mapconcat + (lambda (b) + (propertize + (doom-modeline--shorten-irc (funcall doom-modeline-irc-stylize b)) + 'face '(:inherit (doom-modeline-unread-number doom-modeline-notification)) + 'help-echo (format "IRC Notification: %s\nmouse-1: Switch to buffer" b) + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 + (lambda () + (interactive) + (when (buffer-live-p (get-buffer b)) + (switch-to-buffer b)))))) + buffers + (doom-modeline-vspc))) + +(defun doom-modeline--circe-p () + "Check if `circe' is in use." + (boundp 'tracking-mode-line-buffers)) + +(defun doom-modeline--erc-p () + "Check if `erc' is in use." + (boundp 'erc-modified-channels-alist)) + +(defun doom-modeline--rcirc-p () + "Check if `rcirc' is in use." + (bound-and-true-p rcirc-track-minor-mode)) + +(defun doom-modeline--get-buffers () + "Gets the buffers that have activity." + (cond + ((doom-modeline--circe-p) + tracking-buffers) + ((doom-modeline--erc-p) + (mapcar (lambda (l) + (buffer-name (car l))) + erc-modified-channels-alist)) + ((doom-modeline--rcirc-p) + (mapcar (lambda (b) + (buffer-name b)) + rcirc-activity)))) + +;; Create a modeline segment that contains all the irc tracked buffers +(doom-modeline-def-segment irc-buffers + "The list of shortened, unread irc buffers." + (when (and doom-modeline-irc + (doom-modeline--active) + (not doom-modeline--limited-width-p)) + (let* ((buffers (doom-modeline--get-buffers)) + (number (length buffers))) + (when (> number 0) + (concat + (doom-modeline-spc) + (doom-modeline--tracking-buffers buffers) + (doom-modeline-spc)))))) + +(doom-modeline-def-segment irc + "A notification icon for any unread irc buffer." + (when (and doom-modeline-irc + (doom-modeline--active) + (not doom-modeline--limited-width-p)) + (let* ((buffers (doom-modeline--get-buffers)) + (number (length buffers))) + (when (> number 0) + (concat + (doom-modeline-spc) + + (propertize (concat + (doom-modeline-icon 'material "message" "πŸ—Š" "#" + :face 'doom-modeline-notification + :height 1.0 :v-adjust -0.225) + (doom-modeline-vspc) + ;; Display the number of unread buffers + (propertize (number-to-string number) + 'face '(:inherit + (doom-modeline-unread-number + doom-modeline-notification)))) + 'help-echo (format "IRC Notifications: %s\n%s" + (mapconcat + (lambda (b) (funcall doom-modeline-irc-stylize b)) + buffers + ", ") + (cond + ((doom-modeline--circe-p) + "mouse-1: Switch to previous unread buffer +mouse-3: Switch to next unread buffer") + ((doom-modeline--erc-p) + "mouse-1: Switch to buffer +mouse-3: Switch to next unread buffer") + ((doom-modeline--rcirc-p) + "mouse-1: Switch to server buffer +mouse-3: Switch to next unread buffer"))) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (cond + ((doom-modeline--circe-p) + (define-key map [mode-line mouse-1] + #'tracking-previous-buffer) + (define-key map [mode-line mouse-3] + #'tracking-next-buffer)) + ((doom-modeline--erc-p) + (define-key map [mode-line mouse-1] + #'erc-switch-to-buffer) + (define-key map [mode-line mouse-3] + #'erc-track-switch-buffer)) + ((doom-modeline--rcirc-p) + (define-key map [mode-line mouse-1] + #'rcirc-switch-to-server-buffer) + (define-key map [mode-line mouse-3] + #'rcirc-next-active-buffer))) + map)) + + ;; Display the unread irc buffers as well + (when doom-modeline-irc-buffers + (concat (doom-modeline-spc) + (doom-modeline--tracking-buffers buffers))) + + (doom-modeline-spc)))))) + +(defun doom-modeline-override-rcirc-modeline () + "Override default `rcirc' mode-line." + (if (bound-and-true-p doom-modeline-mode) + (setq global-mode-string + (delq 'rcirc-activity-string global-mode-string)) + (when (and rcirc-track-minor-mode + (not (memq 'rcirc-activity-string global-mode-string))) + (setq global-mode-string + (append global-mode-string '(rcirc-activity-string)))))) +(add-hook 'rcirc-track-minor-mode-hook #'doom-modeline-override-rcirc-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-rcirc-modeline) + + +;; +;; Battery status +;; + +(defvar doom-modeline--battery-status nil) +(defun doom-modeline-update-battery-status () + "Update battery status." + (setq doom-modeline--battery-status + (when (bound-and-true-p display-battery-mode) + (let* ((data (and battery-status-function + (functionp battery-status-function) + (funcall battery-status-function))) + (charging? (string-equal "AC" (cdr (assoc ?L data)))) + (percentage (car (read-from-string (or (cdr (assq ?p data)) "ERR")))) + (valid-percentage? (and (numberp percentage) + (>= percentage 0) + (<= percentage battery-mode-line-limit))) + (face (if valid-percentage? + (cond (charging? 'doom-modeline-battery-charging) + ((< percentage battery-load-critical) 'doom-modeline-battery-critical) + ((< percentage 25) 'doom-modeline-battery-warning) + ((< percentage 95) 'doom-modeline-battery-normal) + (t 'doom-modeline-battery-full)) + 'doom-modeline-battery-error)) + (icon (if valid-percentage? + (cond (charging? + (doom-modeline-icon 'alltheicon "battery-charging" "πŸ”‹" "+" + :face face :height 1.4 :v-adjust -0.1)) + ((> percentage 95) + (doom-modeline-icon 'faicon "battery-full" "πŸ”‹" "-" + :face face :v-adjust -0.0575)) + ((> percentage 70) + (doom-modeline-icon 'faicon "battery-three-quarters" "πŸ”‹" "-" + :face face :v-adjust -0.0575)) + ((> percentage 40) + (doom-modeline-icon 'faicon "battery-half" "πŸ”‹" "-" + :face face :v-adjust -0.0575)) + ((> percentage battery-load-critical) + (doom-modeline-icon 'faicon "battery-quarter" "πŸ”‹" "-" + :face face :v-adjust -0.0575)) + (t (doom-modeline-icon 'faicon "battery-empty" "πŸ”‹" "!" + :face face :v-adjust -0.0575))) + (doom-modeline-icon 'faicon "battery-empty" "⚠" "N/A" + :face face :v-adjust -0.0575))) + (text (if valid-percentage? (format "%d%%%%" percentage) "")) + (help-echo (if (and battery-echo-area-format data valid-percentage?) + (battery-format battery-echo-area-format data) + "Battery status not available"))) + (cons (propertize icon 'help-echo help-echo) + (propertize text 'face face 'help-echo help-echo)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-battery-status)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-battery-status)))))) + +(doom-modeline-def-segment battery + "Display battery status." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p) + (bound-and-true-p display-battery-mode)) + (concat (doom-modeline-spc) + (concat + (car doom-modeline--battery-status) + (doom-modeline-vspc) + (cdr doom-modeline--battery-status)) + (doom-modeline-spc)))) + +(defun doom-modeline-override-battery-modeline () + "Override default battery mode-line." + (if (bound-and-true-p doom-modeline-mode) + (progn + (advice-add #'battery-update :override #'doom-modeline-update-battery-status) + (setq global-mode-string + (delq 'battery-mode-line-string global-mode-string)) + (and (bound-and-true-p display-battery-mode) (battery-update))) + (progn + (advice-remove #'battery-update #'doom-modeline-update-battery-status) + (when (and display-battery-mode battery-status-function battery-mode-line-format + (not (memq 'battery-mode-line-string global-mode-string))) + (setq global-mode-string + (append global-mode-string '(battery-mode-line-string))))))) +(add-hook 'display-battery-mode-hook #'doom-modeline-override-battery-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-battery-modeline) + + +;; +;; Package information +;; + +(doom-modeline-def-segment package + "Show package information via `paradox'." + (let ((active (doom-modeline--active))) + (concat + (let ((front (format-mode-line 'mode-line-front-space))) + (if active + front + (propertize front 'face 'mode-line-inactive))) + + (when (and doom-modeline-icon doom-modeline-major-mode-icon) + (concat + (doom-modeline-spc) + (doom-modeline-icon 'faicon "archive" nil nil + :face (if active + (if doom-modeline-major-mode-color-icon + 'all-the-icons-silver + 'mode-line) + 'mode-line-inactive) + :height 1.0 + :v-adjust -0.0575))) + (let ((info (format-mode-line 'mode-line-buffer-identification))) + (if active + info + (propertize info 'face 'mode-line-inactive)))))) + + +;; +;; Helm +;; + +(defvar doom-modeline--helm-buffer-ids + '(("*helm*" . "HELM") + ("*helm M-x*" . "HELM M-x") + ("*swiper*" . "SWIPER") + ("*Projectile Perspectives*" . "HELM Projectile Perspectives") + ("*Projectile Layouts*" . "HELM Projectile Layouts") + ("*helm-ag*" . (lambda () + (format "HELM Ag: Using %s" + (car (split-string helm-ag-base-command)))))) + "Alist of custom helm buffer names to use. +The cdr can also be a function that returns a name to use.") + +(doom-modeline-def-segment helm-buffer-id + "Helm session identifier." + (when (bound-and-true-p helm-alive-p) + (let ((active (doom-modeline--active))) + (concat + (doom-modeline-spc) + (when doom-modeline-icon + (concat + (doom-modeline-icon 'fileicon "elisp" nil nil + :face (if active + (if doom-modeline-major-mode-color-icon + 'all-the-icons-blue + 'mode-line) + 'mode-line-inactive) + :height 1.0 + :v-adjust -0.15) + (doom-modeline-spc))) + (propertize + (let ((custom (cdr (assoc (buffer-name) doom-modeline--helm-buffer-ids))) + (case-fold-search t) + (name (replace-regexp-in-string "-" " " (buffer-name)))) + (cond ((stringp custom) custom) + ((functionp custom) (funcall custom)) + (t + (string-match "\\*helm:? \\(mode \\)?\\([^\\*]+\\)\\*" name) + (concat "HELM " (capitalize (match-string 2 name)))))) + 'face (if active' doom-modeline-buffer-file 'mode-line-inactive)) + (doom-modeline-spc))))) + +(doom-modeline-def-segment helm-number + "Number of helm candidates." + (when (bound-and-true-p helm-alive-p) + (let ((active (doom-modeline--active))) + (concat + (propertize (format " %d/%d" + (helm-candidate-number-at-point) + (helm-get-candidate-number t)) + 'face (if active 'doom-modeline-buffer-path 'mode-line-inactive)) + (propertize (format " (%d total) " (helm-get-candidate-number)) + 'face (if active 'doom-modeline-info 'mode-line-inactive)))))) + +(doom-modeline-def-segment helm-help + "Helm keybindings help." + (when (bound-and-true-p helm-alive-p) + (let ((active (doom-modeline--active))) + (-interleave + (mapcar (lambda (s) + (propertize (substitute-command-keys s) + 'face (if active + 'doom-modeline-buffer-file + 'mode-line-inactive))) + '("\\\\[helm-help]" + "\\\\[helm-select-action]" + "\\\\[helm-maybe-exit-minibuffer]/F1/F2...")) + (mapcar (lambda (s) + (propertize s 'face (if active 'mode-line 'mode-line-inactive))) + '("(help) " "(actions) " "(action) ")))))) + +(doom-modeline-def-segment helm-prefix-argument + "Helm prefix argument." + (when (and (bound-and-true-p helm-alive-p) + helm--mode-line-display-prefarg) + (let ((arg (prefix-numeric-value (or prefix-arg current-prefix-arg)))) + (unless (= arg 1) + (propertize (format "C-u %s" arg) + 'face (if (doom-modeline--active) + 'doom-modeline-info + 'mode-line-inactive)))))) + +(defvar doom-modeline--helm-current-source nil + "The currently active helm source.") +(doom-modeline-def-segment helm-follow + "Helm follow indicator." + (when (and (bound-and-true-p helm-alive-p) + doom-modeline--helm-current-source + (eq 1 (cdr (assq 'follow doom-modeline--helm-current-source)))) + (propertize "HF" 'face (if (doom-modeline--active) + 'mode-line + 'mode-line-inactive)))) + +;; +;; Git timemachine +;; + +(doom-modeline-def-segment git-timemachine + (let ((active (doom-modeline--active))) + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (propertize "*%b*" 'face (if active + 'doom-modeline-buffer-timemachine + 'mode-line-inactive))))) + +;; +;; Markdown/Org preview +;; + +(doom-modeline-def-segment grip + (when (bound-and-true-p grip-mode) + (concat + (doom-modeline-spc) + (let ((face (if (doom-modeline--active) + (if grip--process + (pcase (process-status grip--process) + ('run 'doom-modeline-buffer-path) + ('exit 'doom-modeline-warning) + (_ 'doom-modeline-urgent)) + 'doom-modeline-urgent) + 'mode-line-inactive))) + (propertize (doom-modeline-icon 'material "pageview" "πŸ—" "@" + :face (if doom-modeline-icon + `(:inherit ,face :weight normal) + face) + :height 1.2 :v-adjust -0.2) + 'help-echo (format "Preview on %s +mouse-1: Preview in browser +mouse-2: Stop preview +mouse-3: Restart preview" + (grip--preview-url)) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'grip-browse-preview) + (define-key map [mode-line mouse-2] + #'grip-stop-preview) + (define-key map [mode-line mouse-3] + #'grip-restart-preview) + map))) + (doom-modeline-spc)))) + +;; +;; Follow mode +;; + +(doom-modeline-def-segment follow + (when (bound-and-true-p follow-mode) + (let* ((windows (follow-all-followers)) + (nwindows (length windows)) + (nfollowing (- (length (memq (selected-window) windows)) + 1))) + (concat + (doom-modeline-spc) + (propertize (format "Follow %d/%d" (- nwindows nfollowing) nwindows) + 'face 'doom-modeline-buffer-minor-mode))))) + +(provide 'doom-modeline-segments) + +;;; doom-modeline-segments.el ends here diff --git a/code/elpa/doom-modeline-20220412.853/doom-modeline.el b/code/elpa/doom-modeline-20220412.853/doom-modeline.el new file mode 100644 index 0000000..b48bda5 --- /dev/null +++ b/code/elpa/doom-modeline-20220412.853/doom-modeline.el @@ -0,0 +1,311 @@ +;;; doom-modeline.el --- A minimal and modern mode-line -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2020 Vincent Zhang + +;; Author: Vincent Zhang +;; Homepage: https://github.com/seagle0128/doom-modeline +;; Version: 3.3.0 +;; Package-Requires: ((emacs "25.1") (all-the-icons "2.2.0") (shrink-path "0.2.0") (dash "2.11.0")) +;; Keywords: faces mode-line + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . +;; + +;;; Commentary: +;; +;; This package offers a fancy and fast mode-line inspired by minimalism design. +;; +;; It's integrated into Doom Emacs (https://github.com/hlissner/doom-emacs) and +;; Centaur Emacs (https://github.com/seagle0128/.emacs.d). +;; +;; The doom-modeline offers: +;; - A match count panel (for anzu, iedit, multiple-cursors, symbol-overlay, +;; evil-search and evil-substitute) +;; - An indicator for recording a macro +;; - Current environment version (e.g. python, ruby, go, etc.) in the major-mode +;; - A customizable mode-line height (see doom-modeline-height) +;; - A minor modes segment which is compatible with minions +;; - An error/warning count segment for flymake/flycheck +;; - A workspace number segment for eyebrowse +;; - A perspective name segment for persp-mode +;; - A window number segment for winum and window-numbering +;; - An indicator for modal editing state, including evil, overwrite, god, ryo +;; and xah-fly-keys, etc. +;; - An indicator for battery status +;; - An indicator for current input method +;; - An indicator for debug state +;; - An indicator for remote host +;; - An indicator for LSP state with lsp-mode or eglot +;; - An indicator for github notifications +;; - An indicator for unread emails with mu4e-alert +;; - An indicator for unread emails with gnus (basically builtin) +;; - An indicator for irc notifications with circe, rcirc or erc. +;; - An indicator for buffer position which is compatible with nyan-mode or poke-line +;; - An indicator for party parrot +;; - An indicator for PDF page number with pdf-tools +;; - An indicator for markdown/org previews with grip +;; - Truncated file name, file icon, buffer state and project name in buffer +;; information segment, which is compatible with project, find-file-in-project +;; and projectile +;; - New mode-line for Info-mode buffers +;; - New package mode-line for paradox +;; - New mode-line for helm buffers +;; - New mode-line for git-timemachine buffers +;; +;; Installation: +;; From melpa, `M-x package-install RET doom-modeline RET`. +;; In `init.el`, +;; (require 'doom-modeline) +;; (doom-modeline-mode 1) +;; or +;; (use-package doom-modeline +;; :ensure t +;; :hook (after-init . doom-modeline-mode)) +;; + +;;; Code: + +(require 'doom-modeline-core) +(require 'doom-modeline-segments) + + +;; +;; Mode lines +;; + +(doom-modeline-def-modeline 'main + '(bar workspace-name window-number modals matches follow buffer-info remote-host buffer-position word-count parrot selection-info) + '(objed-state misc-info persp-name battery grip irc mu4e gnus github debug repl lsp minor-modes input-method indent-info buffer-encoding major-mode process vcs checker)) + +(doom-modeline-def-modeline 'minimal + '(bar matches buffer-info-simple) + '(media-info major-mode)) + +(doom-modeline-def-modeline 'special + '(bar window-number modals matches buffer-info buffer-position word-count parrot selection-info) + '(objed-state misc-info battery irc-buffers debug minor-modes input-method indent-info buffer-encoding major-mode process)) + +(doom-modeline-def-modeline 'project + '(bar window-number modals buffer-default-directory) + '(misc-info battery irc mu4e gnus github debug minor-modes input-method major-mode process)) + +(doom-modeline-def-modeline 'dashboard + '(bar window-number buffer-default-directory-simple) + '(misc-info battery irc mu4e gnus github debug minor-modes input-method major-mode process)) + +(doom-modeline-def-modeline 'vcs + '(bar window-number modals matches buffer-info buffer-position parrot selection-info) + '(misc-info battery irc mu4e gnus github debug minor-modes buffer-encoding major-mode process)) + +(doom-modeline-def-modeline 'package + '(bar window-number package) + '(misc-info major-mode process)) + +(doom-modeline-def-modeline 'info + '(bar window-number buffer-info info-nodes buffer-position parrot selection-info) + '(misc-info buffer-encoding major-mode)) + +(doom-modeline-def-modeline 'media + '(bar window-number buffer-size buffer-info) + '(misc-info media-info major-mode process vcs)) + +(doom-modeline-def-modeline 'message + '(bar window-number modals matches buffer-info-simple buffer-position word-count parrot selection-info) + '(objed-state misc-info battery debug minor-modes input-method indent-info buffer-encoding major-mode)) + +(doom-modeline-def-modeline 'pdf + '(bar window-number matches buffer-info pdf-pages) + '(misc-info major-mode process vcs)) + +(doom-modeline-def-modeline 'org-src + '(bar window-number modals matches buffer-info-simple buffer-position word-count parrot selection-info) + '(objed-state misc-info debug lsp minor-modes input-method indent-info buffer-encoding major-mode process checker)) + +(doom-modeline-def-modeline 'helm + '(bar helm-buffer-id helm-number helm-follow helm-prefix-argument) + '(helm-help)) + +(doom-modeline-def-modeline 'timemachine + '(bar window-number modals matches git-timemachine buffer-position word-count parrot selection-info) + '(misc-info minor-modes indent-info buffer-encoding major-mode)) + + +;; +;; Interfaces +;; + +;;;###autoload +(defun doom-modeline-init () + "Initialize doom mode-line." + (doom-modeline-mode 1)) +(make-obsolete 'doom-modeline-init 'doom-modeline-mode "1.6.0") + +;;;###autoload +(defun doom-modeline-set-main-modeline (&optional default) + "Set main mode-line. +If DEFAULT is non-nil, set the default mode-line for all buffers." + (doom-modeline-set-modeline 'main default)) + +;;;###autoload +(defun doom-modeline-set-minimal-modeline () + "Set minimal mode-line." + (doom-modeline-set-modeline 'minimal)) + +;;;###autoload +(defun doom-modeline-set-special-modeline () + "Set special mode-line." + (doom-modeline-set-modeline 'special)) + +;;;###autoload +(defun doom-modeline-set-project-modeline () + "Set project mode-line." + (doom-modeline-set-modeline 'project)) + +;;;###autoload +(defun doom-modeline-set-dashboard-modeline () + "Set dashboard mode-line." + (doom-modeline-set-modeline 'dashboard)) + +;;;###autoload +(defun doom-modeline-set-vcs-modeline () + "Set vcs mode-line." + (doom-modeline-set-modeline 'vcs)) + +;;;###autoload +(defun doom-modeline-set-info-modeline () + "Set Info mode-line." + (doom-modeline-set-modeline 'info)) + +;;;###autoload +(defun doom-modeline-set-package-modeline () + "Set package mode-line." + (doom-modeline-set-modeline 'package)) + +;;;###autoload +(defun doom-modeline-set-media-modeline () + "Set media mode-line." + (doom-modeline-set-modeline 'media)) + +;;;###autoload +(defun doom-modeline-set-message-modeline () + "Set message mode-line." + (doom-modeline-set-modeline 'message)) + +;;;###autoload +(defun doom-modeline-set-pdf-modeline () + "Set pdf mode-line." + (doom-modeline-set-modeline 'pdf)) + +;;;###autoload +(defun doom-modeline-set-org-src-modeline () + "Set org-src mode-line." + (doom-modeline-set-modeline 'org-src)) + +;;;###autoload +(defun doom-modeline-set-helm-modeline (&rest _) ; To advice helm + "Set helm mode-line." + (doom-modeline-set-modeline 'helm)) + +;;;###autoload +(defun doom-modeline-set-timemachine-modeline () + "Set timemachine mode-line." + (doom-modeline-set-modeline 'timemachine)) + + +;; +;; Minor mode +;; + +(defvar doom-modeline-mode-map (make-sparse-keymap)) + +;; Suppress warnings +(defvar 2C-mode-line-format) +(declare-function helm-display-mode-line "ext:helm-core") + +;;;###autoload +(define-minor-mode doom-modeline-mode + "Toggle doom-modeline on or off." + :group 'doom-modeline + :global t + :lighter nil + :keymap doom-modeline-mode-map + (if doom-modeline-mode + (progn + (doom-modeline-refresh-bars) ; Create bars + (doom-modeline-set-main-modeline t) ; Set default mode-line + + ;; Apply to all existing buffers. + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-set-main-modeline))) + + ;; For two-column editing + (setq 2C-mode-line-format (doom-modeline 'special)) + + ;; Add hooks + (add-hook 'Info-mode-hook #'doom-modeline-set-info-modeline) + (add-hook 'dired-mode-hook #'doom-modeline-set-project-modeline) + (add-hook 'dashboard-mode-hook #'doom-modeline-set-dashboard-modeline) + (add-hook 'image-mode-hook #'doom-modeline-set-media-modeline) + (add-hook 'message-mode-hook #'doom-modeline-set-message-modeline) + (add-hook 'git-commit-mode-hook #'doom-modeline-set-message-modeline) + (add-hook 'magit-mode-hook #'doom-modeline-set-vcs-modeline) + (add-hook 'circe-mode-hook #'doom-modeline-set-special-modeline) + (add-hook 'erc-mode-hook #'doom-modeline-set-special-modeline) + (add-hook 'rcirc-mode-hook #'doom-modeline-set-special-modeline) + (add-hook 'pdf-view-mode-hook #'doom-modeline-set-pdf-modeline) + (add-hook 'org-src-mode-hook #'doom-modeline-set-org-src-modeline) + (add-hook 'git-timemachine-mode-hook #'doom-modeline-set-timemachine-modeline) + (add-hook 'paradox-menu-mode-hook #'doom-modeline-set-package-modeline) + (add-hook 'xwidget-webkit-mode-hook #'doom-modeline-set-minimal-modeline) + + ;; Add advices + (advice-add #'helm-display-mode-line :after #'doom-modeline-set-helm-modeline)) + (progn + ;; Restore mode-line + (let ((original-format (doom-modeline--original-value 'mode-line-format))) + (setq-default mode-line-format original-format) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (setq mode-line-format original-format)))) + + ;; For two-column editing + (setq 2C-mode-line-format (doom-modeline--original-value '2C-mode-line-format)) + + ;; Remove hooks + (remove-hook 'Info-mode-hook #'doom-modeline-set-info-modeline) + (remove-hook 'dired-mode-hook #'doom-modeline-set-project-modeline) + (remove-hook 'dashboard-mode-hook #'doom-modeline-set-dashboard-modeline) + (remove-hook 'image-mode-hook #'doom-modeline-set-media-modeline) + (remove-hook 'message-mode-hook #'doom-modeline-set-message-modeline) + (remove-hook 'git-commit-mode-hook #'doom-modeline-set-message-modeline) + (remove-hook 'magit-mode-hook #'doom-modeline-set-vcs-modeline) + (remove-hook 'circe-mode-hook #'doom-modeline-set-special-modeline) + (remove-hook 'erc-mode-hook #'doom-modeline-set-special-modeline) + (remove-hook 'rcirc-mode-hook #'doom-modeline-set-special-modeline) + (remove-hook 'pdf-view-mode-hook #'doom-modeline-set-pdf-modeline) + (remove-hook 'org-src-mode-hook #'doom-modeline-set-org-src-modeline) + (remove-hook 'git-timemachine-mode-hook #'doom-modeline-set-timemachine-modeline) + (remove-hook 'paradox-menu-mode-hook #'doom-modeline-set-package-modeline) + (remove-hook 'xwidget-webkit-mode-hook #'doom-modeline-set-minimal-modeline) + + ;; Remove advices + (advice-remove #'helm-display-mode-line #'doom-modeline-set-helm-modeline)))) + +(provide 'doom-modeline) + +;;; doom-modeline.el ends here diff --git a/code/elpa/shrink-path-20190208.1335/shrink-path-autoloads.el b/code/elpa/shrink-path-20190208.1335/shrink-path-autoloads.el new file mode 100644 index 0000000..776b017 --- /dev/null +++ b/code/elpa/shrink-path-20190208.1335/shrink-path-autoloads.el @@ -0,0 +1,22 @@ +;;; shrink-path-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "shrink-path" "shrink-path.el" (0 0 0 0)) +;;; Generated autoloads from shrink-path.el + +(register-definition-prefixes "shrink-path" '("shrink-path-")) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; shrink-path-autoloads.el ends here diff --git a/code/elpa/shrink-path-20190208.1335/shrink-path-pkg.el b/code/elpa/shrink-path-20190208.1335/shrink-path-pkg.el new file mode 100644 index 0000000..c568bd0 --- /dev/null +++ b/code/elpa/shrink-path-20190208.1335/shrink-path-pkg.el @@ -0,0 +1,2 @@ +;;; Generated package description from shrink-path.el -*- no-byte-compile: t -*- +(define-package "shrink-path" "20190208.1335" "fish-style path" '((emacs "24") (s "1.6.1") (dash "1.8.0") (f "0.10.0")) :commit "c14882c8599aec79a6e8ef2d06454254bb3e1e41" :authors '(("Benjamin Andresen")) :maintainer '("Benjamin Andresen") :url "https://gitlab.com/bennya/shrink-path.el") diff --git a/code/elpa/shrink-path-20190208.1335/shrink-path.el b/code/elpa/shrink-path-20190208.1335/shrink-path.el new file mode 100644 index 0000000..154bfd6 --- /dev/null +++ b/code/elpa/shrink-path-20190208.1335/shrink-path.el @@ -0,0 +1,150 @@ +;;; shrink-path.el --- fish-style path -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 Benjamin Andresen + +;; Author: Benjamin Andresen +;; Version: 0.3.1 +;; Package-Version: 20190208.1335 +;; Package-Commit: c14882c8599aec79a6e8ef2d06454254bb3e1e41 +;; URL: https://gitlab.com/bennya/shrink-path.el +;; Package-Requires: ((emacs "24") (s "1.6.1") (dash "1.8.0") (f "0.10.0")) + +;; This file is NOT part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file LICENSE. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Provides functions that offer fish shell[1] path truncation. +;; Directory /usr/share/emacs/site-lisp => /u/s/e/site-lisp +;; +;; Also includes utility functions that make integration in eshell or the +;; modeline easier. +;; +;; [1] https://fishshell.com/ + + +;;; Code: +(require 'dash) +(require 's) +(require 'f) +(require 'rx) + +(defun shrink-path--truncate (str) + "Return STR's first character or first two characters if hidden." + (substring str 0 (if (s-starts-with? "." str) 2 1))) + +(defun shrink-path--dirs-internal (full-path &optional truncate-all) + "Return fish-style truncated string based on FULL-PATH. +Optional parameter TRUNCATE-ALL will cause the function to truncate the last +directory too." + (let* ((home (expand-file-name "~")) + (path (replace-regexp-in-string + (s-concat "^" home) "~" full-path)) + (split (s-split "/" path 'omit-nulls)) + (split-len (length split)) + shrunk) + (->> split + (--map-indexed (if (= it-index (1- split-len)) + (if truncate-all (shrink-path--truncate it) it) + (shrink-path--truncate it))) + (s-join "/") + (setq shrunk)) + (s-concat (unless (s-matches? (rx bos (or "~" "/")) shrunk) "/") + shrunk + (unless (s-ends-with? "/" shrunk) "/")))) + + +(defun shrink-path-dirs (&optional path truncate-tail) + "Given PATH return fish-styled shrunken down path. +TRUNCATE-TAIL will cause the function to truncate the last directory too." + (let* ((path (or path default-directory)) + (path (f-full path))) + (cond + ((s-equals? (f-short path) "/") "/") + ((s-matches? (rx bos (or "~" "/") eos) "~/")) + (t (shrink-path--dirs-internal path truncate-tail))))) + +(defun shrink-path-expand (str &optional absolute-p) + "Return expanded path from STR if found or list of matches on multiple. +The path referred to by STR has to exist for this to work. +If ABSOLUTE-P is t the returned path will be absolute." + (let* ((str-split (s-split "/" str 'omit-nulls)) + (head (car str-split))) + (if (= (length str-split) 1) + (s-concat "/" str-split) + (--> (-drop 1 str-split) ;; drop head + (-map (lambda (e) (s-concat e "*")) it) + (-drop-last 1 it) ;; drop tail as it may not exist + (s-join "/" it) + (s-concat (if (s-equals? head "~") "~/" head) it) + (f-glob it) + (-map (lambda (e) (s-concat e "/" (-last-item str-split))) it) + (if absolute-p (-map #'f-full it) (-map #'f-abbrev it)) + (if (= (length it) 1) (car it) it))))) + +(defun shrink-path-prompt (&optional pwd) + "Return cons of BASE and DIR for PWD. +If PWD isn't provided will default to `default-directory'." + (let* ((pwd (or pwd default-directory)) + (shrunk (shrink-path-dirs pwd)) + (split (--> shrunk (s-split "/" it 'omit-nulls))) + base dir) + (setq dir (or (-last-item split) "/")) + (setq base (if (s-equals? dir "/") "" + (s-chop-suffix (s-concat dir "/") shrunk))) + (cons base dir))) + +(defun shrink-path-file (file &optional truncate-tail) + "Return FILE's shrunk down path and filename. +TRUNCATE-TAIL controls if the last directory should also be shortened." + (let ((filename (f-filename file)) + (dirname (f-dirname file))) + (s-concat (shrink-path-dirs dirname truncate-tail) filename))) + +(defun shrink-path-file-expand (str &optional exists-p absolute-p) + "Return STR's expanded filename. +The path referred to by STR has to exist for this to work. +If EXISTS-P is t the filename also has to exist. +If ABSOLUTE-P is t the returned path will be absolute." + (let ((expanded (shrink-path-expand str absolute-p))) + (if (and expanded exists-p) + (if (f-exists? expanded) expanded) + expanded))) + +(defun shrink-path-file-mixed (shrink-path rel-path filename) + "Returns list of mixed truncated file name locations. + +Consists of SHRINK-PATH's parent, SHRINK-PATH basename, relative REL-PATH and +FILENAME. +For use in modeline or prompts, etc." + (let ((shrunk-dirs (shrink-path-prompt shrink-path)) + sp-parent sp-rel rel-rel nd-file) + + (when (f-descendant-of? filename shrink-path) + (when shrunk-dirs + (setq sp-parent (car shrunk-dirs) + sp-rel (cdr shrunk-dirs))) + (setq rel-rel (if (or (f-same? rel-path shrink-path) + (s-equals? (f-relative rel-path shrink-path) ".")) + nil + (f-relative rel-path shrink-path))) + (setq nd-file (file-name-nondirectory filename)) + + (list sp-parent sp-rel rel-rel nd-file)))) + +(provide 'shrink-path) +;;; shrink-path.el ends here diff --git a/common/fonts/all-the-icons.ttf b/common/fonts/all-the-icons.ttf new file mode 100644 index 0000000..634d48e Binary files /dev/null and b/common/fonts/all-the-icons.ttf differ diff --git a/common/fonts/file-icons.ttf b/common/fonts/file-icons.ttf new file mode 100644 index 0000000..dd42225 Binary files /dev/null and b/common/fonts/file-icons.ttf differ diff --git a/common/fonts/fontawesome.ttf b/common/fonts/fontawesome.ttf new file mode 100644 index 0000000..f221e50 Binary files /dev/null and b/common/fonts/fontawesome.ttf differ diff --git a/common/fonts/material-design-icons.ttf b/common/fonts/material-design-icons.ttf new file mode 100644 index 0000000..7015564 Binary files /dev/null and b/common/fonts/material-design-icons.ttf differ diff --git a/common/fonts/octicons.ttf b/common/fonts/octicons.ttf new file mode 100644 index 0000000..6f3edd6 Binary files /dev/null and b/common/fonts/octicons.ttf differ diff --git a/common/fonts/weathericons.ttf b/common/fonts/weathericons.ttf new file mode 100644 index 0000000..948f0a5 Binary files /dev/null and b/common/fonts/weathericons.ttf differ diff --git a/org/elpa/doom-modeline-20220412.853/doom-modeline-autoloads.el b/org/elpa/doom-modeline-20220412.853/doom-modeline-autoloads.el new file mode 100644 index 0000000..481641c --- /dev/null +++ b/org/elpa/doom-modeline-20220412.853/doom-modeline-autoloads.el @@ -0,0 +1,135 @@ +;;; doom-modeline-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "doom-modeline" "doom-modeline.el" (0 0 0 0)) +;;; Generated autoloads from doom-modeline.el + +(autoload 'doom-modeline-init "doom-modeline" "\ +Initialize doom mode-line." nil nil) + +(autoload 'doom-modeline-set-main-modeline "doom-modeline" "\ +Set main mode-line. +If DEFAULT is non-nil, set the default mode-line for all buffers. + +\(fn &optional DEFAULT)" nil nil) + +(autoload 'doom-modeline-set-minimal-modeline "doom-modeline" "\ +Set minimal mode-line." nil nil) + +(autoload 'doom-modeline-set-special-modeline "doom-modeline" "\ +Set special mode-line." nil nil) + +(autoload 'doom-modeline-set-project-modeline "doom-modeline" "\ +Set project mode-line." nil nil) + +(autoload 'doom-modeline-set-dashboard-modeline "doom-modeline" "\ +Set dashboard mode-line." nil nil) + +(autoload 'doom-modeline-set-vcs-modeline "doom-modeline" "\ +Set vcs mode-line." nil nil) + +(autoload 'doom-modeline-set-info-modeline "doom-modeline" "\ +Set Info mode-line." nil nil) + +(autoload 'doom-modeline-set-package-modeline "doom-modeline" "\ +Set package mode-line." nil nil) + +(autoload 'doom-modeline-set-media-modeline "doom-modeline" "\ +Set media mode-line." nil nil) + +(autoload 'doom-modeline-set-message-modeline "doom-modeline" "\ +Set message mode-line." nil nil) + +(autoload 'doom-modeline-set-pdf-modeline "doom-modeline" "\ +Set pdf mode-line." nil nil) + +(autoload 'doom-modeline-set-org-src-modeline "doom-modeline" "\ +Set org-src mode-line." nil nil) + +(autoload 'doom-modeline-set-helm-modeline "doom-modeline" "\ +Set helm mode-line. + +\(fn &rest _)" nil nil) + +(autoload 'doom-modeline-set-timemachine-modeline "doom-modeline" "\ +Set timemachine mode-line." nil nil) + +(defvar doom-modeline-mode nil "\ +Non-nil if Doom-Modeline mode is enabled. +See the `doom-modeline-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `doom-modeline-mode'.") + +(custom-autoload 'doom-modeline-mode "doom-modeline" nil) + +(autoload 'doom-modeline-mode "doom-modeline" "\ +Toggle doom-modeline on or off. + +This is a minor mode. If called interactively, toggle the +`Doom-Modeline mode' mode. If the prefix argument is positive, +enable the mode, and if it is zero or negative, disable the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `(default-value \\='doom-modeline-mode)'. + +The mode's hook is called both when the mode is enabled and when +it is disabled. + +\(fn &optional ARG)" t nil) + +(register-definition-prefixes "doom-modeline" '("doom-modeline-mode-map")) + +;;;*** + +;;;### (autoloads nil "doom-modeline-core" "doom-modeline-core.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from doom-modeline-core.el + +(register-definition-prefixes "doom-modeline-core" '("doom-modeline")) + +;;;*** + +;;;### (autoloads nil "doom-modeline-env" "doom-modeline-env.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from doom-modeline-env.el + (autoload 'doom-modeline-env-setup-python "doom-modeline-env") + (autoload 'doom-modeline-env-setup-ruby "doom-modeline-env") + (autoload 'doom-modeline-env-setup-perl "doom-modeline-env") + (autoload 'doom-modeline-env-setup-go "doom-modeline-env") + (autoload 'doom-modeline-env-setup-elixir "doom-modeline-env") + (autoload 'doom-modeline-env-setup-rust "doom-modeline-env") + +(register-definition-prefixes "doom-modeline-env" '("doom-modeline-")) + +;;;*** + +;;;### (autoloads nil "doom-modeline-segments" "doom-modeline-segments.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from doom-modeline-segments.el + +(register-definition-prefixes "doom-modeline-segments" '("doom-modeline-")) + +;;;*** + +;;;### (autoloads nil nil ("doom-modeline-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; doom-modeline-autoloads.el ends here diff --git a/org/elpa/doom-modeline-20220412.853/doom-modeline-core.el b/org/elpa/doom-modeline-20220412.853/doom-modeline-core.el new file mode 100644 index 0000000..86360f1 --- /dev/null +++ b/org/elpa/doom-modeline-20220412.853/doom-modeline-core.el @@ -0,0 +1,1394 @@ +;;; doom-modeline-core.el --- The core libraries for doom-modeline -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2020 Vincent Zhang + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . +;; + +;;; Commentary: +;; +;; The core libraries for doom-modeline. +;; + +;;; Code: + +(require 'cl-lib) +(require 'subr-x) +(require 'dash) +(require 'all-the-icons) +(require 'shrink-path) + + +;; +;; Compatibility +;; + +(eval-and-compile + (when (< emacs-major-version 26) + ;; Define `if-let*' and `when-let*' variants for 25 users. + (unless (fboundp 'if-let*) (defalias 'if-let* #'if-let)) + (unless (fboundp 'when-let*) (defalias 'when-let* #'when-let)))) + +;; Don’t compact font caches during GC. +(when (eq system-type 'windows-nt) + (setq inhibit-compacting-font-caches t)) + +;;`file-local-name' is introduced in 25.2.2. +(unless (fboundp 'file-local-name) + (defun file-local-name (file) + "Return the local name component of FILE. +It returns a file name which can be used directly as argument of +`process-file', `start-file-process', or `shell-command'." + (or (file-remote-p file 'localname) file))) + +;; Set correct font width for `all-the-icons' for appropriate mode-line width. +;; @see https://emacs.stackexchange.com/questions/14420/how-can-i-fix-incorrect-character-width +(defun doom-modeline--set-char-widths (alist) + "Set correct widths of icons characters in ALIST." + (while (char-table-parent char-width-table) + (setq char-width-table (char-table-parent char-width-table))) + (dolist (pair alist) + (let ((width (car pair)) + (chars (cdr pair)) + (table (make-char-table nil))) + (dolist (char chars) + (set-char-table-range table char width)) + (optimize-char-table table) + (set-char-table-parent table char-width-table) + (setq char-width-table table)))) + +(defconst doom-modeline-rhs-icons-alist + '((2 . (;; VCS + ?\xf0ac ; git-compare + ?\xf023 ; git-merge + ?\xf03f ; arrow-down + ?\xf02d ; alert + ?\xf020 ; git-branch + + ;; Checker + ?\xe611 ; do_not_disturb_alt + ?\xe5ca ; check + ?\xe192 ; access_time + ?\xe624 ; sim_card_alert + ?\xe034 ; pause + ?\xe645 ; priority_high + + ;; Minor modes + ?\xf02f ; gear + + ;; Persp + ?\xe2c7 ; folder + + ;; Preview + ?\xe8a0 ; pageview + + ;; REPL + ?\xf155 ; dollar-sign + + ;; LSP + ?\xf135 ; rocket + + ;; GitHub + ?\xf09b ; github + + ;; Debug + ?\xf188 ; bug + + ;; Mail + ?\xe0be ; email + + ;; IRC + ?\xe0c9 ; message + + ;; Battery + ?\xe939 ; battery-charging + ?\xf244 ; battery-empty + ?\xf240 ; battery-full + ?\xf242 ; battery-half + ?\xf243 ; battery-quarter + ?\xf241 ; battery-three-quarters + )))) + +(defun doom-modeline-set-char-widths (&rest _) + "Set char widths for the unicode icons." + (doom-modeline--set-char-widths doom-modeline-rhs-icons-alist)) + +(if (and (daemonp) + (not (frame-parameter nil 'client))) + (add-hook 'after-make-frame-functions #'doom-modeline-set-char-widths) + (and (display-graphic-p) (doom-modeline-set-char-widths))) + + +;; +;; Customization +;; + +(defgroup doom-modeline nil + "A minimal and modern mode-line." + :group 'mode-line + :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) + +(defcustom doom-modeline-support-imenu nil + "If non-nil, cause imenu to see `doom-modeline' declarations. +This is done by adjusting `lisp-imenu-generic-expression' to +include support for finding `doom-modeline-def-*' forms. + +Must be set before loading doom-modeline." + :type 'boolean + :set (lambda (_sym val) + (if val + (add-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu) + (remove-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu))) + :group 'doom-modeline) + +(defcustom doom-modeline-height 25 + "How tall the mode-line should be. It's only respected in GUI. +If the actual char height is larger, it respects the actual char height. +If `doom-modeline-height' is <= 0 the modeline will have default height." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-bar-width 4 + "How wide the mode-line bar should be. It's only respected in GUI." + :type 'integer + :set (lambda (sym val) + (set sym (if (> val 0) val 1))) + :group 'doom-modeline) + +(defcustom doom-modeline-hud nil + "Whether to use hud instead of default bar. It's only respected in GUI." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-hud-min-height 2 + "Minimum height in pixels of the \"thumb\" of the hud. +Only respected in GUI." + :type 'integer + :set (lambda (sym val) + (set sym (if (> val 1) val 1))) + :group 'doom-modeline) + +(defcustom doom-modeline-window-width-limit 0.25 + "The limit of the window width. + +If `window-width' is smaller than the limit, some information won't be +displayed. It can be an integer or a float number. `nil' means no limit." + :type '(choice integer + float + (const :tag "Disable" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-project-detection 'auto + "How to detect the project root. + +nil means to use `default-directory'. + +The project management packages have some issues on detecting project root. +e.g. `projectile' doesn't handle symlink folders well, while `project' is +unable to handle sub-projects. +Specify another one if you encounter the issue." + :type '(choice (const :tag "Auto-detect" auto) + (const :tag "Find File in Project" ffip) + (const :tag "Projectile" projectile) + (const :tag "Built-in Project" project) + (const :tag "Disable" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-file-name-style 'auto + "Determines the style used by `doom-modeline-buffer-file-name'. + +Given ~/Projects/FOSS/emacs/lisp/comint.el + auto => emacs/lisp/comint.el (in a project) or comint.el + truncate-upto-project => ~/P/F/emacs/lisp/comint.el + truncate-from-project => ~/Projects/FOSS/emacs/l/comint.el + truncate-with-project => emacs/l/comint.el + truncate-except-project => ~/P/F/emacs/l/comint.el + truncate-upto-root => ~/P/F/e/lisp/comint.el + truncate-all => ~/P/F/e/l/comint.el + truncate-nil => ~/Projects/FOSS/emacs/lisp/comint.el + relative-from-project => emacs/lisp/comint.el + relative-to-project => lisp/comint.el + file-name => comint.el + buffer-name => comint.el<2> (uniquify buffer name)" + :type '(choice (const auto) + (const truncate-upto-project) + (const truncate-upto-project) + (const truncate-from-project) + (const truncate-with-project) + (const truncate-except-project) + (const truncate-upto-root) + (const truncate-all) + (const truncate-nil) + (const relative-from-project) + (const relative-to-project) + (const file-name) + (const buffer-name)) + :group'doom-modeline) + +(defcustom doom-modeline-icon t + "Whether display the icons in the mode-line. + +While using the server mode in GUI, should set the value explicitly." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-major-mode-icon t + "Whether display the icon for `major-mode'. + +It respects `doom-modeline-icon'." + :type 'boolean + :group'doom-modeline) + +(defcustom doom-modeline-major-mode-color-icon t + "Whether display the colorful icon for `major-mode'. + +It respects `all-the-icons-color-icons'." + :type 'boolean + :group'doom-modeline) + +(defcustom doom-modeline-buffer-state-icon t + "Whether display the icon for the buffer state. + +It respects `doom-modeline-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-modification-icon t + "Whether display the modification icon for the buffer. + +It respects `doom-modeline-icon' and `doom-modeline-buffer-state-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-unicode-fallback nil + "Whether to use unicode as a fallback (instead of ASCII) when not using icons." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-name t + "Whether display the buffer name." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-minor-modes nil + "Whether display the minor modes in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-enable-word-count nil + "If non-nil, a word count will be added to the selection-info modeline segment." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-continuous-word-count-modes + '(markdown-mode gfm-mode org-mode) + "Major modes in which to display word count continuously. + +It respects `doom-modeline-enable-word-count'." + :type '(repeat (symbol :tag "Major-Mode") ) + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-encoding t + "Whether display the buffer encoding." + :type '(choice (const :tag "Always" t) + (const :tag "When non-default" nondefault) + (const :tag "Never" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-default-coding-system 'utf-8 + "Default coding system for `doom-modeline-buffer-encoding' `nondefault'." + :type 'coding-system + :group 'doom-modeline) + +(defcustom doom-modeline-default-eol-type 0 + "Default EOL type for `doom-modeline-buffer-encoding' `nondefault'." + :type '(choice (const :tag "Unix-style LF" 0) + (const :tag "DOS-style CRLF" 1) + (const :tag "Mac-style CR" 2)) + :group 'doom-modeline) + +(defcustom doom-modeline-indent-info nil + "Whether display the indentation information." + :type 'boolean + :group 'doom-modeline) + +;; It is based upon `editorconfig-indentation-alist' but is used to read indentation levels instead +;; of setting them. (https://github.com/editorconfig/editorconfig-emacs) +(defcustom doom-modeline-indent-alist + '((apache-mode apache-indent-level) + (awk-mode c-basic-offset) + (bpftrace-mode c-basic-offset) + (c++-mode c-basic-offset) + (c-mode c-basic-offset) + (cmake-mode cmake-tab-width) + (coffee-mode coffee-tab-width) + (cperl-mode cperl-indent-level) + (crystal-mode crystal-indent-level) + (csharp-mode c-basic-offset) + (css-mode css-indent-offset) + (d-mode c-basic-offset) + (emacs-lisp-mode lisp-indent-offset) + (enh-ruby-mode enh-ruby-indent-level) + (erlang-mode erlang-indent-level) + (ess-mode ess-indent-offset) + (f90-mode f90-associate-indent + f90-continuation-indent + f90-critical-indent + f90-do-indent + f90-if-indent + f90-program-indent + f90-type-indent) + (feature-mode feature-indent-offset + feature-indent-level) + (fsharp-mode fsharp-continuation-offset + fsharp-indent-level + fsharp-indent-offset) + (groovy-mode groovy-indent-offset) + (haskell-mode haskell-indent-spaces + haskell-indent-offset + haskell-indentation-layout-offset + haskell-indentation-left-offset + haskell-indentation-starter-offset + haskell-indentation-where-post-offset + haskell-indentation-where-pre-offset + shm-indent-spaces) + (haxor-mode haxor-tab-width) + (idl-mode c-basic-offset) + (jade-mode jade-tab-width) + (java-mode c-basic-offset) + (js-mode js-indent-level) + (js-jsx-mode js-indent-level + sgml-basic-offset) + (js2-mode js2-basic-offset) + (js2-jsx-mode js2-basic-offset + sgml-basic-offset) + (js3-mode js3-indent-level) + (json-mode js-indent-level) + (julia-mode julia-indent-offset) + (kotlin-mode kotlin-tab-width) + (latex-mode tex-indent-basic) + (lisp-mode lisp-indent-offset) + (livescript-mode livescript-tab-width) + (lua-mode lua-indent-level) + (matlab-mode matlab-indent-level) + (mips-mode mips-tab-width) + (mustache-mode mustache-basic-offset) + (nasm-mode nasm-basic-offset) + (nginx-mode nginx-indent-level) + (nxml-mode nxml-child-indent) + (objc-mode c-basic-offset) + (octave-mode octave-block-offset) + (perl-mode perl-indent-level) + (php-mode c-basic-offset) + (pike-mode c-basic-offset) + (ps-mode ps-mode-tab) + (pug-mode pug-tab-width) + (puppet-mode puppet-indent-level) + (python-mode python-indent-offset) + (ruby-mode ruby-indent-level) + (rust-mode rust-indent-offset) + (rustic-mode rustic-indent-offset) + (scala-mode scala-indent:step) + (scss-mode css-indent-offset) + (sgml-mode sgml-basic-offset) + (sh-mode sh-basic-offset + sh-indentation) + (slim-mode slim-indent-offset) + (sml-mode sml-indent-level) + (tcl-mode tcl-indent-level + tcl-continued-indent-level) + (terra-mode terra-indent-level) + (typescript-mode typescript-indent-level) + (verilog-mode verilog-indent-level + verilog-indent-level-behavioral + verilog-indent-level-declaration + verilog-indent-level-module + verilog-cexp-indent + verilog-case-indent) + (web-mode web-mode-attr-indent-offset + web-mode-attr-value-indent-offset + web-mode-code-indent-offset + web-mode-css-indent-offset + web-mode-markup-indent-offset + web-mode-sql-indent-offset + web-mode-block-padding + web-mode-script-padding + web-mode-style-padding) + (yaml-mode yaml-indent-offset)) + "Indentation retrieving variables matched to major modes used + when `doom-modeline-indent-info' is non-nil. When multiple + variables are specified for a mode, they will be tried resolved + in the given order." + :type '(alist :key-type symbol :value-type sexp) + :group 'doom-modeline) + +(defcustom doom-modeline-checker-simple-format t + "If non-nil, only display one number for checker information if applicable." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-number-limit 99 + "The maximum number displayed for notifications." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-vcs-max-length 12 + "The maximum displayed length of the branch name of version control." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-workspace-name t + "Whether display the workspace name. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-persp-name t + "Whether display the perspective name. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-display-default-persp-name nil + "If non nil the default perspective name is displayed in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-persp-icon t + "If non nil the perspective name is displayed alongside a folder icon." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-repl t + "Whether display the `repl' state. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-lsp t + "Whether display the `lsp' state. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-github nil + "Whether display the GitHub notifications. + +It requires `ghub' and `async' packages." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-github-interval 1800 ; (* 30 60) + "The interval of checking GitHub." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-env-version t + "Whether display the environment version." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-modal-icon t + "Whether display the modal state icon. + +Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-mu4e nil + "Whether display the mu4e notifications. + +It requires `mu4e-alert' package." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-gnus nil + "Whether to display notifications from gnus. + +It requires `gnus' to be setup" + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-timer 2 + "The wait time in minutes before gnus fetches mail. + +If nil, don't set up a hook." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-idle nil + "Whether to wait an idle time to scan for news. + +When t, sets `doom-modeline-gnus-timer' as an idle timer. If a +number, Emacs must have been idle this given time, checked after +reach the defined timer, to fetch news. The time step can be +configured in `gnus-demon-timestep'." + :type '(choice + (boolean :tag "Set `doom-modeline-gnus-timer' as an idle timer") + (number :tag "Set a custom idle timer")) + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-excluded-groups nil + "A list of groups to be excluded from the unread count. +Groups' names list in `gnus-newsrc-alist'`" + :type '(repeat string) + :group 'doom-modeline) + +(defcustom doom-modeline-irc t + "Whether display the irc notifications. + +It requires `circe' or `erc' package." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-irc-buffers nil + "Whether display the unread irc buffers." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-irc-stylize 'identity + "Function to stylize the irc buffer names." + :type 'function + :group 'doom-modeline) + + +;; +;; Faces +;; + +(defgroup doom-modeline-faces nil + "The faces of `doom-modeline'." + :group 'doom-modeline + :group 'faces + :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) + +(defface doom-modeline-spc-face + '((t (:inherit mode-line))) + "Face used for the white space." + :group 'doom-modeline-faces) + +(defface doom-modeline-spc-inactive-face + '((t (:inherit mode-line-inactive))) + "Face used for the inactive white space." + :group 'doom-modeline-faces) + +(defface doom-modeline-vspc-face + '((t (:inherit variable-pitch))) + "Face used for the variable white space." + :group 'doom-modeline-faces) + +(defface doom-modeline-vspc-inactive-face + '((t (:inherit (mode-line-inactive doom-modeline-vspc-face)))) + "Face used for the variable white space." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-path + '((t (:inherit (mode-line-emphasis bold)))) + "Face used for the dirname part of the buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-file + '((t (:inherit (mode-line-buffer-id bold)))) + "Face used for the filename part of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-modified + '((t (:inherit (error bold) :background nil))) + "Face used for the 'unsaved' symbol in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-major-mode + '((t (:inherit (mode-line-emphasis bold)))) + "Face used for the major-mode segment in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-minor-mode + '((t (:inherit font-lock-doc-face :slant normal))) + "Face used for the minor-modes segment in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-parent-dir + '((t (:inherit (font-lock-comment-face bold)))) + "Face used for the project parent directory of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-dir + '((t (:inherit (font-lock-string-face bold)))) + "Face used for the project directory of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-root-dir + '((t (:inherit (mode-line-emphasis bold)))) + "Face used for the project part of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-highlight + '((t (:inherit mode-line-emphasis))) + "Face for bright segments of the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-panel + '((t (:inherit mode-line-highlight))) + "Face for 'X out of Y' segments, such as `anzu', `evil-substitute' and`iedit', etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-host + '((t (:inherit italic))) + "Face for remote hosts in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-input-method + '((t (:inherit (mode-line-emphasis bold)))) + "Face for input method in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-input-method-alt + '((t (:inherit (font-lock-doc-face bold) :slant normal))) + "Alternative face for input method in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-debug + '((t (:inherit (font-lock-doc-face bold) :slant normal))) + "Face for debug-level messages in the mode-line. Used by vcs, checker, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-info + '((t (:inherit (success bold)))) + "Face for info-level messages in the mode-line. Used by vcs, checker, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-warning + '((t (:inherit (warning bold)))) + "Face for warnings in the mode-line. Used by vcs, checker, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-urgent + '((t (:inherit (error bold)))) + "Face for errors in the mode-line. Used by vcs, checker, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-notification + '((t (:inherit doom-modeline-warning))) + "Face for notifications in the mode-line. Used by GitHub, mu4e, +etc. (also see the face `doom-modeline-unread-number')." + :group 'doom-modeline-faces) + +(defface doom-modeline-unread-number + '((t (:slant italic :weight normal))) + "Face for unread number in the mode-line. Used by GitHub, mu4e, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-bar + '((t (:inherit highlight))) + "The face used for the left-most bar in the mode-line of an active window." + :group 'doom-modeline-faces) + +(defface doom-modeline-bar-inactive + `((t (:background ,(face-foreground 'mode-line-inactive)))) + "The face used for the left-most bar in the mode-line of an inactive window." + :group 'doom-modeline-faces) + +(defface doom-modeline-debug-visual + `((((class color) (background light)) + (:background ,(face-foreground 'all-the-icons-orange))) + (((class color) (background dark)) + (:background ,(face-foreground 'all-the-icons-dorange)))) + "Face to use for the mode-line while debugging." + :group 'doom-modeline) + +(defface doom-modeline-evil-emacs-state + '((t (:inherit (font-lock-builtin-face bold)))) + "Face for the Emacs state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-insert-state + '((t (:inherit (font-lock-keyword-face bold)))) + "Face for the insert state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-motion-state + '((t :inherit (font-lock-doc-face bold) :slant normal)) + "Face for the motion state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-normal-state + '((t (:inherit doom-modeline-info))) + "Face for the normal state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-operator-state + '((t (:inherit doom-modeline-buffer-file))) + "Face for the operator state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-visual-state + '((t (:inherit doom-modeline-warning))) + "Face for the visual state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-replace-state + '((t (:inherit doom-modeline-urgent))) + "Face for the replace state tag in evil state indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-persp-name + '((t (:inherit (font-lock-comment-face italic)))) + "Face for the persp name." + :group 'doom-modeline-faces) + +(defface doom-modeline-persp-buffer-not-in-persp + '((t (:inherit (font-lock-doc-face bold italic)))) + "Face for the buffers which are not in the persp." + :group 'doom-modeline-faces) + +(defface doom-modeline-repl-success + '((t (:inherit success :weight normal))) + "Face for REPL success state." + :group 'doom-modeline-faces) + +(defface doom-modeline-repl-warning + '((t (:inherit warning :weight normal))) + "Face for REPL warning state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-success + '((t (:inherit success :weight normal))) + "Face for LSP success state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-warning + '((t (:inherit warning :weight normal))) + "Face for LSP warning state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-error + '((t (:inherit error :weight normal))) + "Face for LSP error state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-running + '((t (:inherit compilation-mode-line-run :weight normal :slant normal))) + "Face for LSP running state." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-charging + '((t (:inherit success :weight normal))) + "Face for battery charging status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-full + '((t (:inherit success :weight normal))) + "Face for battery full status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-normal + '((t (:inherit mode-line :weight normal))) + "Face for battery normal status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-warning + '((t (:inherit warning :weight normal))) + "Face for battery warning status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-critical + '((t (:inherit error :weight normal))) + "Face for battery critical status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-error + '((t (:inherit error :weight normal))) + "Face for battery error status." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-timemachine + '((t (:inherit doom-modeline-buffer-file :slant italic))) + "Face for timemachine status." + :group 'doom-modeline-faces) + + +;; +;; Externals +;; + +(declare-function face-remap-remove-relative "face-remap") +(declare-function ffip-get-project-root-directory "ext:find-file-in-project") +(declare-function project-root "ext:project") +(declare-function projectile-project-root "ext:projectile") + + +;; +;; Utilities +;; + +(defun doom-modeline-add-font-lock () + "Fontify `doom-modeline-def-*' statements." + (font-lock-add-keywords + 'emacs-lisp-mode + '(("(\\(doom-modeline-def-.+\\)\\_> +\\(.*?\\)\\_>" + (1 font-lock-keyword-face) + (2 font-lock-constant-face))))) +(doom-modeline-add-font-lock) + +(defun doom-modeline-add-imenu () + "Add to `imenu' index." + (add-to-list + 'imenu-generic-expression + '("Modelines" + "^\\s-*(\\(doom-modeline-def-modeline\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\s'\\|\\\\.\\)+\\)" + 2)) + (add-to-list + 'imenu-generic-expression + '("Segments" + "^\\s-*(\\(doom-modeline-def-segment\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" + 2)) + (add-to-list + 'imenu-generic-expression + '("Envs" + "^\\s-*(\\(doom-modeline-def-env\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" + 2))) + + +;; +;; Core helpers +;; + +;; FIXME #183: Force to calculate mode-line height +;; @see https://github.com/seagle0128/doom-modeline/issues/183 +;; @see https://github.com/seagle0128/doom-modeline/issues/483 +(defun doom-modeline-redisplay (&rest _) + "Call `redisplay' to trigger mode-line height calculations. + +Certain functions, including e.g. `fit-window-to-buffer', base +their size calculations on values which are incorrect if the +mode-line has a height different from that of the `default' face +and certain other calculations have not yet taken place for the +window in question. + +These calculations can be triggered by calling `redisplay' +explicitly at the appropriate time and this functions purpose +is to make it easier to do so. + +This function is like `redisplay' with non-nil FORCE argument, +but it will only trigger a redisplay when there is a non nil +`mode-line-format' and the height of the mode-line is different +from that of the `default' face. This function is intended to be +used as an advice to window creation functions." + (when (and (bound-and-true-p doom-modeline-mode) + mode-line-format + (/= (frame-char-height) (window-mode-line-height))) + (redisplay t))) +(unless (>= emacs-major-version 29) + (advice-add #'fit-window-to-buffer :before #'doom-modeline-redisplay)) + +;; Keep `doom-modeline-current-window' up-to-date +(defun doom-modeline--get-current-window (&optional frame) + "Get the current window but should exclude the child windows." + (if (and (fboundp 'frame-parent) (frame-parent frame)) + (frame-selected-window (frame-parent frame)) + (frame-selected-window frame))) + +(defvar doom-modeline-current-window (doom-modeline--get-current-window)) + +(defun doom-modeline--active () + "Whether is an active window." + (unless (and (bound-and-true-p mini-frame-frame) + (and (frame-live-p mini-frame-frame) + (frame-visible-p mini-frame-frame))) + (and doom-modeline-current-window + (eq (doom-modeline--get-current-window) doom-modeline-current-window)))) + +(defun doom-modeline-set-selected-window (&rest _) + "Set `doom-modeline-current-window' appropriately." + (let ((win (doom-modeline--get-current-window))) + (setq doom-modeline-current-window + (if (minibuffer-window-active-p win) + (minibuffer-selected-window) + win)))) + +(defun doom-modeline-unset-selected-window () + "Unset `doom-modeline-current-window' appropriately." + (setq doom-modeline-current-window nil)) + +(add-hook 'pre-redisplay-functions #'doom-modeline-set-selected-window) + +;; Ensure modeline is inactive when Emacs is unfocused (and active otherwise) +(defvar doom-modeline-remap-face-cookie nil) +(defun doom-modeline-focus () + "Focus mode-line." + (when doom-modeline-remap-face-cookie + (require 'face-remap) + (face-remap-remove-relative doom-modeline-remap-face-cookie))) +(defun doom-modeline-unfocus () + "Unfocus mode-line." + (setq doom-modeline-remap-face-cookie + (face-remap-add-relative 'mode-line 'mode-line-inactive))) + +(with-no-warnings + (if (boundp 'after-focus-change-function) + (progn + (defun doom-modeline-focus-change (&rest _) + (if (frame-focus-state) + (doom-modeline-focus) + (doom-modeline-unfocus))) + (advice-add #'handle-switch-frame :after #'doom-modeline-focus-change) + (add-function :after after-focus-change-function #'doom-modeline-focus-change)) + (progn + (add-hook 'focus-in-hook #'doom-modeline-focus) + (add-hook 'focus-out-hook #'doom-modeline-unfocus)))) + + +;; +;; Core +;; + +(defvar doom-modeline-fn-alist ()) +(defvar doom-modeline-var-alist ()) + +(defmacro doom-modeline-def-segment (name &rest body) + "Defines a modeline segment NAME with BODY and byte compiles it." + (declare (indent defun) (doc-string 2)) + (let ((sym (intern (format "doom-modeline-segment--%s" name))) + (docstring (if (stringp (car body)) + (pop body) + (format "%s modeline segment" name)))) + (cond ((and (symbolp (car body)) + (not (cdr body))) + (add-to-list 'doom-modeline-var-alist (cons name (car body))) + `(add-to-list 'doom-modeline-var-alist (cons ',name ',(car body)))) + (t + (add-to-list 'doom-modeline-fn-alist (cons name sym)) + `(progn + (fset ',sym (lambda () ,docstring ,@body)) + (add-to-list 'doom-modeline-fn-alist (cons ',name ',sym)) + ,(unless (bound-and-true-p byte-compile-current-file) + `(let (byte-compile-warnings) + (byte-compile #',sym)))))))) + +(defun doom-modeline--prepare-segments (segments) + "Prepare mode-line `SEGMENTS'." + (let (forms it) + (dolist (seg segments) + (cond ((stringp seg) + (push seg forms)) + ((symbolp seg) + (cond ((setq it (cdr (assq seg doom-modeline-fn-alist))) + (push (list :eval (list it)) forms)) + ((setq it (cdr (assq seg doom-modeline-var-alist))) + (push it forms)) + ((error "%s is not a defined segment" seg)))) + ((error "%s is not a valid segment" seg)))) + (nreverse forms))) + +(defvar doom-modeline--font-width-cache nil) +(defun doom-modeline--font-width () + "Cache the font width." + (if (display-graphic-p) + (let ((attributes (face-all-attributes 'mode-line))) + (or (cdr (assoc attributes doom-modeline--font-width-cache)) + (let ((width (window-font-width nil 'mode-line))) + (push (cons attributes width) doom-modeline--font-width-cache) + width))) + 1)) + +;; Refresh the font width after setting frame parameters +;; to ensure the font width is correct. +(defun doom-modeline-refresh-font-width-cache (&rest _) + "Refresh the font width cache." + (setq doom-modeline--font-width-cache nil) + (doom-modeline--font-width)) +(add-hook 'window-setup-hook #'doom-modeline-refresh-font-width-cache) +(add-hook 'after-make-frame-functions #'doom-modeline-refresh-font-width-cache) +(add-hook 'after-setting-font-hook #'doom-modeline-refresh-font-width-cache) +(add-hook 'server-after-make-frame-hook #'doom-modeline-refresh-font-width-cache) + +(defun doom-modeline-def-modeline (name lhs &optional rhs) + "Defines a modeline format and byte-compiles it. +NAME is a symbol to identify it (used by `doom-modeline' for retrieval). +LHS and RHS are lists of symbols of modeline segments defined with +`doom-modeline-def-segment'. + +Example: + (doom-modeline-def-modeline 'minimal + '(bar matches \" \" buffer-info) + '(media-info major-mode)) + (doom-modeline-set-modeline 'minimal t)" + (let ((sym (intern (format "doom-modeline-format--%s" name))) + (lhs-forms (doom-modeline--prepare-segments lhs)) + (rhs-forms (doom-modeline--prepare-segments rhs))) + (defalias sym + (lambda () + (list lhs-forms + (propertize + " " + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive) + 'display `((space + :align-to + (- (+ right right-fringe right-margin scroll-bar) + ,(* (let ((width (doom-modeline--font-width))) + (or (and (= width 1) 1) + (/ width (frame-char-width) 1.0))) + (string-width + (format-mode-line (cons "" rhs-forms)))))))) + rhs-forms)) + (concat "Modeline:\n" + (format " %s\n %s" + (prin1-to-string lhs) + (prin1-to-string rhs)))))) +(put 'doom-modeline-def-modeline 'lisp-indent-function 'defun) + +(defun doom-modeline (key) + "Return a mode-line configuration associated with KEY (a symbol). +Throws an error if it doesn't exist." + (let ((fn (intern-soft (format "doom-modeline-format--%s" key)))) + (when (functionp fn) + `(:eval (,fn))))) + +(defun doom-modeline-set-modeline (key &optional default) + "Set the modeline format. Does nothing if the modeline KEY doesn't exist. +If DEFAULT is non-nil, set the default mode-line for all buffers." + (when-let ((modeline (doom-modeline key))) + (setf (if default + (default-value 'mode-line-format) + (buffer-local-value 'mode-line-format (current-buffer))) + (list "%e" modeline)))) + + +;; +;; Helpers +;; + +(defsubst doom-modeline-spc () + "Text style with whitespace." + (propertize " " 'face (if (doom-modeline--active) + 'doom-modeline-spc-face + 'doom-modeline-spc-inactive-face))) + +(defsubst doom-modeline-wspc () + "Text style with wide whitespace." + (propertize " " 'face (if (doom-modeline--active) + 'doom-modeline-spc-face + 'doom-modeline-spc-inactive-face))) + +(defsubst doom-modeline-vspc () + "Text style with icons in mode-line." + (propertize " " 'face (if (doom-modeline--active) + 'doom-modeline-vspc-face + 'doom-modeline-vspc-inactive-face))) + +(defun doom-modeline--font-height () + "Calculate the actual char height of the mode-line." + (let ((height (face-attribute 'mode-line :height))) + ;; WORKAROUND: Fix tall issue of 27 on Linux + ;; @see https://github.com/seagle0128/doom-modeline/issues/271 + (round + (* (if (or (<= doom-modeline-height 0) + (and (>= emacs-major-version 27) + (not (eq system-type 'darwin)))) + 1.0 + (if doom-modeline-icon 1.68 1.25)) + (cond ((integerp height) (/ height 10)) + ((floatp height) (* height (frame-char-height))) + (t (frame-char-height))))))) + +(defun doom-modeline--original-value (sym) + "Return the original value for SYM, if any. + +If SYM has an original value, return it in a list. Return nil +otherwise." + (let* ((orig-val-expr (get sym 'standard-value))) + (when (consp orig-val-expr) + (ignore-errors + (list + (eval (car orig-val-expr))))))) + +(defun doom-modeline-add-variable-watcher (symbol watch-function) + "Cause WATCH-FUNCTION to be called when SYMBOL is set if possible. + +See docs of `add-variable-watcher'." + (when (fboundp 'add-variable-watcher) + (add-variable-watcher symbol watch-function))) + +(defun doom-modeline-propertize-icon (icon &optional face) + "Propertize the ICON with the specified FACE. + +The face should be the first attribute, or the font family may be overridden. +So convert the face \":family XXX :height XXX :inherit XXX\" to +\":inherit XXX :family XXX :height XXX\". +See https://github.com/seagle0128/doom-modeline/issues/301." + (if (and doom-modeline-icon (display-graphic-p)) + (when-let ((props (get-text-property 0 'face icon))) + (cl-destructuring-bind (&key family height inherit &allow-other-keys) props + (propertize icon 'face `(:inherit ,(or face inherit props) + :family ,family + :height ,height)))) + (propertize icon 'face face))) + +(defun doom-modeline-icon (icon-set icon-name unicode text &rest args) + "Display icon of ICON-NAME with ARGS in mode-line. + +ICON-SET includes `octicon', `faicon', `material', `alltheicons' and `fileicon', +etc. +UNICODE is the unicode char fallback. TEXT is the ASCII char fallback. +ARGS is same as `all-the-icons-octicon' and others." + (let ((face (or (plist-get args :face) 'mode-line))) + (or + ;; Icons + (when (and (display-graphic-p) + doom-modeline-icon + icon-name + (not (string-empty-p icon-name))) + (when-let* ((func (all-the-icons--function-name icon-set)) + (icon (and (fboundp func) (apply func icon-name args)))) + (doom-modeline-propertize-icon icon face))) + ;; Unicode fallback + (and doom-modeline-unicode-fallback + unicode + (not (string-empty-p unicode)) + (char-displayable-p (string-to-char unicode)) + (propertize unicode 'face face)) + ;; ASCII text + (and text (propertize text 'face face)) + ""))) + +(defun doom-modeline--create-bar-image (face width height) + "Create the bar image. +Use FACE1 for the bar, FACE2 for the background. +WIDTH and HEIGHT are the image size in pixels." + (when (and (display-graphic-p) + (image-type-available-p 'pbm)) + (propertize + " " 'display + (let ((color (or (face-background face nil t) "None"))) + (ignore-errors + (create-image + (concat (format "P1\n%i %i\n" width height) + (make-string (* width height) ?1) + "\n") + 'pbm t :foreground color :ascent 'center)))))) + +(defun doom-modeline--create-hud-image + (face1 face2 width height top-margin bottom-margin) + "Create the hud image. +Use FACE1 for the bar, FACE2 for the background. +WIDTH and HEIGHT are the image size in pixels. +TOP-MARGIN and BOTTOM-MARGIN are the size of the margin above and below the bar, +respectively." + (when (and (display-graphic-p) + (image-type-available-p 'pbm)) + (let ((min-height (min height doom-modeline-hud-min-height))) + (unless (> (- height top-margin bottom-margin) min-height) + (let ((margin (- height min-height))) + (setq top-margin (/ (* margin top-margin) (+ top-margin bottom-margin)) + bottom-margin (- margin top-margin))))) + (propertize + " " 'display + (let ((color1 (or (face-background face1 nil t) "None")) + (color2 (or (face-background face2 nil t) "None"))) + (create-image + (concat + (format "P1\n%i %i\n" width height) + (make-string (* top-margin width) ?0) + (make-string (* (- height top-margin bottom-margin) width) ?1) + (make-string (* bottom-margin width) ?0) + "\n") + 'pbm t :foreground color1 :background color2 :ascent 'center))))) + +;; Check whether `window-total-width' is smaller than the limit +(defvar-local doom-modeline--limited-width-p nil) +(defun doom-modeline-window-size-change-function (&rest _) + "Function for `window-size-change-functions'." + (setq doom-modeline--limited-width-p + (cond + ((integerp doom-modeline-window-width-limit) + (<= (window-total-width) doom-modeline-window-width-limit)) + ((floatp doom-modeline-window-width-limit) + (<= (/ (window-total-width) (frame-width) 1.0) + doom-modeline-window-width-limit))))) + +(add-hook 'window-size-change-functions #'doom-modeline-window-size-change-function) +(add-hook 'buffer-list-update-hook #'doom-modeline-window-size-change-function) + +(defvar-local doom-modeline--project-root nil) +(defun doom-modeline--project-root () + "Get the path to the root of your project. +Return nil if no project was found." + (or doom-modeline--project-root + (setq doom-modeline--project-root + (pcase (if (eq doom-modeline-project-detection 'auto) + (cond + ((fboundp 'ffip-get-project-root-directory) 'ffip) + ((fboundp 'projectile-project-root) 'projectile) + ((fboundp 'project-current) 'project) + (t 'default)) + doom-modeline-project-detection) + ('ffip + (let ((inhibit-message t)) + (ffip-get-project-root-directory))) + ('projectile + (projectile-project-root)) + ('project + (when-let ((project (project-current))) + (expand-file-name (if (fboundp 'project-root) + (project-root project) + (cdr project))))))))) + +(defun doom-modeline-project-p () + "Check if the file is in a project." + (doom-modeline--project-root)) + +(defun doom-modeline-project-root () + "Get the path to the root of your project. +Return `default-directory' if no project was found." + (or (doom-modeline--project-root) default-directory)) + +(defun doom-modeline-buffer-file-name () + "Propertized variable `buffer-file-name' based on +`doom-modeline-buffer-file-name-style'." + (let* ((buffer-file-name (file-local-name (or (buffer-file-name (buffer-base-buffer)) ""))) + (buffer-file-truename (file-local-name + (or buffer-file-truename (file-truename buffer-file-name) ""))) + (file-name + (pcase doom-modeline-buffer-file-name-style + ('auto + (if (doom-modeline-project-p) + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide) + (propertize "%b" 'face 'doom-modeline-buffer-file))) + ('truncate-upto-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink)) + ('truncate-from-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil 'shrink)) + ('truncate-with-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shink 'hide)) + ('truncate-except-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shink)) + ('truncate-upto-root + (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename)) + ('truncate-all + (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename t)) + ('truncate-nil + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename)) + ('relative-to-project + (doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename)) + ('relative-from-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide)) + ('file-name + (propertize (file-name-nondirectory buffer-file-name) + 'face 'doom-modeline-buffer-file)) + ((or 'buffer-name _) + (propertize "%b" 'face 'doom-modeline-buffer-file))))) + (propertize (if (string-empty-p file-name) + (propertize "%b" 'face 'doom-modeline-buffer-file) + file-name) + 'mouse-face 'mode-line-highlight + 'help-echo (concat buffer-file-truename + (unless (string= (file-name-nondirectory buffer-file-truename) + (buffer-name)) + (concat "\n" (buffer-name))) + "\nmouse-1: Previous buffer\nmouse-3: Next buffer") + 'local-map mode-line-buffer-identification-keymap))) + +(defun doom-modeline--buffer-file-name-truncate (file-path true-file-path &optional truncate-tail) + "Propertized variable `buffer-file-name' that truncates every dir along path. +If TRUNCATE-TAIL is t also truncate the parent directory of the file." + (let ((dirs (shrink-path-prompt (file-name-directory true-file-path)))) + (if (null dirs) + (propertize "%b" 'face 'doom-modeline-buffer-file) + (let ((dirname (car dirs)) + (basename (cdr dirs))) + (concat (propertize (concat dirname + (if truncate-tail (substring basename 0 1) basename) + "/") + 'face 'doom-modeline-project-root-dir) + (propertize (file-name-nondirectory file-path) + 'face 'doom-modeline-buffer-file)))))) + +(defun doom-modeline--buffer-file-name-relative (_file-path true-file-path &optional include-project) + "Propertized variable `buffer-file-name' showing directories relative to +project's root only." + (let ((root (file-local-name (doom-modeline-project-root)))) + (if (null root) + (propertize "%b" 'face 'doom-modeline-buffer-file) + (let ((relative-dirs (file-relative-name (file-name-directory true-file-path) + (if include-project (concat root "../") root)))) + (and (equal "./" relative-dirs) (setq relative-dirs "")) + (concat (propertize relative-dirs 'face 'doom-modeline-buffer-path) + (propertize (file-name-nondirectory true-file-path) + 'face 'doom-modeline-buffer-file)))))) + +(defun doom-modeline--buffer-file-name (file-path + _true-file-path + &optional + truncate-project-root-parent + truncate-project-relative-path + hide-project-root-parent) + "Propertized variable `buffer-file-name' given by FILE-PATH. +If TRUNCATE-PROJECT-ROOT-PARENT is non-nil will be saved by truncating project +root parent down fish-shell style. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el + +If TRUNCATE-PROJECT-RELATIVE-PATH is non-nil will be saved by truncating project +relative path down fish-shell style. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => ~/Projects/FOSS/emacs/l/comint.el + +If HIDE-PROJECT-ROOT-PARENT is non-nil will hide project root parent. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => emacs/lisp/comint.el" + (let ((project-root (file-local-name (doom-modeline-project-root)))) + (concat + ;; Project root parent + (unless hide-project-root-parent + (when-let (root-path-parent + (file-name-directory (directory-file-name project-root))) + (propertize + (if (and truncate-project-root-parent + (not (string-empty-p root-path-parent)) + (not (string= root-path-parent "/"))) + (shrink-path--dirs-internal root-path-parent t) + (abbreviate-file-name root-path-parent)) + 'face 'doom-modeline-project-parent-dir))) + ;; Project directory + (propertize + (concat (file-name-nondirectory (directory-file-name project-root)) "/") + 'face 'doom-modeline-project-dir) + ;; relative path + (propertize + (when-let (relative-path (file-relative-name + (or (file-name-directory file-path) "./") + project-root)) + (if (string= relative-path "./") + "" + (if truncate-project-relative-path + (substring (shrink-path--dirs-internal relative-path t) 1) + relative-path))) + 'face 'doom-modeline-buffer-path) + ;; File name + (propertize (file-name-nondirectory file-path) + 'face 'doom-modeline-buffer-file)))) + +(provide 'doom-modeline-core) + +;;; doom-modeline-core.el ends here diff --git a/org/elpa/doom-modeline-20220412.853/doom-modeline-env.el b/org/elpa/doom-modeline-20220412.853/doom-modeline-env.el new file mode 100644 index 0000000..87c8c50 --- /dev/null +++ b/org/elpa/doom-modeline-20220412.853/doom-modeline-env.el @@ -0,0 +1,275 @@ +;;; doom-modeline-env.el --- A environment parser for doom-modeline -*- lexical-binding: t -*- + +;; Copyright (C) 2019-2020 Justin Barclay, Vincent Zhang + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . +;; +;;; Commentary: +;; +;; Parse programming environment. +;; + +;;; Code: + +(require 'subr-x) +(require 'doom-modeline-core) + + +;; Externals +(defvar python-shell-interpreter) + + +;; Customizations + +(defgroup doom-modeline-env nil + "The environment parser for doom-modeline." + :group 'doom-modeline + :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) + +(defcustom doom-modeline-env-load-string "..." + "What to display as the version while a new one is being loaded." + :type 'string + :group 'doom-modeline-env) + +(defcustom doom-modeline-before-update-env-hook nil + "Hooks that run before the modeline version string is updated." + :type 'hook + :group 'doom-modeline-env) + +(defcustom doom-modeline-after-update-env-hook nil + "Hooks that run after the modeline version string is updated." + :type 'hook + :group 'doom-modeline-env) + + +;; Variables + +;; Show version string for multi-version managers like rvm, rbenv, pyenv, etc. +(defvar-local doom-modeline-env--version nil + "The version to display with major-mode in mode-line. +Example: \"2.6.0\"") + +(defvar-local doom-modeline-env--command nil + "A program that we're looking to extract version information from. +Example: \"ruby\"") + +(defvar-local doom-modeline-env--command-args nil + "A list of arguments for the command to extract the version from. +Example: '(\"--version\") ") + +(defvar-local doom-modeline-env--parser nil + "A function that returns version number from a command --version (or similar). +Example: 'doom-modeline-env--ruby") + + +;; Functions & Macros + +(defun doom-modeline-update-env () + "Update environment info on mode-line." + (when (and doom-modeline-env-version + doom-modeline-env--command + (executable-find doom-modeline-env--command) + doom-modeline-env--command-args + doom-modeline-env--parser) + (let ((default-directory (doom-modeline-project-root)) + (buffer (current-buffer))) + (run-hooks 'doom-modeline-before-update-env-hook) + (setq doom-modeline-env--version doom-modeline-env-load-string) + (doom-modeline-env--get + doom-modeline-env--command + doom-modeline-env--command-args + (lambda (prog-version) + (with-current-buffer buffer + (setq doom-modeline-env--version + (funcall doom-modeline-env--parser prog-version)) + (run-hooks 'doom-modeline-after-update-env-hook))))))) + +(add-hook 'find-file-hook #'doom-modeline-update-env) +(with-no-warnings + (if (boundp 'after-focus-change-function) + (add-function + :after after-focus-change-function + (lambda () + (if (frame-focus-state) + (doom-modeline-update-env)))) + (add-hook 'focus-in-hook #'doom-modeline-update-env))) + +(defun doom-modeline-env--get (prog args callback) + "Start a sub process using PROG and apply the ARGS to the sub process. +Once it receives information from STDOUT, it closes off the subprocess and +passes on the information into the CALLBACK. +Example: + (doom-modeline-env--get + \"ruby\" + '(\"--version\") + (lambda (line) + (message (doom-modeline-parser--ruby line)))" + (let ((proc (apply 'start-process + ;; Flaten process-args into a single list so we can handle + ;; variadic length args + (append + (list "doom-modeline-env" nil prog) + args))) + (parser callback)) + (set-process-filter proc + (lambda (_proc line) + (ignore-errors + (funcall parser line)))))) + +(cl-defmacro doom-modeline-def-env (name &key hooks command parser) + "Defines a handler for updating & displaying a version string for a language. + +NAME is an unquoted symbol representing the handler's unique ID. +HOOKS is a list of hook symbols where this handler should be triggered. +COMMAND should be a function that returns a shell command and its arguments (as + a list). It is run on HOOKS. It takes no arguments. +PARSER should be a function for parsing COMMAND's output line-by-line, to + extract the version string." + (declare (indent defun)) + (unless (and hooks command parser) + (error "'%s' env is missing either :hooks, :command or :parser" name)) + (let ((parse-fn (intern (format "doom-modeline-env--%s-parse" name))) + (action-fn (intern (format "doom-modeline-env--%s-args" name))) + (setup-fn (intern (format "doom-modeline-env-setup-%s" name))) + (update-fn (intern (format "doom-modeline-env-update-%s" name))) + (enable-var (intern (format "doom-modeline-env-enable-%s" name))) + (command-var (intern (format "doom-modeline-env-%s-command" name))) + (parser-var (intern (format "doom-modeline-env-%s-parser-fn" name))) + (exe-var (intern (format "doom-modeline-env-%s-executable" name)))) + (macroexp-progn + `((defcustom ,enable-var t + ,(format "Whether to display the version string for %s buffers." name) + :type 'boolean + :group 'doom-modeline-env) + (defvar ,command-var ',action-fn + ,(concat "A function that returns the shell command and arguments (as a list) to\n" + "produce a version string.")) + (defvar ,parser-var ',parse-fn + ,(format "The function to parse each line of `%s'\'s output." command-var)) + (defcustom ,exe-var nil + ,(format (concat "What executable to use for the version indicator in %s buffers.\n\n" + "If nil, the default binary for this language is used.") + name) + :type 'string + :group 'doom-modeline-env) + (defalias ',parse-fn ,parser + (format "The line parser for %s buffers.\n\nUsed by `%s'." + ',name ',update-fn)) + (defalias ',action-fn ,command + (format "The command resolver for %s buffers.\n\nUsed by `%s'." + ',name ',update-fn)) + (defalias ',setup-fn + (lambda () + (if enable-local-variables + (add-hook 'hack-local-variables-hook #',update-fn nil t) + (,update-fn))) + (format "Prepares the modeline to later display the %s version string." + ',name)) + (defalias ',update-fn + (lambda () + (when ,enable-var + (when-let* ((command-list (funcall ,command-var)) + (exe (executable-find (car command-list)))) + (setq doom-modeline-env--command exe + doom-modeline-env--command-args (cdr command-list) + doom-modeline-env--parser ,parser-var) + (doom-modeline-update-env)))) + (format "Updates the %s version string in the modeline." ',name)) + (let ((hooks ',(eval hooks))) + (dolist (hook (if (listp hooks) hooks (list hooks))) + (add-hook hook #',setup-fn))))))) + + +;; Bootstrap +;; Versions, support Python, Ruby, Perl and Golang, etc. + +;;;###autoload (autoload 'doom-modeline-env-setup-python "doom-modeline-env") +(doom-modeline-def-env python + :hooks 'python-mode-hook + :command (lambda () (cond ((and (fboundp 'pipenv-project-p) + (pipenv-project-p)) + (list "pipenv" "run" + (or doom-modeline-env-python-executable + python-shell-interpreter + "python") + "--version")) + ((executable-find "pyenv") (list "pyenv" "version-name")) + ((list (or doom-modeline-env-python-executable + python-shell-interpreter + "python") + "--version")))) + :parser (lambda (line) (let ((version (split-string line))) + (if (>= (length version) 2) + (cadr version) + (car version))))) + +;;;###autoload (autoload 'doom-modeline-env-setup-ruby "doom-modeline-env") +(doom-modeline-def-env ruby + :hooks '(ruby-mode-hook enh-ruby-mode-hook) + :command (lambda () (list (or doom-modeline-env-ruby-executable "ruby") "--version")) + :parser (lambda (line) + (car (split-string + (cadr + (split-string line)) + "p")))) + +;;;###autoload (autoload 'doom-modeline-env-setup-perl "doom-modeline-env") +(doom-modeline-def-env perl + :hooks 'perl-mode-hook + :command (lambda () (list (or doom-modeline-env-perl-executable "perl") "--version")) + :parser (lambda (line) + (cadr + (split-string + (car + (split-string + (cadr + (split-string line "(")) + ")")) + "v")))) + +;;;###autoload (autoload 'doom-modeline-env-setup-go "doom-modeline-env") +(doom-modeline-def-env go + :hooks 'go-mode-hook + :command (lambda () (list (or doom-modeline-env-go-executable "go") "version")) + :parser (lambda (line) + (cadr + (split-string + (cadr + (cdr + (split-string line))) + "go")))) + +;;;###autoload (autoload 'doom-modeline-env-setup-elixir "doom-modeline-env") +(doom-modeline-def-env elixir + :hooks 'elixir-mode-hook + :command (lambda () (list (or doom-modeline-env-elixir-executable "elixir") "--version")) + :parser (lambda (line) (cadr (split-string line)))) + +;;;###autoload (autoload 'doom-modeline-env-setup-rust "doom-modeline-env") +(doom-modeline-def-env rust + :hooks 'rust-mode-hook + :command (lambda () (list (or doom-modeline-env-rust-executable "rustc") "--version")) + :parser (lambda (line) + (car + (split-string + (cadr + (split-string line)) + "-")))) + +(provide 'doom-modeline-env) + +;;; doom-modeline-env.el ends here diff --git a/org/elpa/doom-modeline-20220412.853/doom-modeline-pkg.el b/org/elpa/doom-modeline-20220412.853/doom-modeline-pkg.el new file mode 100644 index 0000000..c289f03 --- /dev/null +++ b/org/elpa/doom-modeline-20220412.853/doom-modeline-pkg.el @@ -0,0 +1,15 @@ +(define-package "doom-modeline" "20220412.853" "A minimal and modern mode-line" + '((emacs "25.1") + (all-the-icons "2.2.0") + (shrink-path "0.2.0") + (dash "2.11.0")) + :commit "7d8eb7c44087a62d8dd6e8ba1afc26facd914fbc" :authors + '(("Vincent Zhang" . "seagle0128@gmail.com")) + :maintainer + '("Vincent Zhang" . "seagle0128@gmail.com") + :keywords + '("faces" "mode-line") + :url "https://github.com/seagle0128/doom-modeline") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/org/elpa/doom-modeline-20220412.853/doom-modeline-segments.el b/org/elpa/doom-modeline-20220412.853/doom-modeline-segments.el new file mode 100644 index 0000000..d0970d1 --- /dev/null +++ b/org/elpa/doom-modeline-20220412.853/doom-modeline-segments.el @@ -0,0 +1,2969 @@ +;;; doom-modeline-segments.el --- The segments for doom-modeline -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2020 Vincent Zhang + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . +;; + +;;; Commentary: +;; +;; The segments for doom-modeline. +;; Use `doom-modeline-def-segment' to create a new segment. +;; + +;;; Code: + +(require 'all-the-icons) +(require 'cl-lib) +(require 'seq) +(require 'subr-x) +(require 'doom-modeline-core) +(require 'doom-modeline-env) + + +;; +;; Externals +;; + +(defvar Info-current-file) +(defvar Info-current-node) +(defvar Info-mode-line-node-keymap) +(defvar anzu--cached-count) +(defvar anzu--current-position) +(defvar anzu--overflow-p) +(defvar anzu--state) +(defvar anzu--total-matched) +(defvar anzu-cons-mode-line-p) +(defvar aw-keys) +(defvar battery-echo-area-format) +(defvar battery-load-critical) +(defvar battery-mode-line-format) +(defvar battery-mode-line-limit) +(defvar battery-status-function) +(defvar boon-command-state) +(defvar boon-insert-state) +(defvar boon-off-state) +(defvar boon-special-state) +(defvar edebug-execution-mode) +(defvar eglot--managed-mode) +(defvar erc-modified-channels-alist) +(defvar evil-ex-active-highlights-alist) +(defvar evil-ex-argument) +(defvar evil-ex-range) +(defvar evil-mc-frozen) +(defvar evil-state) +(defvar evil-visual-beginning) +(defvar evil-visual-end) +(defvar evil-visual-selection) +(defvar flycheck-current-errors) +(defvar flycheck-mode-menu-map) +(defvar flymake--mode-line-format) +(defvar flymake--state) +(defvar flymake-menu) +(defvar gnus-newsrc-alist) +(defvar gnus-newsrc-hashtb) +(defvar grip--process) +(defvar helm--mode-line-display-prefarg) +(defvar iedit-occurrences-overlays) +(defvar meow--indicator) +(defvar minions-direct) +(defvar minions-mode-line-lighter) +(defvar minions-mode-line-minor-modes-map) +(defvar mlscroll-minimum-current-width) +(defvar mlscroll-right-align) +(defvar mu4e-alert-mode-line) +(defvar mu4e-alert-modeline-formatter) +(defvar nyan-minimum-window-width) +(defvar objed--obj-state) +(defvar objed--object) +(defvar objed-modeline-setup-func) +(defvar persp-nil-name) +(defvar phi-replace--mode-line-format) +(defvar phi-search--selection) +(defvar phi-search-mode-line-format) +(defvar poke-line-minimum-window-width) +(defvar rcirc-activity) +(defvar sml-modeline-len) +(defvar symbol-overlay-keywords-alist) +(defvar symbol-overlay-temp-symbol) +(defvar text-scale-mode-amount) +(defvar tracking-buffers) +(defvar winum-auto-setup-mode-line) +(defvar xah-fly-insert-state-p) + +(declare-function anzu--reset-status "ext:anzu") +(declare-function anzu--where-is-here "ext:anzu") +(declare-function async-inject-variables "ext:async") +(declare-function async-start "ext:async") +(declare-function avy-traverse "ext:avy") +(declare-function avy-tree "ext:avy") +(declare-function aw-update "ext:ace-window") +(declare-function aw-window-list "ext:ace-window") +(declare-function battery-format "battery") +(declare-function battery-update "battery") +(declare-function boon-modeline-string "ext:boon") +(declare-function boon-state-string "ext:boon") +(declare-function cider--connection-info "ext:cider") +(declare-function cider-connected-p "ext:cider") +(declare-function cider-current-repl "ext:cider") +(declare-function cider-jack-in "ext:cider") +(declare-function cider-quit "ext:cider") +(declare-function citre-mode "ext:citre-basic-tools") +(declare-function dap--cur-session "ext:dap-mode") +(declare-function dap--debug-session-name "ext:dap-mode") +(declare-function dap--debug-session-state "ext:dap-mode") +(declare-function dap--session-running "ext:dap-mode") +(declare-function dap-debug-recent "ext:dap-mode") +(declare-function dap-disconnect "ext:dap-mode") +(declare-function dap-hydra "ext:dap-hydra") +(declare-function edebug-help "edebug") +(declare-function edebug-next-mode "edebug") +(declare-function edebug-stop "edebug") +(declare-function eglot "ext:eglot") +(declare-function eglot--major-mode "ext:eglot" t t) +(declare-function eglot--project-nickname "ext:eglot" t t) +(declare-function eglot--spinner "ext:eglot" t t) +(declare-function eglot-clear-status "ext:eglot") +(declare-function eglot-current-server "ext:eglot") +(declare-function eglot-events-buffer "ext:eglot") +(declare-function eglot-forget-pending-continuations "ext:eglot") +(declare-function eglot-managed-p "ext:glot") +(declare-function eglot-reconnect "ext:eglot") +(declare-function eglot-shutdown "ext:eglot") +(declare-function eglot-stderr-buffer "ext:eglot") +(declare-function erc-switch-to-buffer "erc") +(declare-function erc-track-switch-buffer "erc-track") +(declare-function evil-delimited-arguments "ext:evil-common") +(declare-function evil-emacs-state-p "ext:evil-states" t t) +(declare-function evil-force-normal-state "ext:evil-commands" t t) +(declare-function evil-insert-state-p "ext:evil-states" t t) +(declare-function evil-motion-state-p "ext:evil-states" t t) +(declare-function evil-normal-state-p "ext:evil-states" t t) +(declare-function evil-operator-state-p "ext:evil-states" t t) +(declare-function evil-replace-state-p "ext:evil-states" t t) +(declare-function evil-state-property "ext:evil-common") +(declare-function evil-visual-state-p "ext:evil-states" t t) +(declare-function eyebrowse--get "ext:eyebrowse") +(declare-function face-remap-remove-relative "face-remap") +(declare-function fancy-narrow-active-p "ext:fancy-narrow") +(declare-function flycheck-buffer "ext:flycheck") +(declare-function flycheck-count-errors "ext:flycheck") +(declare-function flycheck-error-level-compilation-level "ext:flycheck") +(declare-function flycheck-list-errors "ext:flycheck") +(declare-function flycheck-next-error "ext:flycheck") +(declare-function flycheck-previous-error "ext:flycheck") +(declare-function flymake--diag-type "ext:flymake" t t) +(declare-function flymake--handle-report "ext:flymake") +(declare-function flymake--lookup-type-property "ext:flymake") +(declare-function flymake--state-diags "ext:flymake" t t) +(declare-function flymake-disabled-backends "ext:flymake") +(declare-function flymake-goto-next-error "ext:flymake") +(declare-function flymake-goto-prev-error "ext:flymake") +(declare-function flymake-reporting-backends "ext:flymake") +(declare-function flymake-running-backends "ext:flymake") +(declare-function flymake-show-buffer-diagnostics "ext:flymake") +(declare-function flymake-show-diagnostics-buffer "ext:flymake") +(declare-function flymake-start "ext:flymake") +(declare-function follow-all-followers "follow") +(declare-function gnus-demon-add-handler "gnus-demon") +(declare-function grip--preview-url "ext:grip-mode") +(declare-function grip-browse-preview "ext:grip-mode") +(declare-function grip-restart-preview "ext:grip-mode") +(declare-function grip-stop-preview "ext:grip-mode") +(declare-function helm-candidate-number-at-point "ext:helm-core") +(declare-function helm-get-candidate-number "ext:helm-core") +(declare-function iedit-find-current-occurrence-overlay "ext:iedit-lib") +(declare-function iedit-prev-occurrence "ext:iedit-lib") +(declare-function image-get-display-property "image-mode") +(declare-function jsonrpc--request-continuations "ext:jsonrpc" t t) +(declare-function jsonrpc-last-error "ext:jsonrpc" t t) +(declare-function lsp--workspace-print "ext:lsp-mode") +(declare-function lsp-describe-session "ext:lsp-mode") +(declare-function lsp-workspace-folders-open "ext:lsp-mode") +(declare-function lsp-workspace-restart "ext:lsp-mode") +(declare-function lsp-workspace-shutdown "ext:lsp-mode") +(declare-function lsp-workspaces "ext:lsp-mode") +(declare-function lv-message "ext:lv") +(declare-function mc/num-cursors "ext:multiple-cursors-core") +(declare-function mlscroll-mode-line "ext:mlscroll") +(declare-function mu4e-alert-default-mode-line-formatter "ext:mu4e-alert") +(declare-function mu4e-alert-enable-mode-line-display "ext:mu4e-alert") +(declare-function nyan-create "ext:nyan-mode") +(declare-function org-edit-src-save "ext:org-src") +(declare-function parrot-create "ext:parrot") +(declare-function pdf-cache-number-of-pages "ext:pdf-cache" t t) +(declare-function persp-add-buffer "ext:persp-mode") +(declare-function persp-contain-buffer-p "ext:persp-mode") +(declare-function persp-switch "ext:persp-mode") +(declare-function phi-search--initialize "ext:phi-search") +(declare-function poke-line-create "ext:poke-line") +(declare-function popup-create "ext:popup") +(declare-function popup-delete "ext:popup") +(declare-function rcirc-next-active-buffer "rcirc") +(declare-function rcirc-short-buffer-name "rcirc") +(declare-function rcirc-switch-to-server-buffer "rcirc") +(declare-function rcirc-window-configuration-change "rcirc") +(declare-function rime--should-enable-p "ext:rime") +(declare-function rime--should-inline-ascii-p "ext:rime") +(declare-function sml-modeline-create "ext:sml-modeline") +(declare-function symbol-overlay-assoc "ext:symbol-overlay") +(declare-function symbol-overlay-get-list "ext:symbol-overlay") +(declare-function symbol-overlay-get-symbol "ext:symbol-overlay") +(declare-function symbol-overlay-rename "ext:symbol-overlay") +(declare-function tab-bar--current-tab "tab-bar") +(declare-function tab-bar--current-tab-index "tab-bar") +(declare-function tracking-next-buffer "ext:tracking") +(declare-function tracking-previous-buffer "ext:tracking") +(declare-function tracking-shorten "ext:tracking") +(declare-function undo-tree-redo-1 "ext:undo-tree") +(declare-function undo-tree-undo-1 "ext:undo-tree") +(declare-function warning-numeric-level "warnings") +(declare-function window-numbering-clear-mode-line "ext:window-numbering") +(declare-function window-numbering-get-number-string "ext:window-numbering") +(declare-function window-numbering-install-mode-line "ext:window-numbering") +(declare-function winum--clear-mode-line "ext:winum") +(declare-function winum--install-mode-line "ext:winum") +(declare-function winum-get-number-string "ext:winum") + + + +;; +;; Buffer information +;; + +(defvar-local doom-modeline--buffer-file-icon nil) +(defun doom-modeline-update-buffer-file-icon (&rest _) + "Update file icon in mode-line." + (setq doom-modeline--buffer-file-icon + (when (and (display-graphic-p) + doom-modeline-icon + doom-modeline-major-mode-icon) + (let ((icon (all-the-icons-icon-for-buffer))) + (propertize (if (or (null icon) (symbolp icon)) + (doom-modeline-icon 'faicon "file-o" nil nil + :face 'all-the-icons-dsilver + :height 0.9 + :v-adjust 0.0) + icon) + 'help-echo (format "Major-mode: %s" (format-mode-line mode-name)) + 'display '(raise -0.135)))))) +(add-hook 'find-file-hook #'doom-modeline-update-buffer-file-icon) +(add-hook 'after-change-major-mode-hook #'doom-modeline-update-buffer-file-icon) +(add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-buffer-file-icon)))))) + +(defun doom-modeline-buffer-file-state-icon (icon unicode text face) + "Displays an ICON of buffer state with FACE. +UNICODE and TEXT are the alternatives if it is not applicable. +Uses `all-the-icons-material' to fetch the icon." + (doom-modeline-icon 'material icon unicode text + :face face + :height 1.1 + :v-adjust -0.225)) + +(defvar-local doom-modeline--buffer-file-state-icon nil) +(defun doom-modeline-update-buffer-file-state-icon (&rest _) + "Update the buffer or file state in mode-line." + (setq doom-modeline--buffer-file-state-icon + (when doom-modeline-buffer-state-icon + (ignore-errors + (concat + (cond (buffer-read-only + (doom-modeline-buffer-file-state-icon + "lock" "πŸ”’" "%1*" `(:inherit doom-modeline-warning + :weight ,(if doom-modeline-icon + 'normal + 'bold)))) + ((and buffer-file-name (buffer-modified-p) + doom-modeline-buffer-modification-icon) + (doom-modeline-buffer-file-state-icon + "save" "πŸ’Ύ" "%1*" `(:inherit doom-modeline-buffer-modified + :weight ,(if doom-modeline-icon + 'normal + 'bold)))) + ((and buffer-file-name + (not (file-remote-p buffer-file-name)) ; Avoid freezing while connection is lost + (not (file-exists-p buffer-file-name))) + (doom-modeline-buffer-file-state-icon + "do_not_disturb_alt" "🚫" "!" 'doom-modeline-urgent)) + (t "")) + (when (or (buffer-narrowed-p) + (and (bound-and-true-p fancy-narrow-mode) + (fancy-narrow-active-p)) + (bound-and-true-p dired-narrow-mode)) + (doom-modeline-buffer-file-state-icon + "vertical_align_center" "↕" "><" 'doom-modeline-warning))))))) + +(defvar-local doom-modeline--buffer-file-name nil) +(defun doom-modeline-update-buffer-file-name (&rest _) + "Update buffer file name in mode-line." + (setq doom-modeline--buffer-file-name + (ignore-errors + (save-match-data + (if buffer-file-name + (doom-modeline-buffer-file-name) + (propertize "%b" + 'face 'doom-modeline-buffer-file + 'mouse-face 'mode-line-highlight + 'help-echo "Buffer name +mouse-1: Previous buffer\nmouse-3: Next buffer" + 'local-map mode-line-buffer-identification-keymap)))))) +(add-hook 'find-file-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'after-save-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'evil-insert-state-exit-hook #'doom-modeline-update-buffer-file-name) +(advice-add #'not-modified :after #'doom-modeline-update-buffer-file-name) +(advice-add #'rename-buffer :after #'doom-modeline-update-buffer-file-name) +(advice-add #'set-visited-file-name :after #'doom-modeline-update-buffer-file-name) +(advice-add #'pop-to-buffer :after #'doom-modeline-update-buffer-file-name) +(advice-add #'undo :after #'doom-modeline-update-buffer-file-name) +(advice-add #'undo-tree-undo-1 :after #'doom-modeline-update-buffer-file-name) +(advice-add #'undo-tree-redo-1 :after #'doom-modeline-update-buffer-file-name) +(advice-add #'fill-paragraph :after #'doom-modeline-update-buffer-file-name) +(advice-add #'popup-create :after #'doom-modeline-update-buffer-file-name) +(advice-add #'popup-delete :after #'doom-modeline-update-buffer-file-name) +(advice-add #'org-edit-src-save :after #'doom-modeline-update-buffer-file-name) +(advice-add #'symbol-overlay-rename :after #'doom-modeline-update-buffer-file-name) + +(doom-modeline-add-variable-watcher + 'doom-modeline-buffer-file-name-style + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-buffer-file-name-style val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when buffer-file-name + (doom-modeline-update-buffer-file-name))))))) + +(defsubst doom-modeline--buffer-mode-icon () + "The icon of the current major mode." + (when (and doom-modeline-icon doom-modeline-major-mode-icon) + (when-let ((icon (or doom-modeline--buffer-file-icon + (doom-modeline-update-buffer-file-icon)))) + (concat + (let ((active (doom-modeline--active))) + (if (and active doom-modeline-major-mode-color-icon) + icon + (doom-modeline-propertize-icon icon (if active + 'mode-line + 'mode-line-inactive)))) + (doom-modeline-vspc))))) + +(defsubst doom-modeline--buffer-state-icon () + "The icon of the current buffer state." + (when doom-modeline-buffer-state-icon + (when-let ((icon (doom-modeline-update-buffer-file-state-icon))) + (concat + (if (doom-modeline--active) + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)) + (doom-modeline-vspc))))) + +(defsubst doom-modeline--buffer-name () + "The current buffer name." + (when doom-modeline-buffer-name + (if (and (not (eq doom-modeline-buffer-file-name-style 'file-name)) + doom-modeline--limited-width-p) + ;; Only display the buffer name if the window is small, and doesn't need to + ;; respect file-name style. + (propertize "%b" + 'face (cond ((and buffer-file-name (buffer-modified-p)) + 'doom-modeline-buffer-modified) + ((doom-modeline--active) 'doom-modeline-buffer-file) + (t 'mode-line-inactive)) + 'mouse-face 'mode-line-highlight + 'help-echo "Buffer name +mouse-1: Previous buffer\nmouse-3: Next buffer" + 'local-map mode-line-buffer-identification-keymap) + (when-let ((name (or doom-modeline--buffer-file-name + (doom-modeline-update-buffer-file-name)))) + (if (doom-modeline--active) + ;; Check if the buffer is modified + (if (and buffer-file-name (buffer-modified-p)) + (propertize name 'face 'doom-modeline-buffer-modified) + name) + (propertize name 'face 'mode-line-inactive)))))) + +(doom-modeline-def-segment buffer-info + "Combined information about the current buffer, including the current working +directory, the file name, and its state (modified, read-only or non-existent)." + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (doom-modeline--buffer-name))) + +(doom-modeline-def-segment buffer-info-simple + "Display only the current buffer's name, but with fontification." + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (propertize "%b" + 'face (cond ((and buffer-file-name (buffer-modified-p)) + 'doom-modeline-buffer-modified) + ((doom-modeline--active) 'doom-modeline-buffer-file) + (t 'mode-line-inactive)) + 'mouse-face 'mode-line-highlight + 'help-echo "Buffer name +mouse-1: Previous buffer\nmouse-3: Next buffer" + 'local-map mode-line-buffer-identification-keymap))) + +(doom-modeline-def-segment buffer-default-directory + "Displays `default-directory' with the icon and state . This is for special +buffers like the scratch buffer where knowing the current project directory is +important." + (let ((face (cond ((buffer-modified-p) + 'doom-modeline-buffer-modified) + ((doom-modeline--active) 'doom-modeline-buffer-path) + (t 'mode-line-inactive)))) + (concat (doom-modeline-spc) + (and doom-modeline-major-mode-icon + (concat (doom-modeline-icon + 'octicon "file-directory" "πŸ–Ώ" "" + :face face :v-adjust -0.05 :height 1.25) + (doom-modeline-vspc))) + (doom-modeline--buffer-state-icon) + (propertize (abbreviate-file-name default-directory) 'face face)))) + +(doom-modeline-def-segment buffer-default-directory-simple + "Displays `default-directory'. This is for special buffers like the scratch +buffer where knowing the current project directory is important." + (let ((face (if (doom-modeline--active) 'doom-modeline-buffer-path 'mode-line-inactive))) + (concat (doom-modeline-spc) + (and doom-modeline-major-mode-icon + (concat (doom-modeline-icon + 'octicon "file-directory" "πŸ–Ώ" "" + :face face :v-adjust -0.05 :height 1.25) + (doom-modeline-vspc))) + (propertize (abbreviate-file-name default-directory) 'face face)))) + + +;; +;; Encoding +;; + +(doom-modeline-def-segment buffer-encoding + "Displays the eol and the encoding style of the buffer the same way Atom does." + (when doom-modeline-buffer-encoding + (let ((face (if (doom-modeline--active) 'mode-line 'mode-line-inactive)) + (mouse-face 'mode-line-highlight)) + (concat + (doom-modeline-spc) + + ;; eol type + (let ((eol (coding-system-eol-type buffer-file-coding-system))) + (when (or (eq doom-modeline-buffer-encoding t) + (and (eq doom-modeline-buffer-encoding 'nondefault) + (not (equal eol doom-modeline-default-eol-type)))) + (propertize + (pcase eol + (0 "LF ") + (1 "CRLF ") + (2 "CR ") + (_ "")) + 'face face + 'mouse-face mouse-face + 'help-echo (format "End-of-line style: %s\nmouse-1: Cycle" + (pcase eol + (0 "Unix-style LF") + (1 "DOS-style CRLF") + (2 "Mac-style CR") + (_ "Undecided"))) + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] 'mode-line-change-eol) + map)))) + + ;; coding system + (let* ((sys (coding-system-plist buffer-file-coding-system)) + (cat (plist-get sys :category)) + (sym (if (memq cat + '(coding-category-undecided coding-category-utf-8)) + 'utf-8 + (plist-get sys :name)))) + (when (or (eq doom-modeline-buffer-encoding t) + (and (eq doom-modeline-buffer-encoding 'nondefault) + (not (eq cat 'coding-category-undecided)) + (not (eq sym doom-modeline-default-coding-system)))) + (propertize + (upcase (symbol-name sym)) + 'face face + 'mouse-face mouse-face + 'help-echo 'mode-line-mule-info-help-echo + 'local-map mode-line-coding-system-map))) + + (doom-modeline-spc))))) + + +;; +;; Indentation +;; + +(doom-modeline-def-segment indent-info + "Displays the indentation information." + (when doom-modeline-indent-info + (let ((do-propertize + (lambda (mode size) + (propertize + (format " %s %d " mode size) + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive))))) + (if indent-tabs-mode + (funcall do-propertize "TAB" tab-width) + (let ((lookup-var + (seq-find (lambda (var) + (and var (boundp var) (symbol-value var))) + (cdr (assoc major-mode doom-modeline-indent-alist)) nil))) + (funcall do-propertize "SPC" + (if lookup-var + (symbol-value lookup-var) + tab-width))))))) + +;; +;; Remote host +;; + +(doom-modeline-def-segment remote-host + "Hostname for remote buffers." + (when default-directory + (when-let ((host (file-remote-p default-directory 'host))) + (propertize + (concat "@" host) + 'face (if (doom-modeline--active) 'doom-modeline-host 'mode-line-inactive))))) + + +;; +;; Major mode +;; + +(doom-modeline-def-segment major-mode + "The major mode, including environment and text-scale info." + (propertize + (concat + (doom-modeline-spc) + (propertize (format-mode-line + (or (and (boundp 'delighted-modes) + (cadr (assq major-mode delighted-modes))) + mode-name)) + 'help-echo "Major mode\n\ + mouse-1: Display major mode menu\n\ + mouse-2: Show help for major mode\n\ + mouse-3: Toggle minor modes" + 'mouse-face 'mode-line-highlight + 'local-map mode-line-major-mode-keymap) + (when (and doom-modeline-env-version doom-modeline-env--version) + (format " %s" doom-modeline-env--version)) + (and (boundp 'text-scale-mode-amount) + (/= text-scale-mode-amount 0) + (format + (if (> text-scale-mode-amount 0) + " (%+d)" + " (%-d)") + text-scale-mode-amount)) + (doom-modeline-spc)) + 'face (if (doom-modeline--active) + 'doom-modeline-buffer-major-mode + 'mode-line-inactive))) + + +;; +;; Process +;; + +(doom-modeline-def-segment process + "The process info." + (if (doom-modeline--active) + mode-line-process + (propertize (format-mode-line mode-line-process) + 'face 'mode-line-inactive))) + + +;; +;; Minor modes +;; + +(doom-modeline-def-segment minor-modes + (when doom-modeline-minor-modes + (let ((face (if (doom-modeline--active) + 'doom-modeline-buffer-minor-mode + 'mode-line-inactive)) + (mouse-face 'mode-line-highlight) + (help-echo "Minor mode + mouse-1: Display minor mode menu + mouse-2: Show help for minor mode + mouse-3: Toggle minor modes")) + (if (bound-and-true-p minions-mode) + `((:propertize ("" ,(--filter (memq (car it) minions-direct) + minor-mode-alist)) + face ,face + mouse-face ,mouse-face + help-echo ,help-echo + local-map ,mode-line-minor-mode-keymap) + ,(doom-modeline-spc) + (:propertize ("" ,(doom-modeline-icon 'octicon "gear" "βš™" + minions-mode-line-lighter + :face face :v-adjust -0.05)) + mouse-face ,mouse-face + help-echo "Minions +mouse-1: Display minor modes menu" + local-map ,minions-mode-line-minor-modes-map) + ,(doom-modeline-spc)) + `((:propertize ("" minor-mode-alist) + face ,face + mouse-face ,mouse-face + help-echo ,help-echo + local-map ,mode-line-minor-mode-keymap) + ,(doom-modeline-spc)))))) + + +;; +;; VCS +;; + +(defun doom-modeline-vcs-icon (icon &optional unicode text face voffset) + "Displays the vcs ICON with FACE and VOFFSET. + +UNICODE and TEXT are fallbacks. +Uses `all-the-icons-octicon' to fetch the icon." + (doom-modeline-icon 'octicon icon unicode text + :face face :v-adjust (or voffset -0.1))) + +(defvar-local doom-modeline--vcs-icon nil) +(defun doom-modeline-update-vcs-icon (&rest _) + "Update icon of vcs state in mode-line." + (setq doom-modeline--vcs-icon + (when (and vc-mode buffer-file-name) + (let* ((backend (vc-backend buffer-file-name)) + (state (vc-state (file-local-name buffer-file-name) backend))) + (cond ((memq state '(edited added)) + (doom-modeline-vcs-icon "git-compare" "⇆" "*" 'doom-modeline-info -0.05)) + ((eq state 'needs-merge) + (doom-modeline-vcs-icon "git-merge" "β›™" "?" 'doom-modeline-info)) + ((eq state 'needs-update) + (doom-modeline-vcs-icon "arrow-down" "↓" "!" 'doom-modeline-warning)) + ((memq state '(removed conflict unregistered)) + (doom-modeline-vcs-icon "alert" "⚠" "!" 'doom-modeline-urgent)) + (t + (doom-modeline-vcs-icon "git-branch" "ξ‚ " "@" 'doom-modeline-info -0.05))))))) +(add-hook 'find-file-hook #'doom-modeline-update-vcs-icon) +(add-hook 'after-save-hook #'doom-modeline-update-vcs-icon) +(advice-add #'vc-refresh-state :after #'doom-modeline-update-vcs-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-vcs-icon)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-vcs-icon)))))) + +(defvar-local doom-modeline--vcs-text nil) +(defun doom-modeline-update-vcs-text (&rest _) + "Update text of vcs state in mode-line." + (setq doom-modeline--vcs-text + (when (and vc-mode buffer-file-name) + (let* ((backend (vc-backend buffer-file-name)) + (state (vc-state (file-local-name buffer-file-name) backend)) + (str (if vc-display-status + (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)) + ""))) + (propertize (if (> (length str) doom-modeline-vcs-max-length) + (concat + (substring str 0 (- doom-modeline-vcs-max-length 3)) + "...") + str) + 'mouse-face 'mode-line-highlight + 'face (cond ((eq state 'needs-update) + 'doom-modeline-warning) + ((memq state '(removed conflict unregistered)) + 'doom-modeline-urgent) + (t 'doom-modeline-info))))))) +(add-hook 'find-file-hook #'doom-modeline-update-vcs-text) +(add-hook 'after-save-hook #'doom-modeline-update-vcs-text) +(advice-add #'vc-refresh-state :after #'doom-modeline-update-vcs-text) + +(doom-modeline-def-segment vcs + "Displays the current branch, colored based on its state." + (let ((active (doom-modeline--active))) + (when-let ((icon doom-modeline--vcs-icon) + (text doom-modeline--vcs-text)) + (concat + (doom-modeline-spc) + (propertize + (concat + (if active + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)) + (doom-modeline-vspc)) + 'mouse-face 'mode-line-highlight + 'help-echo (get-text-property 1 'help-echo vc-mode) + 'local-map (get-text-property 1 'local-map vc-mode)) + (if active + text + (propertize text 'face 'mode-line-inactive)) + (doom-modeline-spc))))) + + +;; +;; Checker +;; + +(defun doom-modeline-checker-icon (icon unicode text face) + "Displays the checker ICON with FACE. + +UNICODE and TEXT are fallbacks. +Uses `all-the-icons-material' to fetch the icon." + (doom-modeline-icon 'material icon unicode text + :face face :height 1.1 :v-adjust -0.225)) + +(defun doom-modeline-checker-text (text &optional face) + "Displays TEXT with FACE." + (propertize text 'face (or face 'mode-line))) + +;; Flycheck + +(defun doom-modeline--flycheck-count-errors () + "Count the number of ERRORS, grouped by level. + +Return an alist, where each ITEM is a cons cell whose `car' is an +error level, and whose `cdr' is the number of errors of that +level." + (let ((info 0) (warning 0) (error 0)) + (mapc + (lambda (item) + (let ((count (cdr item))) + (pcase (flycheck-error-level-compilation-level (car item)) + (0 (cl-incf info count)) + (1 (cl-incf warning count)) + (2 (cl-incf error count))))) + (flycheck-count-errors flycheck-current-errors)) + `((info . ,info) (warning . ,warning) (error . ,error)))) + +(defvar-local doom-modeline--flycheck-icon nil) +(defun doom-modeline-update-flycheck-icon (&optional status) + "Update flycheck icon via STATUS." + (setq doom-modeline--flycheck-icon + (when-let + ((icon + (pcase status + ('finished (if flycheck-current-errors + (let-alist (doom-modeline--flycheck-count-errors) + (doom-modeline-checker-icon + "block" "🚫" "!" + (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info)))) + (doom-modeline-checker-icon "check" "βœ“" "-" 'doom-modeline-info))) + ('running (doom-modeline-checker-icon "access_time" "⏱" "*" 'doom-modeline-debug)) + ('no-checker (doom-modeline-checker-icon "sim_card_alert" "⚠" "-" 'doom-modeline-debug)) + ('errored (doom-modeline-checker-icon "sim_card_alert" "⚠" "-" 'doom-modeline-urgent)) + ('interrupted (doom-modeline-checker-icon "pause" "⏸" "=" 'doom-modeline-debug)) + ('suspicious (doom-modeline-checker-icon "priority_high" "❗" "!" 'doom-modeline-urgent)) + (_ nil)))) + (propertize icon + 'help-echo (concat "Flycheck\n" + (pcase status + ('finished "mouse-1: Display minor mode menu +mouse-2: Show help for minor mode") + ('running "Running...") + ('no-checker "No Checker") + ('errored "Error") + ('interrupted "Interrupted") + ('suspicious "Suspicious"))) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line down-mouse-1] + flycheck-mode-menu-map) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'flycheck-mode))) + map))))) +(add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck-icon) +(add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flycheck-mode) + (flycheck-buffer))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flycheck-mode) + (flycheck-buffer))))))) + +(defvar-local doom-modeline--flycheck-text nil) +(defun doom-modeline-update-flycheck-text (&optional status) + "Update flycheck text via STATUS." + (setq doom-modeline--flycheck-text + (when-let + ((text + (pcase status + ('finished (when flycheck-current-errors + (let-alist (doom-modeline--flycheck-count-errors) + (if doom-modeline-checker-simple-format + (doom-modeline-checker-text + (number-to-string (+ .error .warning .info)) + (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info))) + (format "%s/%s/%s" + (doom-modeline-checker-text (number-to-string .error) + 'doom-modeline-urgent) + (doom-modeline-checker-text (number-to-string .warning) + 'doom-modeline-warning) + (doom-modeline-checker-text (number-to-string .info) + 'doom-modeline-info)))))) + ('running nil) + ('no-checker nil) + ('errored (doom-modeline-checker-text "Error" 'doom-modeline-urgent)) + ('interrupted (doom-modeline-checker-text "Interrupted" 'doom-modeline-debug)) + ('suspicious (doom-modeline-checker-text "Suspicious" 'doom-modeline-urgent)) + (_ nil)))) + (propertize + text + 'help-echo (pcase status + ('finished + (concat + (when flycheck-current-errors + (let-alist (doom-modeline--flycheck-count-errors) + (format "error: %d, warning: %d, info: %d\n" .error .warning .info))) + "mouse-1: Show all errors +mouse-3: Next error" + (if (featurep 'mwheel) + "\nwheel-up/wheel-down: Previous/next error"))) + ('running "Running...") + ('no-checker "No Checker") + ('errored "Error") + ('interrupted "Interrupted") + ('suspicious "Suspicious")) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'flycheck-list-errors) + (define-key map [mode-line mouse-3] + #'flycheck-next-error) + (when (featurep 'mwheel) + (define-key map [mode-line mouse-wheel-down-event] + (lambda (event) + (interactive "e") + (with-selected-window (posn-window (event-start event)) + (flycheck-previous-error 1)))) + (define-key map [mode-line mouse-wheel-up-event] + (lambda (event) + (interactive "e") + (with-selected-window (posn-window (event-start event)) + (flycheck-next-error 1)))) + map)))))) +(add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck-text) +(add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck-text) + +;; Flymake + +;; Compatibility +;; @see https://github.com/emacs-mirror/emacs/commit/6e100869012da9244679696634cab6b9cac96303. +(with-eval-after-load 'flymake + (unless (boundp 'flymake--state) + (defvaralias 'flymake--state 'flymake--backend-state)) + (unless (fboundp 'flymake--state-diags) + (defalias 'flymake--state-diags 'flymake--backend-state-diags))) + +(defvar-local doom-modeline--flymake-icon nil) +(defun doom-modeline-update-flymake-icon (&rest _) + "Update flymake icon." + (setq flymake--mode-line-format nil) ; remove the lighter of minor mode + (setq doom-modeline--flymake-icon + (let* ((known (hash-table-keys flymake--state)) + (running (flymake-running-backends)) + (disabled (flymake-disabled-backends)) + (reported (flymake-reporting-backends)) + (all-disabled (and disabled (null running))) + (some-waiting (cl-set-difference running reported))) + (when-let + ((icon + (cond + (some-waiting (doom-modeline-checker-icon "access_time" "⏰" "*" 'doom-modeline-debug)) + ((null known) (doom-modeline-checker-icon "sim_card_alert" "❓" "?" 'doom-modeline-debug)) + (all-disabled (doom-modeline-checker-icon "sim_card_alert" "❗" "!" 'doom-modeline-urgent)) + (t (let ((.error 0) + (.warning 0) + (.note 0)) + (progn + (cl-loop + with warning-level = (warning-numeric-level :warning) + with note-level = (warning-numeric-level :debug) + for state being the hash-values of flymake--state + do (cl-loop + with diags = (flymake--state-diags state) + for diag in diags do + (let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity + (warning-numeric-level :error)))) + (cond ((> severity warning-level) (cl-incf .error)) + ((> severity note-level) (cl-incf .warning)) + (t (cl-incf .note)))))) + (if (> (+ .error .warning .note) 0) + (doom-modeline-checker-icon "do_not_disturb_alt" "🚫" "!" + (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info))) + (doom-modeline-checker-icon "check" "βœ”" "-" 'doom-modeline-info)))))))) + (propertize + icon + 'help-echo (concat "Flymake\n" + (cond + (some-waiting "Running...") + ((null known) "No Checker") + (all-disabled "All Checkers Disabled") + (t (format "%d/%d backends running +mouse-1: Display minor mode menu +mouse-2: Show help for minor mode" + (length running) (length known))))) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line down-mouse-1] + flymake-menu) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'flymake-mode))) + map)))))) +(advice-add #'flymake--handle-report :after #'doom-modeline-update-flymake-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flymake-mode) + (flymake-start))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flymake-mode) + (flymake-start))))))) + +(defvar-local doom-modeline--flymake-text nil) +(defun doom-modeline-update-flymake-text (&rest _) + "Update flymake text." + (setq flymake--mode-line-format nil) ; remove the lighter of minor mode + (setq doom-modeline--flymake-text + (let* ((known (hash-table-keys flymake--state)) + (running (flymake-running-backends)) + (disabled (flymake-disabled-backends)) + (reported (flymake-reporting-backends)) + (all-disabled (and disabled (null running))) + (some-waiting (cl-set-difference running reported)) + (warning-level (warning-numeric-level :warning)) + (note-level (warning-numeric-level :debug)) + (.error 0) + (.warning 0) + (.note 0)) + (maphash (lambda (_b state) + (cl-loop + with diags = (flymake--state-diags state) + for diag in diags do + (let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity + (warning-numeric-level :error)))) + (cond ((> severity warning-level) (cl-incf .error)) + ((> severity note-level) (cl-incf .warning)) + (t (cl-incf .note)))))) + flymake--state) + (when-let + ((text + (cond + (some-waiting doom-modeline--flymake-text) + ((null known) nil) + (all-disabled nil) + (t (let ((num (+ .error .warning .note))) + (when (> num 0) + (if doom-modeline-checker-simple-format + (doom-modeline-checker-text (number-to-string num) + (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info))) + (format "%s/%s/%s" + (doom-modeline-checker-text (number-to-string .error) + 'doom-modeline-urgent) + (doom-modeline-checker-text (number-to-string .warning) + 'doom-modeline-warning) + (doom-modeline-checker-text (number-to-string .note) + 'doom-modeline-info))))))))) + (propertize + text + 'help-echo (cond + (some-waiting "Running...") + ((null known) "No Checker") + (all-disabled "All Checkers Disabled") + (t (format "error: %d, warning: %d, note: %d +mouse-1: List all problems%s" + .error .warning .note + (if (featurep 'mwheel) + "\nwheel-up/wheel-down: Previous/next problem")))) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'flymake-show-diagnostics-buffer) + (when (featurep 'mwheel) + (define-key map (vector 'mode-line + mouse-wheel-down-event) + (lambda (event) + (interactive "e") + (with-selected-window (posn-window (event-start event)) + (flymake-goto-prev-error 1 nil t)))) + (define-key map (vector 'mode-line + mouse-wheel-up-event) + (lambda (event) + (interactive "e") + (with-selected-window (posn-window (event-start event)) + (flymake-goto-next-error 1 nil t)))) + map))))))) +(advice-add #'flymake--handle-report :after #'doom-modeline-update-flymake-text) + +(doom-modeline-def-segment checker + "Displays color-coded error status in the current buffer with pretty icons." + (let ((active (doom-modeline--active)) + (seg (cond ((and (bound-and-true-p flymake-mode) + (bound-and-true-p flymake--state)) ; only support 26+ + `(,doom-modeline--flymake-icon . ,doom-modeline--flymake-text)) + ((bound-and-true-p flycheck-mode) + `(,doom-modeline--flycheck-icon . ,doom-modeline--flycheck-text))))) + (let ((icon (car seg)) + (text (cdr seg))) + (concat + (when icon + (concat + (doom-modeline-spc) + (if active + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)))) + (when text + (concat + (if icon (doom-modeline-vspc) (doom-modeline-spc)) + (if active + text + (propertize text 'face 'mode-line-inactive)))) + (doom-modeline-spc))))) + + +;; +;; Word Count +;; + +(doom-modeline-def-segment word-count + "The buffer word count. +Displayed when in a major mode in `doom-modeline-continuous-word-count-modes'. +Respects `doom-modeline-enable-word-count'." + (when (and doom-modeline-enable-word-count + (member major-mode doom-modeline-continuous-word-count-modes)) + (propertize (format " %dW" (count-words (point-min) (point-max))) + 'face (if (doom-modeline--active) + 'mode-line + 'mode-line-inactive)))) + + +;; +;; Selection +;; + +(defsubst doom-modeline-column (pos) + "Get the column of the position `POS'." + (save-excursion (goto-char pos) + (current-column))) + +(doom-modeline-def-segment selection-info + "Information about the current selection, such as how many characters and +lines are selected, or the NxM dimensions of a block selection." + (when (and (or mark-active (and (bound-and-true-p evil-local-mode) + (eq evil-state 'visual))) + (doom-modeline--active)) + (cl-destructuring-bind (beg . end) + (if (and (bound-and-true-p evil-local-mode) (eq evil-state 'visual)) + (cons evil-visual-beginning evil-visual-end) + (cons (region-beginning) (region-end))) + (propertize + (let ((lines (count-lines beg (min end (point-max))))) + (concat (doom-modeline-spc) + (cond ((or (bound-and-true-p rectangle-mark-mode) + (and (bound-and-true-p evil-visual-selection) + (eq 'block evil-visual-selection))) + (let ((cols (abs (- (doom-modeline-column end) + (doom-modeline-column beg))))) + (format "%dx%dB" lines cols))) + ((and (bound-and-true-p evil-visual-selection) + (eq evil-visual-selection 'line)) + (format "%dL" lines)) + ((> lines 1) + (format "%dC %dL" (- end beg) lines)) + (t + (format "%dC" (- end beg)))) + (when doom-modeline-enable-word-count + (format " %dW" (count-words beg end))) + (doom-modeline-spc))) + 'face 'doom-modeline-highlight)))) + + +;; +;; Matches (macro, anzu, evil-substitute, iedit, symbol-overlay and multi-cursors) +;; + +(defsubst doom-modeline--macro-recording () + "Display current Emacs or evil macro being recorded." + (when (and (doom-modeline--active) + (or defining-kbd-macro executing-kbd-macro)) + (let ((sep (propertize " " 'face 'doom-modeline-panel )) + (vsep (propertize " " 'face + '(:inherit (doom-modeline-panel variable-pitch))))) + (concat + sep + (doom-modeline-icon 'material "fiber_manual_record" "●" + (if (bound-and-true-p evil-this-macro) + (char-to-string evil-this-macro) + "Macro") + :face 'doom-modeline-panel + :v-adjust -0.225) + vsep + (doom-modeline-icon 'octicon "triangle-right" "β–Ά" ">" + :face 'doom-modeline-panel + :v-adjust -0.05) + sep)))) + +;; `anzu' and `evil-anzu' expose current/total state that can be displayed in the +;; mode-line. +(defun doom-modeline-fix-anzu-count (positions here) + "Calulate anzu count via POSITIONS and HERE." + (cl-loop for (start . end) in positions + collect t into before + when (and (>= here start) (<= here end)) + return (length before) + finally return 0)) + +(advice-add #'anzu--where-is-here :override #'doom-modeline-fix-anzu-count) + +(setq anzu-cons-mode-line-p nil) ; manage modeline segment ourselves +;; Ensure anzu state is cleared when searches & iedit are done +(with-eval-after-load 'anzu + (add-hook 'isearch-mode-end-hook #'anzu--reset-status t) + (add-hook 'iedit-mode-end-hook #'anzu--reset-status) + (advice-add #'evil-force-normal-state :after #'anzu--reset-status) + ;; Fix matches segment mirroring across all buffers + (mapc #'make-variable-buffer-local + '(anzu--total-matched + anzu--current-position anzu--state anzu--cached-count + anzu--cached-positions anzu--last-command + anzu--last-isearch-string anzu--overflow-p))) + +(defsubst doom-modeline--anzu () + "Show the match index and total number thereof. +Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with +`evil-search'." + (when (and (bound-and-true-p anzu--state) + (not (bound-and-true-p iedit-mode))) + (propertize + (let ((here anzu--current-position) + (total anzu--total-matched)) + (cond ((eq anzu--state 'replace-query) + (format " %d replace " anzu--cached-count)) + ((eq anzu--state 'replace) + (format " %d/%d " here total)) + (anzu--overflow-p + (format " %s+ " total)) + (t + (format " %s/%d " here total)))) + 'face (if (doom-modeline--active) 'doom-modeline-panel 'mode-line-inactive)))) + +(defsubst doom-modeline--evil-substitute () + "Show number of matches for evil-ex substitutions and highlights in real time." + (when (and (bound-and-true-p evil-local-mode) + (or (assq 'evil-ex-substitute evil-ex-active-highlights-alist) + (assq 'evil-ex-global-match evil-ex-active-highlights-alist) + (assq 'evil-ex-buffer-match evil-ex-active-highlights-alist))) + (propertize + (let ((range (if evil-ex-range + (cons (car evil-ex-range) (cadr evil-ex-range)) + (cons (line-beginning-position) (line-end-position)))) + (pattern (car-safe (evil-delimited-arguments evil-ex-argument 2)))) + (if pattern + (format " %s matches " (how-many pattern (car range) (cdr range))) + " - ")) + 'face (if (doom-modeline--active) 'doom-modeline-panel 'mode-line-inactive)))) + +(defun doom-modeline-themes--overlay-sort (a b) + "Sort overlay A and B." + (< (overlay-start a) (overlay-start b))) + +(defsubst doom-modeline--iedit () + "Show the number of iedit regions matches + what match you're on." + (when (and (bound-and-true-p iedit-mode) + (bound-and-true-p iedit-occurrences-overlays)) + (propertize + (let ((this-oc (or (let ((inhibit-message t)) + (iedit-find-current-occurrence-overlay)) + (save-excursion (iedit-prev-occurrence) + (iedit-find-current-occurrence-overlay)))) + (length (length iedit-occurrences-overlays))) + (format " %s/%d " + (if this-oc + (- length + (length (memq this-oc (sort (append iedit-occurrences-overlays nil) + #'doom-modeline-themes--overlay-sort))) + -1) + "-") + length)) + 'face (if (doom-modeline--active) 'doom-modeline-panel 'mode-line-inactive)))) + +(defsubst doom-modeline--symbol-overlay () + "Show the number of matches for symbol overlay." + (when-let ((active (doom-modeline--active))) + (when (and (bound-and-true-p symbol-overlay-keywords-alist) + (not (bound-and-true-p symbol-overlay-temp-symbol)) + (not (bound-and-true-p iedit-mode))) + (let* ((keyword (symbol-overlay-assoc (symbol-overlay-get-symbol t))) + (symbol (car keyword)) + (before (symbol-overlay-get-list -1 symbol)) + (after (symbol-overlay-get-list 1 symbol)) + (count (length before))) + (if (symbol-overlay-assoc symbol) + (propertize + (format (concat " %d/%d " (and (cadr keyword) "in scope ")) + (+ count 1) + (+ count (length after))) + 'face (if active 'doom-modeline-panel 'mode-line-inactive))))))) + +(defsubst doom-modeline--multiple-cursors () + "Show the number of multiple cursors." + (cl-destructuring-bind (count . face) + (cond ((bound-and-true-p multiple-cursors-mode) + (cons (mc/num-cursors) + (if (doom-modeline--active) + 'doom-modeline-panel + 'mode-line-inactive))) + ((bound-and-true-p evil-mc-cursor-list) + (cons (length evil-mc-cursor-list) + (cond ((not (doom-modeline--active)) 'mode-line-inactive) + (evil-mc-frozen 'doom-modeline-bar) + ('doom-modeline-panel)))) + ((cons nil nil))) + (when count + (concat (propertize " " 'face face) + (or (doom-modeline-icon 'faicon "i-cursor" nil nil + :face face :v-adjust -0.0575) + (propertize "I" + 'face `(:inherit ,face :height 1.4 :weight normal) + 'display '(raise -0.1))) + (propertize (doom-modeline-vspc) + 'face `(:inherit (variable-pitch ,face))) + (propertize (format "%d " count) + 'face face))))) + +(defsubst doom-modeline--phi-search () + "Show the number of matches for `phi-search' and `phi-replace'." + (when-let ((active (doom-modeline--active))) + (when (bound-and-true-p phi-search--overlays) + (let ((total (length phi-search--overlays)) + (selection phi-search--selection)) + (when selection + (propertize + (format " %d/%d " (1+ selection) total) + 'face (if active 'doom-modeline-panel 'mode-line-inactive))))))) + +(defun doom-modeline--override-phi-search-mode-line (orig-fun &rest args) + "Override the mode-line of `phi-search' and `phi-replace'." + (if (bound-and-true-p doom-modeline-mode) + (apply orig-fun mode-line-format (cdr args)) + (apply orig-fun args))) +(advice-add #'phi-search--initialize :around #'doom-modeline--override-phi-search-mode-line) + +(defsubst doom-modeline--buffer-size () + "Show buffer size." + (when size-indication-mode + (concat (doom-modeline-spc) + (propertize "%I" + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive) + 'help-echo "Buffer size +mouse-1: Display Line and Column Mode Menu" + 'mouse-face 'mode-line-highlight + 'local-map mode-line-column-line-number-mode-map) + (doom-modeline-spc)))) + +(doom-modeline-def-segment matches + "Displays: 1. the currently recording macro, 2. A current/total for the +current search term (with `anzu'), 3. The number of substitutions being +conducted with `evil-ex-substitute', and/or 4. The number of active `iedit' +regions, 5. The current/total for the highlight term (with `symbol-overlay'), +6. The number of active `multiple-cursors'." + (let ((meta (concat (doom-modeline--macro-recording) + (doom-modeline--anzu) + (doom-modeline--phi-search) + (doom-modeline--evil-substitute) + (doom-modeline--iedit) + (doom-modeline--symbol-overlay) + (doom-modeline--multiple-cursors)))) + (or (and (not (string-empty-p meta)) meta) + (doom-modeline--buffer-size)))) + +(doom-modeline-def-segment buffer-size + "Display buffer size." + (doom-modeline--buffer-size)) + +;; +;; Media +;; + +(doom-modeline-def-segment media-info + "Metadata regarding the current file, such as dimensions for images." + ;; TODO Include other information + (cond ((eq major-mode 'image-mode) + (cl-destructuring-bind (width . height) + (when (fboundp 'image-size) + (image-size (image-get-display-property) :pixels)) + (propertize + (format " %dx%d " width height) + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive)))))) + + +;; +;; Bars +;; + +(defvar doom-modeline--bar-active nil) +(defvar doom-modeline--bar-inactive nil) + +(defsubst doom-modeline--bar () + "The default bar regulates the height of the mode-line in GUI." + (unless (and doom-modeline--bar-active doom-modeline--bar-inactive) + (let ((width doom-modeline-bar-width) + (height (max doom-modeline-height + (doom-modeline--font-height)))) + (when (and (numberp width) (numberp height)) + (setq doom-modeline--bar-active + (doom-modeline--create-bar-image 'doom-modeline-bar width height) + doom-modeline--bar-inactive + (doom-modeline--create-bar-image + 'doom-modeline-bar-inactive width height))))) + (if (doom-modeline--active) + doom-modeline--bar-active + doom-modeline--bar-inactive)) + +(defun doom-modeline-refresh-bars () + "Refresh mode-line bars on next redraw." + (setq doom-modeline--bar-active nil + doom-modeline--bar-inactive nil)) + +(cl-defstruct doom-modeline--hud-cache active inactive top-margin bottom-margin) + +(defsubst doom-modeline--hud () + "Powerline's hud segment reimplemented in the style of Doom's bar segment." + (let* ((ws (window-start)) + (we (window-end)) + (bs (buffer-size)) + (height (max doom-modeline-height + (doom-modeline--font-height))) + (top-margin (if (zerop bs) + 0 + (/ (* height (1- ws)) bs))) + (bottom-margin (if (zerop bs) + 0 + (max 0 (/ (* height (- bs we 1)) bs)))) + (cache (or (window-parameter nil 'doom-modeline--hud-cache) + (set-window-parameter nil 'doom-modeline--hud-cache + (make-doom-modeline--hud-cache))))) + (unless (and (doom-modeline--hud-cache-active cache) + (doom-modeline--hud-cache-inactive cache) + (= top-margin (doom-modeline--hud-cache-top-margin cache)) + (= bottom-margin + (doom-modeline--hud-cache-bottom-margin cache))) + (setf (doom-modeline--hud-cache-active cache) + (doom-modeline--create-hud-image + 'doom-modeline-bar 'default doom-modeline-bar-width + height top-margin bottom-margin) + (doom-modeline--hud-cache-inactive cache) + (doom-modeline--create-hud-image + 'doom-modeline-bar-inactive 'default doom-modeline-bar-width + height top-margin bottom-margin) + (doom-modeline--hud-cache-top-margin cache) top-margin + (doom-modeline--hud-cache-bottom-margin cache) bottom-margin)) + (if (doom-modeline--active) + (doom-modeline--hud-cache-active cache) + (doom-modeline--hud-cache-inactive cache)))) + +(defun doom-modeline-invalidate-huds () + "Invalidate all cached hud images." + (dolist (frame (frame-list)) + (dolist (window (window-list frame)) + (set-window-parameter window 'doom-modeline--hud-cache nil)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-height + (lambda (_sym val op _where) + (when (and (eq op 'set) (integerp val)) + (doom-modeline-refresh-bars) + (doom-modeline-invalidate-huds)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-bar-width + (lambda (_sym val op _where) + (when (and (eq op 'set) (integerp val)) + (doom-modeline-refresh-bars) + (doom-modeline-invalidate-huds)))) + +(add-hook 'after-setting-font-hook #'doom-modeline-refresh-bars) +(add-hook 'after-setting-font-hook #'doom-modeline-invalidate-huds) + +(doom-modeline-def-segment bar + "The bar regulates the height of the mode-line in GUI." + (if doom-modeline-hud + (doom-modeline--hud) + (doom-modeline--bar))) + +(doom-modeline-def-segment hud + "Powerline's hud segment reimplemented in the style of Doom's bar segment." + (doom-modeline--hud)) + + +;; +;; Window number +;; + +;; HACK: `ace-window-display-mode' should respect the ignore buffers. +(defun doom-modeline-aw-update () + "Update ace-window-path window parameter for all windows. +Ensure all windows are labeled so the user can select a specific +one. The ignored buffers are excluded unless `aw-ignore-on' is nil." + (let ((ignore-window-parameters t)) + (avy-traverse + (avy-tree (aw-window-list) aw-keys) + (lambda (path leaf) + (set-window-parameter + leaf 'ace-window-path + (propertize + (apply #'string (reverse path)) + 'face 'aw-mode-line-face)))))) +(advice-add #'aw-update :override #'doom-modeline-aw-update) + +;; Remove original window number of `ace-window-display-mode'. +(add-hook 'ace-window-display-mode-hook + (lambda () + (setq-default mode-line-format + (assq-delete-all 'ace-window-display-mode + (default-value 'mode-line-format))))) + +(advice-add #'window-numbering-install-mode-line :override #'ignore) +(advice-add #'window-numbering-clear-mode-line :override #'ignore) +(advice-add #'winum--install-mode-line :override #'ignore) +(advice-add #'winum--clear-mode-line :override #'ignore) + +(doom-modeline-def-segment window-number + "The current window number." + (let ((num (cond + ((bound-and-true-p ace-window-display-mode) + (aw-update) + (window-parameter (selected-window) 'ace-window-path)) + ((bound-and-true-p winum-mode) + (setq winum-auto-setup-mode-line nil) + (winum-get-number-string)) + ((bound-and-true-p window-numbering-mode) + (window-numbering-get-number-string)) + (t "")))) + (if (and (< 0 (length num)) + (< 1 (length (cl-mapcan + (lambda (frame) + ;; Exclude minibuffer and child frames + (unless (and (fboundp 'frame-parent) + (frame-parent frame)) + (window-list frame 'never))) + (visible-frame-list))))) + (propertize (format " %s " num) + 'face (if (doom-modeline--active) + 'doom-modeline-buffer-major-mode + 'mode-line-inactive)) + (doom-modeline-spc)))) + + +;; +;; Workspace +;; + +(doom-modeline-def-segment workspace-name + "The current workspace name or number. +Requires `eyebrowse-mode' to be enabled or `tab-bar-mode' tabs to be created." + (when doom-modeline-workspace-name + (when-let + ((name (cond + ((and (bound-and-true-p eyebrowse-mode) + (< 1 (length (eyebrowse--get 'window-configs)))) + (assq-delete-all 'eyebrowse-mode mode-line-misc-info) + (when-let* + ((num (eyebrowse--get 'current-slot)) + (tag (nth 2 (assoc num (eyebrowse--get 'window-configs))))) + (if (< 0 (length tag)) tag (int-to-string num)))) + ((and (fboundp 'tab-bar-mode) + (< 1 (length (frame-parameter nil 'tabs)))) + (let* ((current-tab (tab-bar--current-tab)) + (tab-index (tab-bar--current-tab-index)) + (explicit-name (alist-get 'explicit-name current-tab)) + (tab-name (alist-get 'name current-tab))) + (if explicit-name tab-name (+ 1 tab-index))))))) + (propertize (format " %s " name) 'face + (if (doom-modeline--active) + 'doom-modeline-buffer-major-mode + 'mode-line-inactive))))) + + +;; +;; Perspective +;; + +(defvar-local doom-modeline--persp-name nil) +(defun doom-modeline-update-persp-name (&rest _) + "Update perspective name in mode-line." + (setq doom-modeline--persp-name + ;; Support `persp-mode', while not support `perspective' + (when (and doom-modeline-persp-name + (bound-and-true-p persp-mode) + (fboundp 'safe-persp-name) + (fboundp 'get-current-persp)) + (let* ((persp (get-current-persp)) + (name (safe-persp-name persp)) + (face (if (and persp + (not (persp-contain-buffer-p (current-buffer) persp))) + 'doom-modeline-persp-buffer-not-in-persp + 'doom-modeline-persp-name)) + (icon (doom-modeline-icon 'material "folder" "πŸ–Ώ" "#" + :face `(:inherit ,face :slant normal) + :height 1.1 + :v-adjust -0.225))) + (when (or doom-modeline-display-default-persp-name + (not (string-equal persp-nil-name name))) + (concat (doom-modeline-spc) + (propertize (concat (and doom-modeline-persp-icon + (concat icon (doom-modeline-vspc))) + (propertize name 'face face)) + 'help-echo "mouse-1: Switch perspective +mouse-2: Show help for minor mode" + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'persp-switch) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'persp-mode))) + map)) + (doom-modeline-spc))))))) + +(add-hook 'buffer-list-update-hook #'doom-modeline-update-persp-name) +(add-hook 'find-file-hook #'doom-modeline-update-persp-name) +(add-hook 'persp-activated-functions #'doom-modeline-update-persp-name) +(add-hook 'persp-renamed-functions #'doom-modeline-update-persp-name) +(advice-add #'lv-message :after #'doom-modeline-update-persp-name) + +(doom-modeline-def-segment persp-name + "The current perspective name." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p)) + doom-modeline--persp-name)) + + +;; +;; Misc info +;; + +(doom-modeline-def-segment misc-info + "Mode line construct for miscellaneous information. +By default, this shows the information specified by `global-mode-string'." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p)) + '("" mode-line-misc-info))) + + +;; +;; Position +;; + +;; Be compatible with Emacs 25. +(defvar doom-modeline-column-zero-based + (if (boundp 'column-number-indicator-zero-based) + column-number-indicator-zero-based + t) + "When non-nil, mode line displays column numbers zero-based. +See `column-number-indicator-zero-based'.") + +(defvar doom-modeline-percent-position + (if (boundp 'mode-line-percent-position) + mode-line-percent-position + '(-3 "%p")) + "Specification of \"percentage offset\" of window through buffer. +See `mode-line-percent-position'.") + +(doom-modeline-add-variable-watcher + 'column-number-indicator-zero-based + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-column-zero-based val)))) + +(doom-modeline-add-variable-watcher + 'mode-line-percent-position + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-percent-position val)))) + +(doom-modeline-def-segment buffer-position + "The buffer position information." + (let* ((active (doom-modeline--active)) + (lc '(line-number-mode + (column-number-mode + (doom-modeline-column-zero-based "%l:%c" "%l:%C") + "%l") + (column-number-mode (doom-modeline-column-zero-based ":%c" ":%C")))) + (face (if active 'mode-line 'mode-line-inactive)) + (mouse-face 'mode-line-highlight) + (local-map mode-line-column-line-number-mode-map)) + (concat + (doom-modeline-wspc) + + ;; Line and column + (propertize (format-mode-line lc) + 'face face + 'help-echo "Buffer position\n\ +mouse-1: Display Line and Column Mode Menu" + 'mouse-face mouse-face + 'local-map local-map) + + ;; Position + (cond ((and active + (bound-and-true-p nyan-mode) + (not doom-modeline--limited-width-p) + (>= (window-width) nyan-minimum-window-width)) + (concat + (doom-modeline-wspc) + (propertize (nyan-create) 'mouse-face mouse-face))) + ((and active + (bound-and-true-p poke-line-mode) + (not doom-modeline--limited-width-p) + (>= (window-width) poke-line-minimum-window-width)) + (concat + (doom-modeline-wspc) + (propertize (poke-line-create) 'mouse-face mouse-face))) + ((and active + (bound-and-true-p mlscroll-mode) + (not doom-modeline--limited-width-p) + (>= (window-width) mlscroll-minimum-current-width)) + (concat + (doom-modeline-wspc) + (let ((mlscroll-right-align nil)) + (format-mode-line (mlscroll-mode-line))))) + ((and active + (bound-and-true-p sml-modeline-mode) + (not doom-modeline--limited-width-p) + (>= (window-width) sml-modeline-len)) + (concat + (doom-modeline-wspc) + (propertize (sml-modeline-create) 'mouse-face mouse-face))) + (t "")) + + ;; Percent position + (when doom-modeline-percent-position + (concat + (doom-modeline-spc) + (propertize (format-mode-line '("" doom-modeline-percent-position "%%")) + 'face face + 'help-echo "Buffer percentage\n\ +mouse-1: Display Line and Column Mode Menu" + 'mouse-face mouse-face + 'local-map local-map))) + + (when (or line-number-mode column-number-mode doom-modeline-percent-position) + (doom-modeline-spc))))) + +;; +;; Party parrot +;; +(doom-modeline-def-segment parrot + "The party parrot animated icon. Requires `parrot-mode' to be enabled." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p) + (bound-and-true-p parrot-mode)) + (concat (doom-modeline-wspc) + (parrot-create) + (doom-modeline-spc)))) + +;; +;; Modals (evil, overwrite, god, ryo and xah-fly-keys, etc.) +;; + +(defun doom-modeline--modal-icon (text face help-echo) + "Display the model icon with FACE and HELP-ECHO. +TEXT is alternative if icon is not available." + (propertize (doom-modeline-icon + 'material + (when doom-modeline-modal-icon "fiber_manual_record") + "●" + text + :face (if (doom-modeline--active) face 'mode-line-inactive) + :v-adjust -0.225) + 'help-echo help-echo)) + +(defsubst doom-modeline--evil () + "The current evil state. Requires `evil-mode' to be enabled." + (when (bound-and-true-p evil-local-mode) + (doom-modeline--modal-icon + (let ((tag (evil-state-property evil-state :tag t))) + (if (stringp tag) tag (funcall tag))) + (cond + ((evil-normal-state-p) 'doom-modeline-evil-normal-state) + ((evil-emacs-state-p) 'doom-modeline-evil-emacs-state) + ((evil-insert-state-p) 'doom-modeline-evil-insert-state) + ((evil-motion-state-p) 'doom-modeline-evil-motion-state) + ((evil-visual-state-p) 'doom-modeline-evil-visual-state) + ((evil-operator-state-p) 'doom-modeline-evil-operator-state) + ((evil-replace-state-p) 'doom-modeline-evil-replace-state) + (t 'doom-modeline-evil-normal-state)) + (evil-state-property evil-state :name t)))) + +(defsubst doom-modeline--overwrite () + "The current overwrite state which is enabled by command `overwrite-mode'." + (when (and (bound-and-true-p overwrite-mode) + (not (bound-and-true-p evil-local-mode))) + (doom-modeline--modal-icon " " 'doom-modeline-urgent "Overwrite mode"))) + +(defsubst doom-modeline--god () + "The current god state which is enabled by the command `god-mode'." + (when (bound-and-true-p god-local-mode) + (doom-modeline--modal-icon " " 'doom-modeline-evil-normal-state "God mode"))) + +(defsubst doom-modeline--ryo () + "The current ryo-modal state which is enabled by the command `ryo-modal-mode'." + (when (bound-and-true-p ryo-modal-mode) + (doom-modeline--modal-icon "" 'doom-modeline-evil-normal-state "Ryo modal"))) + +(defsubst doom-modeline--xah-fly-keys () + "The current `xah-fly-keys' state." + (when (bound-and-true-p xah-fly-keys) + (if xah-fly-insert-state-p + (doom-modeline--modal-icon " " + 'doom-modeline-evil-insert-state + (format "Xah-fly insert mode")) + (doom-modeline--modal-icon " " + 'doom-modeline-evil-normal-state + (format "Xah-fly command mode"))))) + +(defsubst doom-modeline--boon () + "The current Boon state. Requires `boon-mode' to be enabled." + (when (bound-and-true-p boon-local-mode) + (doom-modeline--modal-icon + (boon-state-string) + (cond + (boon-command-state 'doom-modeline-evil-normal-state) + (boon-insert-state 'doom-modeline-evil-insert-state) + (boon-special-state 'doom-modeline-evil-emacs-state) + (boon-off-state 'doom-modeline-evil-operator-state) + (t 'doom-modeline-evil-operator-state)) + (boon-modeline-string)))) + +(defsubst doom-modeline--meow () + "The current Meow state. Requires `meow-mode' to be enabled." + (when (bound-and-true-p meow-mode) + meow--indicator)) + +(doom-modeline-def-segment modals + "Displays modal editing states, including `evil', `overwrite', `god', `ryo' +and `xha-fly-kyes', etc." + (let* ((evil (doom-modeline--evil)) + (ow (doom-modeline--overwrite)) + (god (doom-modeline--god)) + (ryo (doom-modeline--ryo)) + (xf (doom-modeline--xah-fly-keys)) + (boon (doom-modeline--boon)) + (vsep (doom-modeline-vspc)) + (meow (doom-modeline--meow)) + (sep (and (or evil ow god ryo xf boon) (doom-modeline-spc)))) + (concat sep + (and evil (concat evil (and (or ow god ryo xf boon meow) vsep))) + (and ow (concat ow (and (or god ryo xf boon meow) vsep))) + (and god (concat god (and (or ryo xf boon meow) vsep))) + (and ryo (concat ryo (and (or xf boon meow) vsep))) + (and xf (concat xf (and (or boon meow) vsep))) + (and boon (concat boon (and meow vsep))) + meow + sep))) + +;; +;; Objed state +;; + +(defvar doom-modeline--objed-active nil) + +(defun doom-modeline-update-objed (_ &optional reset) + "Update `objed' status, inactive when RESET is true." + (setq doom-modeline--objed-active (not reset))) + +(setq objed-modeline-setup-func #'doom-modeline-update-objed) + +(doom-modeline-def-segment objed-state () + "The current objed state." + (when (and doom-modeline--objed-active + (doom-modeline--active)) + (propertize (format " %s(%s) " + (symbol-name objed--object) + (char-to-string (aref (symbol-name objed--obj-state) 0))) + 'face 'doom-modeline-evil-emacs-state + 'help-echo (format "Objed object: %s (%s)" + (symbol-name objed--object) + (symbol-name objed--obj-state))))) + + +;; +;; Input method +;; + +(doom-modeline-def-segment input-method + "The current input method." + (propertize (cond (current-input-method + (concat (doom-modeline-spc) + current-input-method-title + (doom-modeline-spc))) + ((and (bound-and-true-p evil-local-mode) + (bound-and-true-p evil-input-method)) + (concat + (doom-modeline-spc) + (nth 3 (assoc default-input-method input-method-alist)) + (doom-modeline-spc))) + (t "")) + 'face (if (doom-modeline--active) + (if (and (bound-and-true-p rime-mode) + (equal current-input-method "rime")) + (if (and (rime--should-enable-p) + (not (rime--should-inline-ascii-p))) + 'doom-modeline-input-method + 'doom-modeline-input-method-alt) + 'doom-modeline-input-method) + 'mode-line-inactive) + 'help-echo (concat + "Current input method: " + current-input-method + "\n\ +mouse-2: Disable input method\n\ +mouse-3: Describe current input method") + 'mouse-face 'mode-line-highlight + 'local-map mode-line-input-method-map)) + + +;; +;; Info +;; + +(doom-modeline-def-segment info-nodes + "The topic and nodes in the Info buffer." + (let ((active (doom-modeline--active))) + (concat + (propertize " (" 'face (if active 'mode-line 'mode-line-inactive)) + ;; topic + (propertize (if (stringp Info-current-file) + (replace-regexp-in-string + "%" "%%" + (file-name-sans-extension + (file-name-nondirectory Info-current-file))) + (format "*%S*" Info-current-file)) + 'face (if active 'doom-modeline-info 'mode-line-inactive)) + (propertize ") " 'face (if active 'mode-line 'mode-line-inactive)) + ;; node + (when Info-current-node + (propertize (replace-regexp-in-string + "%" "%%" Info-current-node) + 'face (if active 'doom-modeline-buffer-path 'mode-line-inactive) + 'help-echo + "mouse-1: scroll forward, mouse-3: scroll back" + 'mouse-face 'mode-line-highlight + 'local-map Info-mode-line-node-keymap))))) + + +;; +;; REPL +;; + +(defun doom-modeline-repl-icon (text face) + "Display REPL icon (or TEXT in terminal) with FACE." + (doom-modeline-icon 'faicon "terminal" "$" text + :face face :height 1.0 :v-adjust -0.0575)) + +(defvar doom-modeline--cider nil) + +(defun doom-modeline-update-cider () + "Update cider repl state." + (setq doom-modeline--cider + (let* ((connected (cider-connected-p)) + (face (if connected 'doom-modeline-repl-success 'doom-modeline-repl-warning)) + (repl-buffer (cider-current-repl nil nil)) + (cider-info (when repl-buffer + (cider--connection-info repl-buffer t))) + (icon (doom-modeline-repl-icon "REPL" face))) + (propertize icon + 'help-echo + (if connected + (format "CIDER Connected %s\nmouse-2: CIDER quit" cider-info) + "CIDER Disconnected\nmouse-1: CIDER jack-in") + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (if connected + (define-key map [mode-line mouse-2] + #'cider-quit) + (define-key map [mode-line mouse-1] + #'cider-jack-in)) + map))))) + +(add-hook 'cider-connected-hook #'doom-modeline-update-cider) +(add-hook 'cider-disconnected-hook #'doom-modeline-update-cider) +(add-hook 'cider-mode-hook #'doom-modeline-update-cider) + +(doom-modeline-def-segment repl + "The REPL state." + (when doom-modeline-repl + (when-let (icon (when (bound-and-true-p cider-mode) + doom-modeline--cider)) + (concat + (doom-modeline-spc) + (if (doom-modeline--active) + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)) + (doom-modeline-spc))))) + + +;; +;; LSP +;; + +(defun doom-modeline-lsp-icon (text face) + "Display LSP icon (or TEXT in terminal) with FACE." + (doom-modeline-icon 'faicon "rocket" "πŸš€" text + :face face :height 1.0 :v-adjust -0.0575)) + +(defvar-local doom-modeline--lsp nil) +(defun doom-modeline-update-lsp (&rest _) + "Update `lsp-mode' state." + (setq doom-modeline--lsp + (let* ((workspaces (lsp-workspaces)) + (face (if workspaces 'doom-modeline-lsp-success 'doom-modeline-lsp-warning)) + (icon (doom-modeline-lsp-icon "LSP" face))) + (propertize icon + 'help-echo + (if workspaces + (concat "LSP Connected " + (string-join + (mapcar (lambda (w) + (format "[%s]\n" (lsp--workspace-print w))) + workspaces)) + "C-mouse-1: Switch to another workspace folder +mouse-1: Describe current session +mouse-2: Quit server +mouse-3: Reconnect to server") + "LSP Disconnected +mouse-1: Reload to start server") + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (if workspaces + (progn + (define-key map [mode-line C-mouse-1] + #'lsp-workspace-folders-open) + (define-key map [mode-line mouse-1] + #'lsp-describe-session) + (define-key map [mode-line mouse-2] + #'lsp-workspace-shutdown) + (define-key map [mode-line mouse-3] + #'lsp-workspace-restart)) + (progn + (define-key map [mode-line mouse-1] + (lambda () + (interactive) + (ignore-errors (revert-buffer t t)))))) + map))))) +(add-hook 'lsp-before-initialize-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-initialize-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-uninitialized-functions #'doom-modeline-update-lsp) +(add-hook 'lsp-before-open-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-open-hook #'doom-modeline-update-lsp) + +(defvar-local doom-modeline--eglot nil) +(defun doom-modeline-update-eglot () + "Update `eglot' state." + (setq doom-modeline--eglot + (pcase-let* ((server (and (eglot-managed-p) (eglot-current-server))) + (nick (and server (eglot--project-nickname server))) + (pending (and server (hash-table-count + (jsonrpc--request-continuations server)))) + (`(,_id ,doing ,done-p ,detail) (and server (eglot--spinner server))) + (last-error (and server (jsonrpc-last-error server))) + (face (cond (last-error 'doom-modeline-lsp-error) + ((and doing (not done-p)) 'doom-modeline-lsp-running) + ((and pending (cl-plusp pending)) 'doom-modeline-lsp-warning) + (nick 'doom-modeline-lsp-success) + (t 'doom-modeline-lsp-warning))) + (icon (doom-modeline-lsp-icon "EGLOT" face))) + (propertize icon + 'help-echo (cond + (last-error + (format "EGLOT\nAn error occured: %s +mouse-3: Clear this status" (plist-get last-error :message))) + ((and doing (not done-p)) + (format "EGLOT\n%s%s" doing + (if detail (format "%s" detail) ""))) + ((and pending (cl-plusp pending)) + (format "EGLOT\n%d outstanding requests" pending)) + (nick (format "EGLOT Connected (%s/%s) +C-mouse-1: Go to server errors +mouse-1: Go to server events +mouse-2: Quit server +mouse-3: Reconnect to server" nick (eglot--major-mode server))) + (t "EGLOT Disconnected +mouse-1: Start server")) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (cond (last-error + (define-key map [mode-line mouse-3] + #'eglot-clear-status)) + ((and pending (cl-plusp pending)) + (define-key map [mode-line mouse-3] + #'eglot-forget-pending-continuations)) + (nick + (define-key map [mode-line C-mouse-1] + #'eglot-stderr-buffer) + (define-key map [mode-line mouse-1] + #'eglot-events-buffer) + (define-key map [mode-line mouse-2] + #'eglot-shutdown) + (define-key map [mode-line mouse-3] + #'eglot-reconnect)) + (t (define-key map [mode-line mouse-1] + #'eglot))) + map))))) +(add-hook 'eglot-managed-mode-hook #'doom-modeline-update-eglot) + +(defvar-local doom-modeline--tags nil) +(defun doom-modeline-update-tags () + "Update tags state." + (setq doom-modeline--tags + (propertize + (doom-modeline-lsp-icon "LSP" 'doom-modeline-lsp-success) + 'help-echo "TAGS: Citre mode +mouse-1: Toggle citre mode" + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'citre-mode)))) +(add-hook 'citre-mode-hook #'doom-modeline-update-tags) + +(defun doom-modeline-update-lsp-icon () + "Update lsp icon." + (cond ((bound-and-true-p lsp-mode) + (doom-modeline-update-lsp)) + ((bound-and-true-p eglot--managed-mode) + (doom-modeline-update-eglot)) + ((bound-and-true-p citre-mode) + (doom-modeline-update-tags)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-lsp-icon)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-lsp-icon)))))) + +(doom-modeline-def-segment lsp + "The LSP server state." + (when (and doom-modeline-lsp + (not doom-modeline--limited-width-p)) + (let ((active (doom-modeline--active)) + (icon (cond ((bound-and-true-p lsp-mode) + doom-modeline--lsp) + ((bound-and-true-p eglot--managed-mode) + doom-modeline--eglot) + ((bound-and-true-p citre-mode) + doom-modeline--tags)))) + (when icon + (concat + (doom-modeline-spc) + (if active + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive)) + (doom-modeline-spc)))))) + +(defun doom-modeline-override-eglot-modeline () + "Override `eglot' mode-line." + (if (bound-and-true-p doom-modeline-mode) + (setq mode-line-misc-info + (delq (assq 'eglot--managed-mode mode-line-misc-info) mode-line-misc-info)) + (add-to-list 'mode-line-misc-info + `(eglot--managed-mode (" [" eglot--mode-line-format "] "))))) +(add-hook 'eglot-managed-mode-hook #'doom-modeline-override-eglot-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-eglot-modeline) + + +;; +;; GitHub +;; + +(defvar doom-modeline--github-notification-number 0) +(defvar doom-modeline-before-github-fetch-notification-hook nil + "Hooks before fetching GitHub notifications. +Example: + (add-hook 'doom-modeline-before-github-fetch-notification-hook + #'auth-source-pass-enable)") +(defun doom-modeline--github-fetch-notifications () + "Fetch GitHub notifications." + (when (and doom-modeline-github + (require 'async nil t)) + (async-start + `(lambda () + ,(async-inject-variables + "\\`\\(load-path\\|auth-sources\\|doom-modeline-before-github-fetch-notification-hook\\)\\'") + (run-hooks 'doom-modeline-before-github-fetch-notification-hook) + (when (require 'ghub nil t) + (with-timeout (10) + (ignore-errors + (when-let* ((username (ghub--username ghub-default-host)) + (token (ghub--token ghub-default-host username 'ghub t))) + (ghub-get "/notifications" nil + :query '((notifications . "true")) + :username username + :auth token + :noerror t)))))) + (lambda (result) + (message "") ; suppress message + (setq doom-modeline--github-notification-number (length result)))))) + +(defvar doom-modeline--github-timer nil) +(defun doom-modeline-github-timer () + "Start/Stop the timer for GitHub fetching." + (if (timerp doom-modeline--github-timer) + (cancel-timer doom-modeline--github-timer)) + (setq doom-modeline--github-timer + (and doom-modeline-github + (run-with-idle-timer 30 + doom-modeline-github-interval + #'doom-modeline--github-fetch-notifications)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-github + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-github val) + (doom-modeline-github-timer)))) + +(doom-modeline-github-timer) + +(doom-modeline-def-segment github + "The GitHub notifications." + (when (and doom-modeline-github + (doom-modeline--active) + (not doom-modeline--limited-width-p) + (numberp doom-modeline--github-notification-number) + (> doom-modeline--github-notification-number 0)) + (concat + (doom-modeline-spc) + (propertize + (concat + (doom-modeline-icon 'faicon "github" "πŸ””" "#" + :face 'doom-modeline-notification + :v-adjust -0.0575) + (doom-modeline-vspc) + ;; GitHub API is paged, and the limit is 50 + (propertize + (if (>= doom-modeline--github-notification-number 50) + "50+" + (number-to-string doom-modeline--github-notification-number)) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'help-echo "Github Notifications +mouse-1: Show notifications +mouse-3: Fetch notifications" + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + (lambda () + "Open GitHub notifications page." + (interactive) + (run-with-idle-timer 300 nil #'doom-modeline--github-fetch-notifications) + (browse-url "https://github.com/notifications"))) + (define-key map [mode-line mouse-3] + (lambda () + "Fetching GitHub notifications." + (interactive) + (message "Fetching GitHub notifications...") + (doom-modeline--github-fetch-notifications))) + map)) + (doom-modeline-spc)))) + + +;; +;; Debug states +;; + +;; Highlight the mode-line while debugging. +(defvar-local doom-modeline--debug-cookie nil) +(defun doom-modeline--debug-visual (&rest _) + "Update the face of mode-line for debugging." + (mapc (lambda (buffer) + (with-current-buffer buffer + (setq doom-modeline--debug-cookie + (face-remap-add-relative 'mode-line 'doom-modeline-debug-visual)) + (force-mode-line-update))) + (buffer-list))) + +(defun doom-modeline--normal-visual (&rest _) + "Restore the face of mode-line." + (mapc (lambda (buffer) + (with-current-buffer buffer + (when doom-modeline--debug-cookie + (face-remap-remove-relative doom-modeline--debug-cookie) + (force-mode-line-update)))) + (buffer-list))) + +(add-hook 'dap-session-created-hook #'doom-modeline--debug-visual) +(add-hook 'dap-terminated-hook #'doom-modeline--normal-visual) + +(defun doom-modeline-debug-icon (face &rest args) + "Display debug icon with FACE and ARGS." + (doom-modeline-icon 'faicon "bug" "πŸ›" "!" :face face :v-adjust -0.0575 args)) + +(defun doom-modeline--debug-dap () + "The current `dap-mode' state." + (when (and (bound-and-true-p dap-mode) + (bound-and-true-p lsp-mode)) + (when-let ((session (dap--cur-session))) + (when (dap--session-running session) + (propertize (doom-modeline-debug-icon 'doom-modeline-info) + 'help-echo (format "DAP (%s - %s) +mouse-1: Display debug hydra +mouse-2: Display recent configurations +mouse-3: Disconnect session" + (dap--debug-session-name session) + (dap--debug-session-state session)) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'dap-hydra) + (define-key map [mode-line mouse-2] + #'dap-debug-recent) + (define-key map [mode-line mouse-3] + #'dap-disconnect) + map)))))) + +(defvar-local doom-modeline--debug-dap nil) +(defun doom-modeline-update-debug-dap (&rest _) + "Update dap debug state." + (setq doom-modeline--debug-dap (doom-modeline--debug-dap))) + +(add-hook 'dap-session-created-hook #'doom-modeline-update-debug-dap) +(add-hook 'dap-session-changed-hook #'doom-modeline-update-debug-dap) +(add-hook 'dap-terminated-hook #'doom-modeline-update-debug-dap) + +(defsubst doom-modeline--debug-edebug () + "The current `edebug' state." + (when (bound-and-true-p edebug-mode) + (propertize (doom-modeline-debug-icon 'doom-modeline-info) + 'help-echo (format "EDebug (%s) +mouse-1: Show help +mouse-2: Next +mouse-3: Stop debugging" + edebug-execution-mode) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'edebug-help) + (define-key map [mode-line mouse-2] + #'edebug-next-mode) + (define-key map [mode-line mouse-3] + #'edebug-stop) + map)))) + +(defsubst doom-modeline--debug-on-error () + "The current `debug-on-error' state." + (when debug-on-error + (propertize (doom-modeline-debug-icon 'doom-modeline-urgent) + 'help-echo "Debug on Error +mouse-1: Toggle Debug on Error" + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-error)))) + +(defsubst doom-modeline--debug-on-quit () + "The current `debug-on-quit' state." + (when debug-on-quit + (propertize (doom-modeline-debug-icon 'doom-modeline-warning) + 'help-echo "Debug on Quit +mouse-1: Toggle Debug on Quit" + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-quit)))) + +(doom-modeline-def-segment debug + "The current debug state." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p)) + (let* ((dap doom-modeline--debug-dap) + (edebug (doom-modeline--debug-edebug)) + (on-error (doom-modeline--debug-on-error)) + (on-quit (doom-modeline--debug-on-quit)) + (vsep (doom-modeline-vspc)) + (sep (and (or dap edebug on-error on-quit) (doom-modeline-spc)))) + (concat sep + (and dap (concat dap (and (or edebug on-error on-quit) vsep))) + (and edebug (concat edebug (and (or on-error on-quit) vsep))) + (and on-error (concat on-error (and on-quit vsep))) + on-quit + sep)))) + + +;; +;; PDF pages +;; + +(defvar-local doom-modeline--pdf-pages nil) +(defun doom-modeline-update-pdf-pages () + "Update PDF pages." + (setq doom-modeline--pdf-pages + (format " P%d/%d " + (or (eval `(pdf-view-current-page)) 0) + (pdf-cache-number-of-pages)))) +(add-hook 'pdf-view-change-page-hook #'doom-modeline-update-pdf-pages) + +(doom-modeline-def-segment pdf-pages + "Display PDF pages." + (propertize doom-modeline--pdf-pages + 'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive))) + + +;; +;; `mu4e-alert' notifications +;; + +(doom-modeline-def-segment mu4e + "Show notifications of any unread emails in `mu4e'." + (when (and doom-modeline-mu4e + (doom-modeline--active) + (not doom-modeline--limited-width-p) + (bound-and-true-p mu4e-alert-mode-line) + (numberp mu4e-alert-mode-line) + ;; don't display if the unread mails count is zero + (> mu4e-alert-mode-line 0)) + (concat + (doom-modeline-spc) + (propertize + (concat + (doom-modeline-icon 'material "email" "πŸ“§" "#" + :face 'doom-modeline-notification + :height 1.1 :v-adjust -0.2) + (doom-modeline-vspc) + (propertize + (if (> mu4e-alert-mode-line doom-modeline-number-limit) + (format "%d+" doom-modeline-number-limit) + (number-to-string mu4e-alert-mode-line)) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'mouse-face 'mode-line-highlight + 'keymap '(mode-line keymap + (mouse-1 . mu4e-alert-view-unread-mails) + (mouse-2 . mu4e-alert-view-unread-mails) + (mouse-3 . mu4e-alert-view-unread-mails)) + 'help-echo (concat (if (= mu4e-alert-mode-line 1) + "You have an unread email" + (format "You have %s unread emails" mu4e-alert-mode-line)) + "\nClick here to view " + (if (= mu4e-alert-mode-line 1) "it" "them"))) + (doom-modeline-spc)))) + +(defun doom-modeline-override-mu4e-alert-modeline (&rest _) + "Delete `mu4e-alert-mode-line' from global modeline string." + (when (featurep 'mu4e-alert) + (if (and doom-modeline-mu4e + (bound-and-true-p doom-modeline-mode)) + ;; Delete original modeline + (progn + (setq global-mode-string + (delete '(:eval mu4e-alert-mode-line) global-mode-string)) + (setq mu4e-alert-modeline-formatter #'identity)) + ;; Recover default settings + (setq mu4e-alert-modeline-formatter #'mu4e-alert-default-mode-line-formatter)))) +(advice-add #'mu4e-alert-enable-mode-line-display + :after #'doom-modeline-override-mu4e-alert-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-alert-modeline) + + +;; +;; `gnus' notifications +;; + +(defvar doom-modeline--gnus-unread-mail 0) +(defvar doom-modeline--gnus-started nil + "Used to determine if gnus has started.") +(defun doom-modeline-update-gnus-status (&rest _) + "Get the total number of unread news of gnus group." + (setq doom-modeline--gnus-unread-mail + (when (and doom-modeline-gnus + doom-modeline--gnus-started) + (let ((total-unread-news-number 0)) + (mapc (lambda (g) + (let* ((group (car g)) + (unread (eval `(gnus-group-unread ,group)))) + (when (and (not (seq-contains-p doom-modeline-gnus-excluded-groups group)) + (numberp unread) + (> unread 0)) + (setq total-unread-news-number (+ total-unread-news-number unread))))) + gnus-newsrc-alist) + total-unread-news-number)))) + +;; Update the modeline after changes have been made +(add-hook 'gnus-group-update-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-summary-update-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-group-update-group-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-after-getting-new-news-hook #'doom-modeline-update-gnus-status) + +;; Only start to listen to gnus when gnus is actually running +(defun doom-modeline-start-gnus-listener () + "Start GNUS listener." + (when (and doom-modeline-gnus + (not doom-modeline--gnus-started)) + (setq doom-modeline--gnus-started t) + ;; Scan gnus in the background if the timer is higher than 0 + (doom-modeline-update-gnus-status) + (if (> doom-modeline-gnus-timer 0) + (gnus-demon-add-handler 'gnus-demon-scan-news doom-modeline-gnus-timer doom-modeline-gnus-idle)))) +(add-hook 'gnus-started-hook #'doom-modeline-start-gnus-listener) + +;; Stop the listener if gnus isn't running +(defun doom-modeline-stop-gnus-listener () + "Stop GNUS listener." + (setq doom-modeline--gnus-started nil)) +(add-hook 'gnus-exit-gnus-hook #'doom-modeline-stop-gnus-listener) + +(doom-modeline-def-segment gnus + "Show notifications of any unread emails in `gnus'." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p) + doom-modeline-gnus + doom-modeline--gnus-started + ;; Don't display if the unread mails count is zero + (numberp doom-modeline--gnus-unread-mail) + (> doom-modeline--gnus-unread-mail 0)) + (concat + (doom-modeline-spc) + (propertize + (concat + (doom-modeline-icon 'material "email" "πŸ“§" "#" + :face 'doom-modeline-notification + :height 1.1 :v-adjust -0.2) + (doom-modeline-vspc) + (propertize + (if (> doom-modeline--gnus-unread-mail doom-modeline-number-limit) + (format "%d+" doom-modeline-number-limit) + (number-to-string doom-modeline--gnus-unread-mail)) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'mouse-face 'mode-line-highlight + 'help-echo (if (= doom-modeline--gnus-unread-mail 1) + "You have an unread email" + (format "You have %s unread emails" doom-modeline--gnus-unread-mail))) + (doom-modeline-spc)))) + + +;; +;; IRC notifications +;; + +(defun doom-modeline--shorten-irc (name) + "Wrapper for `tracking-shorten' and `erc-track-shorten-function' with NAME. + +One key difference is that when `tracking-shorten' and +`erc-track-shorten-function' returns nil we will instead return the original +value of name. This is necessary in cases where the user has stylized the name +to be an icon and we don't want to remove that so we just return the original." + (or (and (boundp 'tracking-shorten) + (car (tracking-shorten (list name)))) + (and (boundp 'erc-track-shorten-function) + (functionp erc-track-shorten-function) + (car (funcall erc-track-shorten-function (list name)))) + (and (boundp 'rcirc-short-buffer-name) + (rcirc-short-buffer-name name)) + name)) + +(defun doom-modeline--tracking-buffers (buffers) + "Logic to convert some irc BUFFERS to their font-awesome icon." + (mapconcat + (lambda (b) + (propertize + (doom-modeline--shorten-irc (funcall doom-modeline-irc-stylize b)) + 'face '(:inherit (doom-modeline-unread-number doom-modeline-notification)) + 'help-echo (format "IRC Notification: %s\nmouse-1: Switch to buffer" b) + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 + (lambda () + (interactive) + (when (buffer-live-p (get-buffer b)) + (switch-to-buffer b)))))) + buffers + (doom-modeline-vspc))) + +(defun doom-modeline--circe-p () + "Check if `circe' is in use." + (boundp 'tracking-mode-line-buffers)) + +(defun doom-modeline--erc-p () + "Check if `erc' is in use." + (boundp 'erc-modified-channels-alist)) + +(defun doom-modeline--rcirc-p () + "Check if `rcirc' is in use." + (bound-and-true-p rcirc-track-minor-mode)) + +(defun doom-modeline--get-buffers () + "Gets the buffers that have activity." + (cond + ((doom-modeline--circe-p) + tracking-buffers) + ((doom-modeline--erc-p) + (mapcar (lambda (l) + (buffer-name (car l))) + erc-modified-channels-alist)) + ((doom-modeline--rcirc-p) + (mapcar (lambda (b) + (buffer-name b)) + rcirc-activity)))) + +;; Create a modeline segment that contains all the irc tracked buffers +(doom-modeline-def-segment irc-buffers + "The list of shortened, unread irc buffers." + (when (and doom-modeline-irc + (doom-modeline--active) + (not doom-modeline--limited-width-p)) + (let* ((buffers (doom-modeline--get-buffers)) + (number (length buffers))) + (when (> number 0) + (concat + (doom-modeline-spc) + (doom-modeline--tracking-buffers buffers) + (doom-modeline-spc)))))) + +(doom-modeline-def-segment irc + "A notification icon for any unread irc buffer." + (when (and doom-modeline-irc + (doom-modeline--active) + (not doom-modeline--limited-width-p)) + (let* ((buffers (doom-modeline--get-buffers)) + (number (length buffers))) + (when (> number 0) + (concat + (doom-modeline-spc) + + (propertize (concat + (doom-modeline-icon 'material "message" "πŸ—Š" "#" + :face 'doom-modeline-notification + :height 1.0 :v-adjust -0.225) + (doom-modeline-vspc) + ;; Display the number of unread buffers + (propertize (number-to-string number) + 'face '(:inherit + (doom-modeline-unread-number + doom-modeline-notification)))) + 'help-echo (format "IRC Notifications: %s\n%s" + (mapconcat + (lambda (b) (funcall doom-modeline-irc-stylize b)) + buffers + ", ") + (cond + ((doom-modeline--circe-p) + "mouse-1: Switch to previous unread buffer +mouse-3: Switch to next unread buffer") + ((doom-modeline--erc-p) + "mouse-1: Switch to buffer +mouse-3: Switch to next unread buffer") + ((doom-modeline--rcirc-p) + "mouse-1: Switch to server buffer +mouse-3: Switch to next unread buffer"))) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (cond + ((doom-modeline--circe-p) + (define-key map [mode-line mouse-1] + #'tracking-previous-buffer) + (define-key map [mode-line mouse-3] + #'tracking-next-buffer)) + ((doom-modeline--erc-p) + (define-key map [mode-line mouse-1] + #'erc-switch-to-buffer) + (define-key map [mode-line mouse-3] + #'erc-track-switch-buffer)) + ((doom-modeline--rcirc-p) + (define-key map [mode-line mouse-1] + #'rcirc-switch-to-server-buffer) + (define-key map [mode-line mouse-3] + #'rcirc-next-active-buffer))) + map)) + + ;; Display the unread irc buffers as well + (when doom-modeline-irc-buffers + (concat (doom-modeline-spc) + (doom-modeline--tracking-buffers buffers))) + + (doom-modeline-spc)))))) + +(defun doom-modeline-override-rcirc-modeline () + "Override default `rcirc' mode-line." + (if (bound-and-true-p doom-modeline-mode) + (setq global-mode-string + (delq 'rcirc-activity-string global-mode-string)) + (when (and rcirc-track-minor-mode + (not (memq 'rcirc-activity-string global-mode-string))) + (setq global-mode-string + (append global-mode-string '(rcirc-activity-string)))))) +(add-hook 'rcirc-track-minor-mode-hook #'doom-modeline-override-rcirc-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-rcirc-modeline) + + +;; +;; Battery status +;; + +(defvar doom-modeline--battery-status nil) +(defun doom-modeline-update-battery-status () + "Update battery status." + (setq doom-modeline--battery-status + (when (bound-and-true-p display-battery-mode) + (let* ((data (and battery-status-function + (functionp battery-status-function) + (funcall battery-status-function))) + (charging? (string-equal "AC" (cdr (assoc ?L data)))) + (percentage (car (read-from-string (or (cdr (assq ?p data)) "ERR")))) + (valid-percentage? (and (numberp percentage) + (>= percentage 0) + (<= percentage battery-mode-line-limit))) + (face (if valid-percentage? + (cond (charging? 'doom-modeline-battery-charging) + ((< percentage battery-load-critical) 'doom-modeline-battery-critical) + ((< percentage 25) 'doom-modeline-battery-warning) + ((< percentage 95) 'doom-modeline-battery-normal) + (t 'doom-modeline-battery-full)) + 'doom-modeline-battery-error)) + (icon (if valid-percentage? + (cond (charging? + (doom-modeline-icon 'alltheicon "battery-charging" "πŸ”‹" "+" + :face face :height 1.4 :v-adjust -0.1)) + ((> percentage 95) + (doom-modeline-icon 'faicon "battery-full" "πŸ”‹" "-" + :face face :v-adjust -0.0575)) + ((> percentage 70) + (doom-modeline-icon 'faicon "battery-three-quarters" "πŸ”‹" "-" + :face face :v-adjust -0.0575)) + ((> percentage 40) + (doom-modeline-icon 'faicon "battery-half" "πŸ”‹" "-" + :face face :v-adjust -0.0575)) + ((> percentage battery-load-critical) + (doom-modeline-icon 'faicon "battery-quarter" "πŸ”‹" "-" + :face face :v-adjust -0.0575)) + (t (doom-modeline-icon 'faicon "battery-empty" "πŸ”‹" "!" + :face face :v-adjust -0.0575))) + (doom-modeline-icon 'faicon "battery-empty" "⚠" "N/A" + :face face :v-adjust -0.0575))) + (text (if valid-percentage? (format "%d%%%%" percentage) "")) + (help-echo (if (and battery-echo-area-format data valid-percentage?) + (battery-format battery-echo-area-format data) + "Battery status not available"))) + (cons (propertize icon 'help-echo help-echo) + (propertize text 'face face 'help-echo help-echo)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-battery-status)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-battery-status)))))) + +(doom-modeline-def-segment battery + "Display battery status." + (when (and (doom-modeline--active) + (not doom-modeline--limited-width-p) + (bound-and-true-p display-battery-mode)) + (concat (doom-modeline-spc) + (concat + (car doom-modeline--battery-status) + (doom-modeline-vspc) + (cdr doom-modeline--battery-status)) + (doom-modeline-spc)))) + +(defun doom-modeline-override-battery-modeline () + "Override default battery mode-line." + (if (bound-and-true-p doom-modeline-mode) + (progn + (advice-add #'battery-update :override #'doom-modeline-update-battery-status) + (setq global-mode-string + (delq 'battery-mode-line-string global-mode-string)) + (and (bound-and-true-p display-battery-mode) (battery-update))) + (progn + (advice-remove #'battery-update #'doom-modeline-update-battery-status) + (when (and display-battery-mode battery-status-function battery-mode-line-format + (not (memq 'battery-mode-line-string global-mode-string))) + (setq global-mode-string + (append global-mode-string '(battery-mode-line-string))))))) +(add-hook 'display-battery-mode-hook #'doom-modeline-override-battery-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-battery-modeline) + + +;; +;; Package information +;; + +(doom-modeline-def-segment package + "Show package information via `paradox'." + (let ((active (doom-modeline--active))) + (concat + (let ((front (format-mode-line 'mode-line-front-space))) + (if active + front + (propertize front 'face 'mode-line-inactive))) + + (when (and doom-modeline-icon doom-modeline-major-mode-icon) + (concat + (doom-modeline-spc) + (doom-modeline-icon 'faicon "archive" nil nil + :face (if active + (if doom-modeline-major-mode-color-icon + 'all-the-icons-silver + 'mode-line) + 'mode-line-inactive) + :height 1.0 + :v-adjust -0.0575))) + (let ((info (format-mode-line 'mode-line-buffer-identification))) + (if active + info + (propertize info 'face 'mode-line-inactive)))))) + + +;; +;; Helm +;; + +(defvar doom-modeline--helm-buffer-ids + '(("*helm*" . "HELM") + ("*helm M-x*" . "HELM M-x") + ("*swiper*" . "SWIPER") + ("*Projectile Perspectives*" . "HELM Projectile Perspectives") + ("*Projectile Layouts*" . "HELM Projectile Layouts") + ("*helm-ag*" . (lambda () + (format "HELM Ag: Using %s" + (car (split-string helm-ag-base-command)))))) + "Alist of custom helm buffer names to use. +The cdr can also be a function that returns a name to use.") + +(doom-modeline-def-segment helm-buffer-id + "Helm session identifier." + (when (bound-and-true-p helm-alive-p) + (let ((active (doom-modeline--active))) + (concat + (doom-modeline-spc) + (when doom-modeline-icon + (concat + (doom-modeline-icon 'fileicon "elisp" nil nil + :face (if active + (if doom-modeline-major-mode-color-icon + 'all-the-icons-blue + 'mode-line) + 'mode-line-inactive) + :height 1.0 + :v-adjust -0.15) + (doom-modeline-spc))) + (propertize + (let ((custom (cdr (assoc (buffer-name) doom-modeline--helm-buffer-ids))) + (case-fold-search t) + (name (replace-regexp-in-string "-" " " (buffer-name)))) + (cond ((stringp custom) custom) + ((functionp custom) (funcall custom)) + (t + (string-match "\\*helm:? \\(mode \\)?\\([^\\*]+\\)\\*" name) + (concat "HELM " (capitalize (match-string 2 name)))))) + 'face (if active' doom-modeline-buffer-file 'mode-line-inactive)) + (doom-modeline-spc))))) + +(doom-modeline-def-segment helm-number + "Number of helm candidates." + (when (bound-and-true-p helm-alive-p) + (let ((active (doom-modeline--active))) + (concat + (propertize (format " %d/%d" + (helm-candidate-number-at-point) + (helm-get-candidate-number t)) + 'face (if active 'doom-modeline-buffer-path 'mode-line-inactive)) + (propertize (format " (%d total) " (helm-get-candidate-number)) + 'face (if active 'doom-modeline-info 'mode-line-inactive)))))) + +(doom-modeline-def-segment helm-help + "Helm keybindings help." + (when (bound-and-true-p helm-alive-p) + (let ((active (doom-modeline--active))) + (-interleave + (mapcar (lambda (s) + (propertize (substitute-command-keys s) + 'face (if active + 'doom-modeline-buffer-file + 'mode-line-inactive))) + '("\\\\[helm-help]" + "\\\\[helm-select-action]" + "\\\\[helm-maybe-exit-minibuffer]/F1/F2...")) + (mapcar (lambda (s) + (propertize s 'face (if active 'mode-line 'mode-line-inactive))) + '("(help) " "(actions) " "(action) ")))))) + +(doom-modeline-def-segment helm-prefix-argument + "Helm prefix argument." + (when (and (bound-and-true-p helm-alive-p) + helm--mode-line-display-prefarg) + (let ((arg (prefix-numeric-value (or prefix-arg current-prefix-arg)))) + (unless (= arg 1) + (propertize (format "C-u %s" arg) + 'face (if (doom-modeline--active) + 'doom-modeline-info + 'mode-line-inactive)))))) + +(defvar doom-modeline--helm-current-source nil + "The currently active helm source.") +(doom-modeline-def-segment helm-follow + "Helm follow indicator." + (when (and (bound-and-true-p helm-alive-p) + doom-modeline--helm-current-source + (eq 1 (cdr (assq 'follow doom-modeline--helm-current-source)))) + (propertize "HF" 'face (if (doom-modeline--active) + 'mode-line + 'mode-line-inactive)))) + +;; +;; Git timemachine +;; + +(doom-modeline-def-segment git-timemachine + (let ((active (doom-modeline--active))) + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (propertize "*%b*" 'face (if active + 'doom-modeline-buffer-timemachine + 'mode-line-inactive))))) + +;; +;; Markdown/Org preview +;; + +(doom-modeline-def-segment grip + (when (bound-and-true-p grip-mode) + (concat + (doom-modeline-spc) + (let ((face (if (doom-modeline--active) + (if grip--process + (pcase (process-status grip--process) + ('run 'doom-modeline-buffer-path) + ('exit 'doom-modeline-warning) + (_ 'doom-modeline-urgent)) + 'doom-modeline-urgent) + 'mode-line-inactive))) + (propertize (doom-modeline-icon 'material "pageview" "πŸ—" "@" + :face (if doom-modeline-icon + `(:inherit ,face :weight normal) + face) + :height 1.2 :v-adjust -0.2) + 'help-echo (format "Preview on %s +mouse-1: Preview in browser +mouse-2: Stop preview +mouse-3: Restart preview" + (grip--preview-url)) + 'mouse-face 'mode-line-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'grip-browse-preview) + (define-key map [mode-line mouse-2] + #'grip-stop-preview) + (define-key map [mode-line mouse-3] + #'grip-restart-preview) + map))) + (doom-modeline-spc)))) + +;; +;; Follow mode +;; + +(doom-modeline-def-segment follow + (when (bound-and-true-p follow-mode) + (let* ((windows (follow-all-followers)) + (nwindows (length windows)) + (nfollowing (- (length (memq (selected-window) windows)) + 1))) + (concat + (doom-modeline-spc) + (propertize (format "Follow %d/%d" (- nwindows nfollowing) nwindows) + 'face 'doom-modeline-buffer-minor-mode))))) + +(provide 'doom-modeline-segments) + +;;; doom-modeline-segments.el ends here diff --git a/org/elpa/doom-modeline-20220412.853/doom-modeline.el b/org/elpa/doom-modeline-20220412.853/doom-modeline.el new file mode 100644 index 0000000..b48bda5 --- /dev/null +++ b/org/elpa/doom-modeline-20220412.853/doom-modeline.el @@ -0,0 +1,311 @@ +;;; doom-modeline.el --- A minimal and modern mode-line -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2020 Vincent Zhang + +;; Author: Vincent Zhang +;; Homepage: https://github.com/seagle0128/doom-modeline +;; Version: 3.3.0 +;; Package-Requires: ((emacs "25.1") (all-the-icons "2.2.0") (shrink-path "0.2.0") (dash "2.11.0")) +;; Keywords: faces mode-line + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . +;; + +;;; Commentary: +;; +;; This package offers a fancy and fast mode-line inspired by minimalism design. +;; +;; It's integrated into Doom Emacs (https://github.com/hlissner/doom-emacs) and +;; Centaur Emacs (https://github.com/seagle0128/.emacs.d). +;; +;; The doom-modeline offers: +;; - A match count panel (for anzu, iedit, multiple-cursors, symbol-overlay, +;; evil-search and evil-substitute) +;; - An indicator for recording a macro +;; - Current environment version (e.g. python, ruby, go, etc.) in the major-mode +;; - A customizable mode-line height (see doom-modeline-height) +;; - A minor modes segment which is compatible with minions +;; - An error/warning count segment for flymake/flycheck +;; - A workspace number segment for eyebrowse +;; - A perspective name segment for persp-mode +;; - A window number segment for winum and window-numbering +;; - An indicator for modal editing state, including evil, overwrite, god, ryo +;; and xah-fly-keys, etc. +;; - An indicator for battery status +;; - An indicator for current input method +;; - An indicator for debug state +;; - An indicator for remote host +;; - An indicator for LSP state with lsp-mode or eglot +;; - An indicator for github notifications +;; - An indicator for unread emails with mu4e-alert +;; - An indicator for unread emails with gnus (basically builtin) +;; - An indicator for irc notifications with circe, rcirc or erc. +;; - An indicator for buffer position which is compatible with nyan-mode or poke-line +;; - An indicator for party parrot +;; - An indicator for PDF page number with pdf-tools +;; - An indicator for markdown/org previews with grip +;; - Truncated file name, file icon, buffer state and project name in buffer +;; information segment, which is compatible with project, find-file-in-project +;; and projectile +;; - New mode-line for Info-mode buffers +;; - New package mode-line for paradox +;; - New mode-line for helm buffers +;; - New mode-line for git-timemachine buffers +;; +;; Installation: +;; From melpa, `M-x package-install RET doom-modeline RET`. +;; In `init.el`, +;; (require 'doom-modeline) +;; (doom-modeline-mode 1) +;; or +;; (use-package doom-modeline +;; :ensure t +;; :hook (after-init . doom-modeline-mode)) +;; + +;;; Code: + +(require 'doom-modeline-core) +(require 'doom-modeline-segments) + + +;; +;; Mode lines +;; + +(doom-modeline-def-modeline 'main + '(bar workspace-name window-number modals matches follow buffer-info remote-host buffer-position word-count parrot selection-info) + '(objed-state misc-info persp-name battery grip irc mu4e gnus github debug repl lsp minor-modes input-method indent-info buffer-encoding major-mode process vcs checker)) + +(doom-modeline-def-modeline 'minimal + '(bar matches buffer-info-simple) + '(media-info major-mode)) + +(doom-modeline-def-modeline 'special + '(bar window-number modals matches buffer-info buffer-position word-count parrot selection-info) + '(objed-state misc-info battery irc-buffers debug minor-modes input-method indent-info buffer-encoding major-mode process)) + +(doom-modeline-def-modeline 'project + '(bar window-number modals buffer-default-directory) + '(misc-info battery irc mu4e gnus github debug minor-modes input-method major-mode process)) + +(doom-modeline-def-modeline 'dashboard + '(bar window-number buffer-default-directory-simple) + '(misc-info battery irc mu4e gnus github debug minor-modes input-method major-mode process)) + +(doom-modeline-def-modeline 'vcs + '(bar window-number modals matches buffer-info buffer-position parrot selection-info) + '(misc-info battery irc mu4e gnus github debug minor-modes buffer-encoding major-mode process)) + +(doom-modeline-def-modeline 'package + '(bar window-number package) + '(misc-info major-mode process)) + +(doom-modeline-def-modeline 'info + '(bar window-number buffer-info info-nodes buffer-position parrot selection-info) + '(misc-info buffer-encoding major-mode)) + +(doom-modeline-def-modeline 'media + '(bar window-number buffer-size buffer-info) + '(misc-info media-info major-mode process vcs)) + +(doom-modeline-def-modeline 'message + '(bar window-number modals matches buffer-info-simple buffer-position word-count parrot selection-info) + '(objed-state misc-info battery debug minor-modes input-method indent-info buffer-encoding major-mode)) + +(doom-modeline-def-modeline 'pdf + '(bar window-number matches buffer-info pdf-pages) + '(misc-info major-mode process vcs)) + +(doom-modeline-def-modeline 'org-src + '(bar window-number modals matches buffer-info-simple buffer-position word-count parrot selection-info) + '(objed-state misc-info debug lsp minor-modes input-method indent-info buffer-encoding major-mode process checker)) + +(doom-modeline-def-modeline 'helm + '(bar helm-buffer-id helm-number helm-follow helm-prefix-argument) + '(helm-help)) + +(doom-modeline-def-modeline 'timemachine + '(bar window-number modals matches git-timemachine buffer-position word-count parrot selection-info) + '(misc-info minor-modes indent-info buffer-encoding major-mode)) + + +;; +;; Interfaces +;; + +;;;###autoload +(defun doom-modeline-init () + "Initialize doom mode-line." + (doom-modeline-mode 1)) +(make-obsolete 'doom-modeline-init 'doom-modeline-mode "1.6.0") + +;;;###autoload +(defun doom-modeline-set-main-modeline (&optional default) + "Set main mode-line. +If DEFAULT is non-nil, set the default mode-line for all buffers." + (doom-modeline-set-modeline 'main default)) + +;;;###autoload +(defun doom-modeline-set-minimal-modeline () + "Set minimal mode-line." + (doom-modeline-set-modeline 'minimal)) + +;;;###autoload +(defun doom-modeline-set-special-modeline () + "Set special mode-line." + (doom-modeline-set-modeline 'special)) + +;;;###autoload +(defun doom-modeline-set-project-modeline () + "Set project mode-line." + (doom-modeline-set-modeline 'project)) + +;;;###autoload +(defun doom-modeline-set-dashboard-modeline () + "Set dashboard mode-line." + (doom-modeline-set-modeline 'dashboard)) + +;;;###autoload +(defun doom-modeline-set-vcs-modeline () + "Set vcs mode-line." + (doom-modeline-set-modeline 'vcs)) + +;;;###autoload +(defun doom-modeline-set-info-modeline () + "Set Info mode-line." + (doom-modeline-set-modeline 'info)) + +;;;###autoload +(defun doom-modeline-set-package-modeline () + "Set package mode-line." + (doom-modeline-set-modeline 'package)) + +;;;###autoload +(defun doom-modeline-set-media-modeline () + "Set media mode-line." + (doom-modeline-set-modeline 'media)) + +;;;###autoload +(defun doom-modeline-set-message-modeline () + "Set message mode-line." + (doom-modeline-set-modeline 'message)) + +;;;###autoload +(defun doom-modeline-set-pdf-modeline () + "Set pdf mode-line." + (doom-modeline-set-modeline 'pdf)) + +;;;###autoload +(defun doom-modeline-set-org-src-modeline () + "Set org-src mode-line." + (doom-modeline-set-modeline 'org-src)) + +;;;###autoload +(defun doom-modeline-set-helm-modeline (&rest _) ; To advice helm + "Set helm mode-line." + (doom-modeline-set-modeline 'helm)) + +;;;###autoload +(defun doom-modeline-set-timemachine-modeline () + "Set timemachine mode-line." + (doom-modeline-set-modeline 'timemachine)) + + +;; +;; Minor mode +;; + +(defvar doom-modeline-mode-map (make-sparse-keymap)) + +;; Suppress warnings +(defvar 2C-mode-line-format) +(declare-function helm-display-mode-line "ext:helm-core") + +;;;###autoload +(define-minor-mode doom-modeline-mode + "Toggle doom-modeline on or off." + :group 'doom-modeline + :global t + :lighter nil + :keymap doom-modeline-mode-map + (if doom-modeline-mode + (progn + (doom-modeline-refresh-bars) ; Create bars + (doom-modeline-set-main-modeline t) ; Set default mode-line + + ;; Apply to all existing buffers. + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-set-main-modeline))) + + ;; For two-column editing + (setq 2C-mode-line-format (doom-modeline 'special)) + + ;; Add hooks + (add-hook 'Info-mode-hook #'doom-modeline-set-info-modeline) + (add-hook 'dired-mode-hook #'doom-modeline-set-project-modeline) + (add-hook 'dashboard-mode-hook #'doom-modeline-set-dashboard-modeline) + (add-hook 'image-mode-hook #'doom-modeline-set-media-modeline) + (add-hook 'message-mode-hook #'doom-modeline-set-message-modeline) + (add-hook 'git-commit-mode-hook #'doom-modeline-set-message-modeline) + (add-hook 'magit-mode-hook #'doom-modeline-set-vcs-modeline) + (add-hook 'circe-mode-hook #'doom-modeline-set-special-modeline) + (add-hook 'erc-mode-hook #'doom-modeline-set-special-modeline) + (add-hook 'rcirc-mode-hook #'doom-modeline-set-special-modeline) + (add-hook 'pdf-view-mode-hook #'doom-modeline-set-pdf-modeline) + (add-hook 'org-src-mode-hook #'doom-modeline-set-org-src-modeline) + (add-hook 'git-timemachine-mode-hook #'doom-modeline-set-timemachine-modeline) + (add-hook 'paradox-menu-mode-hook #'doom-modeline-set-package-modeline) + (add-hook 'xwidget-webkit-mode-hook #'doom-modeline-set-minimal-modeline) + + ;; Add advices + (advice-add #'helm-display-mode-line :after #'doom-modeline-set-helm-modeline)) + (progn + ;; Restore mode-line + (let ((original-format (doom-modeline--original-value 'mode-line-format))) + (setq-default mode-line-format original-format) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (setq mode-line-format original-format)))) + + ;; For two-column editing + (setq 2C-mode-line-format (doom-modeline--original-value '2C-mode-line-format)) + + ;; Remove hooks + (remove-hook 'Info-mode-hook #'doom-modeline-set-info-modeline) + (remove-hook 'dired-mode-hook #'doom-modeline-set-project-modeline) + (remove-hook 'dashboard-mode-hook #'doom-modeline-set-dashboard-modeline) + (remove-hook 'image-mode-hook #'doom-modeline-set-media-modeline) + (remove-hook 'message-mode-hook #'doom-modeline-set-message-modeline) + (remove-hook 'git-commit-mode-hook #'doom-modeline-set-message-modeline) + (remove-hook 'magit-mode-hook #'doom-modeline-set-vcs-modeline) + (remove-hook 'circe-mode-hook #'doom-modeline-set-special-modeline) + (remove-hook 'erc-mode-hook #'doom-modeline-set-special-modeline) + (remove-hook 'rcirc-mode-hook #'doom-modeline-set-special-modeline) + (remove-hook 'pdf-view-mode-hook #'doom-modeline-set-pdf-modeline) + (remove-hook 'org-src-mode-hook #'doom-modeline-set-org-src-modeline) + (remove-hook 'git-timemachine-mode-hook #'doom-modeline-set-timemachine-modeline) + (remove-hook 'paradox-menu-mode-hook #'doom-modeline-set-package-modeline) + (remove-hook 'xwidget-webkit-mode-hook #'doom-modeline-set-minimal-modeline) + + ;; Remove advices + (advice-remove #'helm-display-mode-line #'doom-modeline-set-helm-modeline)))) + +(provide 'doom-modeline) + +;;; doom-modeline.el ends here diff --git a/org/elpa/shrink-path-20190208.1335/shrink-path-autoloads.el b/org/elpa/shrink-path-20190208.1335/shrink-path-autoloads.el new file mode 100644 index 0000000..776b017 --- /dev/null +++ b/org/elpa/shrink-path-20190208.1335/shrink-path-autoloads.el @@ -0,0 +1,22 @@ +;;; shrink-path-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "shrink-path" "shrink-path.el" (0 0 0 0)) +;;; Generated autoloads from shrink-path.el + +(register-definition-prefixes "shrink-path" '("shrink-path-")) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; shrink-path-autoloads.el ends here diff --git a/org/elpa/shrink-path-20190208.1335/shrink-path-pkg.el b/org/elpa/shrink-path-20190208.1335/shrink-path-pkg.el new file mode 100644 index 0000000..c568bd0 --- /dev/null +++ b/org/elpa/shrink-path-20190208.1335/shrink-path-pkg.el @@ -0,0 +1,2 @@ +;;; Generated package description from shrink-path.el -*- no-byte-compile: t -*- +(define-package "shrink-path" "20190208.1335" "fish-style path" '((emacs "24") (s "1.6.1") (dash "1.8.0") (f "0.10.0")) :commit "c14882c8599aec79a6e8ef2d06454254bb3e1e41" :authors '(("Benjamin Andresen")) :maintainer '("Benjamin Andresen") :url "https://gitlab.com/bennya/shrink-path.el") diff --git a/org/elpa/shrink-path-20190208.1335/shrink-path.el b/org/elpa/shrink-path-20190208.1335/shrink-path.el new file mode 100644 index 0000000..154bfd6 --- /dev/null +++ b/org/elpa/shrink-path-20190208.1335/shrink-path.el @@ -0,0 +1,150 @@ +;;; shrink-path.el --- fish-style path -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 Benjamin Andresen + +;; Author: Benjamin Andresen +;; Version: 0.3.1 +;; Package-Version: 20190208.1335 +;; Package-Commit: c14882c8599aec79a6e8ef2d06454254bb3e1e41 +;; URL: https://gitlab.com/bennya/shrink-path.el +;; Package-Requires: ((emacs "24") (s "1.6.1") (dash "1.8.0") (f "0.10.0")) + +;; This file is NOT part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file LICENSE. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Provides functions that offer fish shell[1] path truncation. +;; Directory /usr/share/emacs/site-lisp => /u/s/e/site-lisp +;; +;; Also includes utility functions that make integration in eshell or the +;; modeline easier. +;; +;; [1] https://fishshell.com/ + + +;;; Code: +(require 'dash) +(require 's) +(require 'f) +(require 'rx) + +(defun shrink-path--truncate (str) + "Return STR's first character or first two characters if hidden." + (substring str 0 (if (s-starts-with? "." str) 2 1))) + +(defun shrink-path--dirs-internal (full-path &optional truncate-all) + "Return fish-style truncated string based on FULL-PATH. +Optional parameter TRUNCATE-ALL will cause the function to truncate the last +directory too." + (let* ((home (expand-file-name "~")) + (path (replace-regexp-in-string + (s-concat "^" home) "~" full-path)) + (split (s-split "/" path 'omit-nulls)) + (split-len (length split)) + shrunk) + (->> split + (--map-indexed (if (= it-index (1- split-len)) + (if truncate-all (shrink-path--truncate it) it) + (shrink-path--truncate it))) + (s-join "/") + (setq shrunk)) + (s-concat (unless (s-matches? (rx bos (or "~" "/")) shrunk) "/") + shrunk + (unless (s-ends-with? "/" shrunk) "/")))) + + +(defun shrink-path-dirs (&optional path truncate-tail) + "Given PATH return fish-styled shrunken down path. +TRUNCATE-TAIL will cause the function to truncate the last directory too." + (let* ((path (or path default-directory)) + (path (f-full path))) + (cond + ((s-equals? (f-short path) "/") "/") + ((s-matches? (rx bos (or "~" "/") eos) "~/")) + (t (shrink-path--dirs-internal path truncate-tail))))) + +(defun shrink-path-expand (str &optional absolute-p) + "Return expanded path from STR if found or list of matches on multiple. +The path referred to by STR has to exist for this to work. +If ABSOLUTE-P is t the returned path will be absolute." + (let* ((str-split (s-split "/" str 'omit-nulls)) + (head (car str-split))) + (if (= (length str-split) 1) + (s-concat "/" str-split) + (--> (-drop 1 str-split) ;; drop head + (-map (lambda (e) (s-concat e "*")) it) + (-drop-last 1 it) ;; drop tail as it may not exist + (s-join "/" it) + (s-concat (if (s-equals? head "~") "~/" head) it) + (f-glob it) + (-map (lambda (e) (s-concat e "/" (-last-item str-split))) it) + (if absolute-p (-map #'f-full it) (-map #'f-abbrev it)) + (if (= (length it) 1) (car it) it))))) + +(defun shrink-path-prompt (&optional pwd) + "Return cons of BASE and DIR for PWD. +If PWD isn't provided will default to `default-directory'." + (let* ((pwd (or pwd default-directory)) + (shrunk (shrink-path-dirs pwd)) + (split (--> shrunk (s-split "/" it 'omit-nulls))) + base dir) + (setq dir (or (-last-item split) "/")) + (setq base (if (s-equals? dir "/") "" + (s-chop-suffix (s-concat dir "/") shrunk))) + (cons base dir))) + +(defun shrink-path-file (file &optional truncate-tail) + "Return FILE's shrunk down path and filename. +TRUNCATE-TAIL controls if the last directory should also be shortened." + (let ((filename (f-filename file)) + (dirname (f-dirname file))) + (s-concat (shrink-path-dirs dirname truncate-tail) filename))) + +(defun shrink-path-file-expand (str &optional exists-p absolute-p) + "Return STR's expanded filename. +The path referred to by STR has to exist for this to work. +If EXISTS-P is t the filename also has to exist. +If ABSOLUTE-P is t the returned path will be absolute." + (let ((expanded (shrink-path-expand str absolute-p))) + (if (and expanded exists-p) + (if (f-exists? expanded) expanded) + expanded))) + +(defun shrink-path-file-mixed (shrink-path rel-path filename) + "Returns list of mixed truncated file name locations. + +Consists of SHRINK-PATH's parent, SHRINK-PATH basename, relative REL-PATH and +FILENAME. +For use in modeline or prompts, etc." + (let ((shrunk-dirs (shrink-path-prompt shrink-path)) + sp-parent sp-rel rel-rel nd-file) + + (when (f-descendant-of? filename shrink-path) + (when shrunk-dirs + (setq sp-parent (car shrunk-dirs) + sp-rel (cdr shrunk-dirs))) + (setq rel-rel (if (or (f-same? rel-path shrink-path) + (s-equals? (f-relative rel-path shrink-path) ".")) + nil + (f-relative rel-path shrink-path))) + (setq nd-file (file-name-nondirectory filename)) + + (list sp-parent sp-rel rel-rel nd-file)))) + +(provide 'shrink-path) +;;; shrink-path.el ends here