diff --git a/core/core-modules.el b/core/core-modules.el index 88b7bbafc..34997dd7d 100644 --- a/core/core-modules.el +++ b/core/core-modules.el @@ -17,7 +17,8 @@ (syntax-checker (:tools flycheck))) (:tools (rotate-text (:editor rotate-text))) (:emacs (electric-indent (:emacs electric)) - (hideshow (:editor fold)))) + (hideshow (:editor fold))) + (:ui (doom-modeline (:ui modeline)))) "An alist of deprecated modules, mapping deprecated modules to an optional new location (which will create an alias). Each CAR and CDR is a (CATEGORY . MODULES). E.g. diff --git a/init.example.el b/init.example.el index d45312a35..79782f582 100644 --- a/init.example.el +++ b/init.example.el @@ -21,12 +21,11 @@ ;;deft ; notational velocity for Emacs doom ; what makes DOOM look the way it does doom-dashboard ; a nifty splash screen for Emacs - doom-modeline ; a snazzy Atom-inspired mode-line doom-quit ; DOOM quit-message prompts when you quit Emacs evil-goggles ; display visual hints when editing in evil ;;fci ; a `fill-column' indicator hl-todo ; highlight TODO/FIXME/NOTE tags - ;;modeline ; snazzy, Atom-inspired modeline, plus API + modeline ; snazzy, Atom-inspired modeline, plus API nav-flash ; blink the current line after jumping ;;neotree ; a project drawer, like NERDTree for vim treemacs ; a project drawer, like neotree but cooler diff --git a/modules/lang/python/autoload/python.el b/modules/lang/python/autoload/python.el index 635df2f07..27ed691a3 100644 --- a/modules/lang/python/autoload/python.el +++ b/modules/lang/python/autoload/python.el @@ -1,8 +1,5 @@ ;;; lang/python/autoload/python.el -*- lexical-binding: t; -*- -(defvar +python-version-cache (make-hash-table :test 'equal) - "TODO") - ;;;###autoload (defun +python/open-repl () "Open the Python REPL." @@ -38,53 +35,3 @@ (let ((python-shell-interpreter "jupyter") (python-shell-interpreter-args (format "console %s" (string-join +python-jupyter-repl-args " ")))) (+python/open-repl))) - -(defun +python--extract-version (prefix str) - (when str - (format "%s%s" prefix (cadr (split-string str " "))))) - -;;;###autoload -(defun +python-version () - "Return the currently installed version of python on your system or active in -the current pipenv. - -This is not necessarily aware of env management tools like virtualenv, pyenv or -pipenv, unless those tools have modified the PATH that Emacs picked up when you -started it." - (condition-case _ - (if-let* ((proot (and (fboundp 'pipenv-project-p) - (pipenv-project-p)))) - (let* ((default-directory proot) - (v (car (process-lines "pipenv" "run" "python" "--version")))) - (puthash proot - (+python--extract-version "Pipenv " v) - +python-version-cache)) - (puthash (or (doom-project-root) default-directory) - (+python--extract-version - "Python " - (car (process-lines python-shell-interpreter "--version"))) - +python-version-cache)) - (error "Python"))) - - -;; -;; Hooks - -;;;###autoload -(defun +python|update-version (&rest _) - "Update `+python--version' by consulting `+python-version' function." - (setq +python--version - (or (gethash (or (and (fboundp 'pipenv-project-p) - (pipenv-project-p)) - (doom-project-root) - default-directory) - +python-version-cache) - (+python-version)))) - -;;;###autoload -(defun +python|update-version-in-all-buffers (&rest _) - "Update `+python-version' in all buffers in `python-mode'." - (dolist (buffer (doom-buffers-in-mode 'python-mode)) - (setq +python-version-cache (clrhash +python-version-cache)) - (with-current-buffer buffer - (+python|update-version)))) diff --git a/modules/lang/python/config.el b/modules/lang/python/config.el index 529b69ddd..8ec9fe931 100644 --- a/modules/lang/python/config.el +++ b/modules/lang/python/config.el @@ -11,9 +11,6 @@ called.") "CLI arguments to initialize 'jupiter console %s' with when `+python/open-ipython-repl' is called.") -(defvar-local +python--version nil - "The python version in the current buffer.") - ;; ;; Packages @@ -55,14 +52,7 @@ called.") sp-point-after-word-p sp-point-before-same-p)) - (setq-hook! 'python-mode-hook tab-width python-indent-offset) - - ;; Add python/pipenv version string to the major mode in the modeline - (defun +python|init-mode-line () - (setq mode-name +python-mode-line-indicator)) - (add-hook 'python-mode-hook #'+python|init-mode-line) - - (add-hook 'python-mode-hook #'+python|update-version)) + (setq-hook! 'python-mode-hook tab-width python-indent-offset)) (def-package! anaconda-mode @@ -152,9 +142,9 @@ called.") (format "PIPENV_MAX_DEPTH=9999 %s run %%c %%o %%s %%a" bin) "%c %o %s %a"))) (:description . "Run Python script"))) - - (advice-add #'pipenv-activate :after-while #'+python|update-version-in-all-buffers) - (advice-add #'pipenv-deactivate :after-while #'+python|update-version-in-all-buffers)) + (when (featurep! :ui modeline) + (advice-add #'pipenv-activate :after-while #'+modeline|update-env-in-all-windows) + (advice-add #'pipenv-deactivate :after-while #'+modeline|update-env-in-all-windows))) (def-package! pyenv-mode @@ -164,8 +154,9 @@ called.") (pyenv-mode +1) (when (executable-find "pyenv") (add-to-list 'exec-path (expand-file-name "shims" (or (getenv "PYENV_ROOT") "~/.pyenv")))) - (advice-add #'pyenv-mode-set :after #'+python|update-version-in-all-buffers) - (advice-add #'pyenv-mode-unset :after #'+python|update-version-in-all-buffers)) + (when (featurep! :ui modeline) + (advice-add #'pyenv-mode-set :after #'+modeline|update-env-in-all-windows) + (advice-add #'pyenv-mode-unset :after #'+modeline|update-env-in-all-windows))) (def-package! pyvenv @@ -173,9 +164,10 @@ called.") :after python :config (defun +python-current-pyvenv () pyvenv-virtual-env-name) - (add-hook 'pyvenv-post-activate-hooks #'+python|update-version-in-all-buffers) - (add-hook 'pyvenv-post-deactivate-hooks #'+python|update-version-in-all-buffers) - (add-to-list '+python-mode-line-indicator + (when (featurep! :ui modeline) + (add-hook 'pyvenv-post-activate-hooks #'+modeline|update-env-in-all-windows) + (add-hook 'pyvenv-post-deactivate-hooks #'+modeline|update-env-in-all-windows)) + (add-to-list 'global-mode-string '(pyvenv-virtual-env-name (" venv:" pyvenv-virtual-env-name)) 'append)) @@ -214,8 +206,9 @@ called.") (conda-env-initialize-interactive-shells) (after! eshell (conda-env-initialize-eshell)) - (add-hook 'conda-postactivate-hook #'+python|update-version-in-all-buffers) - (add-hook 'conda-postdeactivate-hook #'+python|update-version-in-all-buffers) - (add-to-list '+python-mode-line-indicator + (when (featurep! :ui modeline) + (add-hook 'conda-postactivate-hook #'+modeline|update-env-in-all-windows) + (add-hook 'conda-postdeactivate-hook #'+modeline|update-env-in-all-windows)) + (add-to-list 'global-mode-string '(conda-env-current-name (" conda:" conda-env-current-name)) 'append)) diff --git a/modules/lang/ruby/autoload.el b/modules/lang/ruby/autoload.el index cc2b21323..8f9519283 100644 --- a/modules/lang/ruby/autoload.el +++ b/modules/lang/ruby/autoload.el @@ -1,8 +1,5 @@ ;;; lang/ruby/autoload.el -*- lexical-binding: t; -*- -(defvar +ruby-version-cache (make-hash-table :test 'equal) - "TODO") - ;;;###autoload (defun +ruby|cleanup-robe-servers () "Clean up dangling inf robe processes if there are no more `enh-ruby-mode' @@ -16,38 +13,3 @@ buffers open." (when (processp process) (kill-process (get-buffer-process inf-buffer)) (kill-buffer inf-buffer))))))) - -;;;###autoload -(defun +ruby-version () - "Return the currently installed version of ruby on your system (the first -ruby executable found in your PATH). - -This is not necessarily aware of env management tools like virtualenv, pyenv or -pipenv, unless those tools have modified the PATH that Emacs picked up when you -started it." - (condition-case _ - (let ((version-str (car (process-lines "ruby" "--version")))) - (puthash (or (doom-project-root) default-directory) - (format "Ruby %s" (cadr (split-string version-str " "))) - +ruby-version-cache)) - (error "Ruby"))) - - -;; -;; Hooks - -;;;###autoload -(defun +ruby|update-version (&rest _) - "Update `+ruby--version' by consulting `+ruby-version' function." - (setq +ruby--version - (or (gethash (or (doom-project-root) default-directory) - +ruby-version-cache) - (+ruby-version)))) - -;;;###autoload -(defun +ruby|update-version-in-all-buffers (&rest _) - "Update `+ruby--version' in all `enh-ruby-mode' buffers." - (dolist (buffer (doom-buffers-in-mode 'enh-ruby-mode)) - (setq +ruby-version-cache (clrhash +ruby-version-cache)) - (with-current-buffer buffer - (+ruby|update-version)))) diff --git a/modules/lang/ruby/config.el b/modules/lang/ruby/config.el index 009927d4f..82392619b 100644 --- a/modules/lang/ruby/config.el +++ b/modules/lang/ruby/config.el @@ -1,12 +1,5 @@ ;;; lang/ruby/config.el -*- lexical-binding: t; -*- -(defvar +ruby-mode-line-indicator '("" +ruby--version) - "Format for the ruby version/env indicator in the mode-line.") - -(defvar-local +ruby--version nil - "The ruby version in the current buffer.") - - ;; ;; Packages @@ -34,14 +27,7 @@ (add-to-list 'company-dabbrev-code-modes 'ruby-mode nil #'eq)) ;; so class and module pairs work - (setq-hook! (ruby-mode enh-ruby-mode) sp-max-pair-length 6) - - ;; Add ruby version string to the major mode in the modeline - (defun +ruby|init-mode-line () - (setq mode-name +ruby-mode-line-indicator)) - (add-hook 'enh-ruby-mode-hook #'+ruby|init-mode-line) - - (add-hook 'enh-ruby-mode-hook #'+ruby|update-version)) + (setq-hook! (ruby-mode enh-ruby-mode) sp-max-pair-length 6)) (def-package! robe diff --git a/modules/tools/pdf/+modeline.el b/modules/tools/pdf/+modeline.el deleted file mode 100644 index f3fe0532c..000000000 --- a/modules/tools/pdf/+modeline.el +++ /dev/null @@ -1,20 +0,0 @@ -;;; tools/pdf/+modeline.el -*- lexical-binding: t; -*- - -(def-modeline-segment! +pdf-pages - "Current and total page indicator for PDF documents." - (format "P %d/%d" (pdf-view-current-page) (pdf-cache-number-of-pages))) - -(if (featurep! :ui modeline) - (def-modeline-format! '+pdf - '(+modeline-matches " " +modeline-buffer-id " " +pdf-pages) - '(+modeline-major-mode (vc-mode (" " +modeline-vcs)))) - (def-modeline! '+pdf - '(bar matches " " buffer-info " " +pdf-pages) - '(major-mode vcs))) - -(defun +pdf|init-modeline () - (funcall (if (featurep! :ui modeline) - #'set-modeline! - #'doom-set-modeline) - '+pdf)) -(add-hook 'pdf-tools-enabled-hook #'+pdf|init-modeline) diff --git a/modules/tools/pdf/config.el b/modules/tools/pdf/config.el index 681cb29f2..a10e9a5e3 100644 --- a/modules/tools/pdf/config.el +++ b/modules/tools/pdf/config.el @@ -28,9 +28,6 @@ (setq-default pdf-view-display-size 'fit-page) ;; Turn off cua so copy works (add-hook! 'pdf-view-mode-hook (cua-mode 0)) - ;; Custom modeline that removes useless info and adds page numbers - (when (or (featurep! :ui doom-modeline) (featurep! :ui modeline)) - (load! "+modeline")) ;; Handle PDF-tools related popups better (set-popup-rule! "^\\*Outline*" :side 'right :size 40 :select nil) ;; The next rules are not needed, they are defined in modules/ui/popups/+hacks.el diff --git a/modules/ui/doom-modeline/README.org b/modules/ui/doom-modeline/README.org deleted file mode 100644 index 28590ef8f..000000000 --- a/modules/ui/doom-modeline/README.org +++ /dev/null @@ -1,52 +0,0 @@ -#+TITLE: :ui doom-modeline - -This module customizes the Emacs mode-line. - -The DOOM modeline was designed for minimalism, and offers: - -+ A match count panel (for ~evil-search~, ~iedit~ and ~evil-substitute~) -+ An indicator for recording a macro -+ Local python/ruby version in the major-mode -+ A customizable mode-line height (see ~+doom-modeline-height~) -+ An error/warning count segment for flycheck - -[[/../screenshots/ml.png]] -[[/../screenshots/ml-search.png]] -[[/../screenshots/ml-subst.png]] -[[/../screenshots/ml-macro.png]] -[[/../screenshots/ml-version.png]] -[[/../screenshots/ml-errors.png]] - -* Table of Contents :TOC: -- [[#install][Install]] -- [[#extracting-my-modeline][Extracting my modeline]] -- [[#troubleshooting][Troubleshooting]] - - [[#where-are-my-minor-modes][Where are my minor modes?]] - -* Install -This module requires the fonts included with ~all-the-icons~ to be installed. - -Run ~M-x all-the-icons-install-fonts~ to do so. - -* Extracting my modeline -Some might want my modeline without the DOOM config altogether. I've tried to make this easier for you, but there are a few things you'll need to do: - -+ Ensure [[https://github.com/bbatsov/projectile][projectile]] and [[https://github.com/domtronn/all-the-icons.el][all-the-icons]] are installed. -+ Ensure ~projectile-mode~ is enabled. -+ Ensure the fonts included with ~all-the-icons~ are installed (~M-x all-the-icons-install-fonts~). -+ Replace ~def-package!~ calls with ~use-package~. -+ Replace ~doom-project-root~ calls with ~projectile-project-root~. -+ The ~+doom-modeline--make-xpm~ function is memoized with the ~def-memoized!~ macro. Change ~def-memoized!~ to ~defun~. -+ Copy the ~add-hook!~ macro definition from [[/core/core-lib.el][core/core-lib.el]]. -+ Copy the following macros and functions from [[/core/core-ui.el][core/core-ui.el]]: - + ~def-modeline-segment!~ - + ~def-modeline!~ - + ~doom--prepare-modeline-segments~ - + ~doom-modeline~ - + ~doom-set-modeline~ - -That /should/ be everything. As I have never used this out of my config I can't guarantee immediate success, but I'd be happy to help you out if you file an issue. - -* Troubleshooting -** Where are my minor modes? -I didn't need it, so I removed it. Run ~M-x doom/what-minor-mode~ to investigate what minor modes are currently active. diff --git a/modules/ui/doom-modeline/autoload.el b/modules/ui/doom-modeline/autoload.el deleted file mode 100644 index 1c188ef9f..000000000 --- a/modules/ui/doom-modeline/autoload.el +++ /dev/null @@ -1,19 +0,0 @@ -;;; ui/doom-modeline/autoload.el -*- lexical-binding: t; -*- - -(defvar +doom-modeline--old-bar-height nil) -;;;###autoload -(defun +doom-modeline|resize-for-big-font () - "Adjust the modeline's height when `doom-big-font-mode' is enabled. This was -made to be added to `doom-big-font-mode-hook'." - (unless +doom-modeline--old-bar-height - (setq +doom-modeline--old-bar-height +doom-modeline-height)) - (let ((default-height +doom-modeline--old-bar-height)) - (if doom-big-font-mode - (let* ((font-size (font-get doom-font :size)) - (big-size (font-get doom-big-font :size)) - (ratio (/ (float big-size) font-size))) - (setq +doom-modeline-height (ceiling (* default-height ratio 0.75)))) - (setq +doom-modeline-height default-height)) - ;; already has a variable watcher in Emacs 26+ - (unless EMACS26+ (+doom-modeline|refresh-bars)))) - diff --git a/modules/ui/doom-modeline/config.el b/modules/ui/doom-modeline/config.el deleted file mode 100644 index f5f8d708f..000000000 --- a/modules/ui/doom-modeline/config.el +++ /dev/null @@ -1,830 +0,0 @@ -;;; ui/doom-modeline/config.el -*- lexical-binding: t; -*- - -;; We handle this ourselves -(setq projectile-dynamic-mode-line nil) - - -;; -;; Modeline library - -(defvar doom--modeline-fn-alist ()) -(defvar doom--modeline-var-alist ()) - -(defmacro def-modeline-segment! (name &rest body) - "Defines a modeline segment 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--prepare-modeline-segments (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 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))) - -(defun 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 `def-modeline-segment!'. - -Example: - (def-modeline! 'minimal - '(bar matches \" \" buffer-info) - '(media-info major-mode)) - (doom-set-modeline 'minimal t)" - (let ((sym (intern (format "doom-modeline-format--%s" name))) - (lhs-forms (doom--prepare-modeline-segments lhs)) - (rhs-forms (doom--prepare-modeline-segments rhs))) - (defalias sym - (lambda () - (let ((lhs (eval `(list ,@lhs-forms) t)) - (rhs (eval `(list ,@rhs-forms) t))) - (let ((rhs-str (format-mode-line rhs))) - (list lhs - (propertize - " " 'display - `((space :align-to (- (+ right right-fringe right-margin) - ,(+ 1 (string-width rhs-str)))))) - rhs-str)))) - (concat "Modeline:\n" - (format " %s\n %s" - (prin1-to-string lhs) - (prin1-to-string rhs)))))) - -(defun doom-modeline (key) - "Returns 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-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)))) - - -;; -;; Custom faces - -(defgroup +doom-modeline nil - "TODO" - :group '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) - -(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) - -(defface doom-modeline-buffer-modified - '((t (:inherit (error bold) :background nil))) - "Face used for the 'unsaved' symbol in the mode-line." - :group '+doom-modeline) - -(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) - -(defface doom-modeline-highlight - '((t (:inherit mode-line-emphasis))) - "Face for bright segments of the mode-line." - :group '+doom-modeline) - -(defface doom-modeline-panel - '((t (:inherit mode-line-highlight))) - "Face for 'X out of Y' segments, such as `+doom-modeline--anzu', `+doom-modeline--evil-substitute' and -`iedit'" - :group '+doom-modeline) - -(defface doom-modeline-info - `((t (:inherit (success bold)))) - "Face for info-level messages in the modeline. Used by `*vc'." - :group '+doom-modeline) - -(defface doom-modeline-warning - `((t (:inherit (warning bold)))) - "Face for warnings in the modeline. Used by `*flycheck'" - :group '+doom-modeline) - -(defface doom-modeline-urgent - `((t (:inherit (error bold)))) - "Face for errors in the modeline. Used by `*flycheck'" - :group '+doom-modeline) - -;; Bar -(defface doom-modeline-bar '((t (:inherit highlight))) - "The face used for the left-most bar on the mode-line of an active window." - :group '+doom-modeline) - -(defface doom-modeline-eldoc-bar '((t (:inherit shadow))) - "The face used for the left-most bar on the mode-line when eldoc-eval is -active." - :group '+doom-modeline) - -(defface doom-modeline-inactive-bar '((t (:inherit warning :inverse-video t))) - "The face used for the left-most bar on the mode-line of an inactive window." - :group '+doom-modeline) - - -;; -;; Packages - -;; anzu and evil-anzu expose current/total state that can be displayed in the -;; mode-line. -(def-package! anzu - :after-call isearch-mode - :config - (setq anzu-cons-mode-line-p nil - anzu-minimum-input-length 1 - anzu-search-threshold 250) - (global-anzu-mode +1) - - (defun +doom-modeline*fix-anzu-count (positions 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) - - ;; Avoid anzu conflicts across 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)) - ;; Ensure anzu state is cleared when searches & iedit are done - (add-hook 'isearch-mode-end-hook #'anzu--reset-status t) - (add-hook 'doom-escape-hook #'anzu--reset-status t) - (add-hook 'iedit-mode-end-hook #'anzu--reset-status)) - - -(def-package! evil-anzu - :when (featurep! :feature evil) - :after-call (evil-ex-start-search evil-ex-start-word-search)) - - -;; fish-style modeline -(def-package! shrink-path - :commands (shrink-path-prompt shrink-path-file-mixed)) - - -;; Keep `+doom-modeline-current-window' up-to-date -(defvar +doom-modeline-current-window (frame-selected-window)) -(defun +doom-modeline|set-selected-window (&rest _) - "Sets `+doom-modeline-current-window' appropriately" - (when-let* ((win (frame-selected-window))) - (unless (minibuffer-window-active-p win) - (setq +doom-modeline-current-window win) - (force-mode-line-update)))) - -(defun +doom-modeline|unset-selected-window () - (setq +doom-modeline-current-window nil) - (force-mode-line-update)) - -(add-hook 'window-configuration-change-hook #'+doom-modeline|set-selected-window) -(add-hook 'doom-enter-window-hook #'+doom-modeline|set-selected-window) -(with-no-warnings - (cond ((not (boundp 'after-focus-change-function)) - (add-hook 'focus-in-hook #'+doom-modeline|set-selected-window) - (add-hook 'focus-out-hook #'+doom-modeline|unset-selected-window)) - ((defun +doom-modeline|refresh-frame () - (setq +doom-modeline-current-window nil) - (cl-loop for frame in (frame-list) - if (eq (frame-focus-state frame) t) - return (setq +doom-modeline-current-window (frame-selected-window frame))) - (force-mode-line-update)) - (add-function :after after-focus-change-function #'+doom-modeline|refresh-frame)))) - - -;; -;; Variables - -(defvar +doom-modeline-height 23 - "How tall the mode-line should be (only respected in GUI emacs).") - -(defvar +doom-modeline-bar-width 3 - "How wide the mode-line bar should be (only respected in GUI emacs).") - -(defvar +doom-modeline-buffer-file-name-style 'truncate-upto-project - "Determines the style used by `+doom-modeline-buffer-file-name'. - -Given ~/Projects/FOSS/emacs/lisp/comint.el -truncate-upto-project => ~/P/F/emacs/lisp/comint.el -truncate-upto-root => ~/P/F/e/lisp/comint.el -truncate-all => ~/P/F/e/l/comint.el -relative-from-project => emacs/lisp/comint.el -relative-to-project => lisp/comint.el -file-name => comint.el") - -;; externs -(defvar anzu--state nil) -(defvar evil-mode nil) -(defvar evil-state nil) -(defvar evil-visual-selection nil) -(defvar iedit-mode nil) -(defvar all-the-icons-scale-factor) -(defvar all-the-icons-default-adjust) - - -;; -;; Modeline helpers - -(defun active () - (eq (selected-window) +doom-modeline-current-window)) - -(defun +doom-modeline--make-xpm (face width height) - "Create an XPM bitmap. Inspired by `powerline''s `pl/make-xpm'." - (propertize - " " 'display - (let ((data (make-list height (make-list width 1))) - (color (or (face-background face nil t) "None"))) - (ignore-errors - (create-image - (concat - (format "/* XPM */\nstatic char * percent[] = {\n\"%i %i 2 1\",\n\". c %s\",\n\" c %s\"," - (length (car data)) - (length data) - color - color) - (apply #'concat - (cl-loop with idx = 0 - with len = (length data) - for dl in data - do (cl-incf idx) - collect - (concat "\"" - (cl-loop for d in dl - if (= d 0) collect (string-to-char " ") - else collect (string-to-char ".")) - (if (eq idx len) "\"};" "\",\n"))))) - 'xpm t :ascent 'center))))) - -(defun +doom-modeline-buffer-file-name () - "Propertized `buffer-file-name' based on `+doom-modeline-buffer-file-name-style'." - (let ((buffer-file-name (or (buffer-file-name (buffer-base-buffer)) ""))) - (unless buffer-file-truename - (setq buffer-file-truename (file-truename buffer-file-name))) - (propertize - (pcase +doom-modeline-buffer-file-name-style - (`truncate-upto-project - (+doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink)) - (`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)) - (`relative-to-project - (+doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename)) - (`relative-from-project - (+doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename 'include-project)) - (`file-name - (propertize (file-name-nondirectory buffer-file-name) - 'face - (let ((face (or (and (buffer-modified-p) - 'doom-modeline-buffer-modified) - (and (active) - 'doom-modeline-buffer-file)))) - (when face `(:inherit ,face)))))) - 'help-echo buffer-file-truename))) - -(defun +doom-modeline--buffer-file-name-truncate (file-path true-file-path &optional truncate-tail) - "Propertized `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))) - (active (active))) - (if (null dirs) - (propertize "%b" 'face (if active 'doom-modeline-buffer-file)) - (let ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified))) - (let ((dirname (car dirs)) - (basename (cdr dirs)) - (dir-faces (or modified-faces (if active 'doom-modeline-project-root-dir))) - (file-faces (or modified-faces (if active 'doom-modeline-buffer-file)))) - (concat (propertize (concat dirname - (if truncate-tail (substring basename 0 1) basename) - "/") - 'face (if dir-faces `(:inherit ,dir-faces))) - (propertize (file-name-nondirectory file-path) - 'face (if file-faces `(:inherit ,file-faces))))))))) - -(defun +doom-modeline--buffer-file-name-relative (_file-path true-file-path &optional include-project) - "Propertized `buffer-file-name' showing directories relative to project's root only." - (let ((root (or (doom-project-root) default-directory)) - (active (active))) - (if (null root) - (propertize "%b" 'face (if active 'doom-modeline-buffer-file)) - (let* ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified)) - (relative-dirs (file-relative-name (file-name-directory true-file-path) - (if include-project (concat root "../") root))) - (relative-faces (or modified-faces (if active 'doom-modeline-buffer-path))) - (file-faces (or modified-faces (if active 'doom-modeline-buffer-file)))) - (if (equal "./" relative-dirs) (setq relative-dirs "")) - (concat (propertize relative-dirs 'face (if relative-faces `(:inherit ,relative-faces))) - (propertize (file-name-nondirectory true-file-path) - 'face (if file-faces `(:inherit ,file-faces)))))))) - -(defun +doom-modeline--buffer-file-name (file-path _true-file-path &optional truncate-project-root-parent) - "Propertized `buffer-file-name'. -If TRUNCATE-PROJECT-ROOT-PARENT is t space will be saved by truncating it down -fish-shell style. - -Example: -~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el" - (let* ((project-root (or (doom-project-root) default-directory)) - (file-name-split (shrink-path-file-mixed project-root - (file-name-directory file-path) - file-path)) - (active (active))) - (if (null file-name-split) - (propertize "%b" 'face (if active 'doom-modeline-buffer-file)) - (pcase-let ((`(,root-path-parent ,project ,relative-path ,file-path) file-name-split)) - (let ((modified-faces (if (buffer-modified-p) 'doom-modeline-buffer-modified))) - (let ((sp-faces (or modified-faces (if active 'font-lock-comment-face))) - (project-faces (or modified-faces (if active 'font-lock-string-face))) - (relative-faces (or modified-faces (if active 'doom-modeline-buffer-path))) - (file-faces (or modified-faces (if active 'doom-modeline-buffer-file)))) - (let ((sp-props `(,@(if sp-faces `(:inherit ,sp-faces)) ,@(if active '(:weight bold)))) - (project-props `(,@(if project-faces `(:inherit ,project-faces)) ,@(if active '(:weight bold)))) - (relative-props `(,@(if relative-faces `(:inherit ,relative-faces)))) - (file-props `(,@(if file-faces `(:inherit ,file-faces))))) - (concat (propertize (if truncate-project-root-parent - root-path-parent - (abbreviate-file-name project-root)) - 'face sp-props) - (propertize (concat project "/") 'face project-props) - (if relative-path (propertize relative-path 'face relative-props)) - (propertize file-path 'face file-props))))))))) - - -;; -;; buffer information - -(def-modeline-segment! buffer-default-directory - "Displays `default-directory'. This is for special buffers like the scratch -buffer where knowing the current project directory is important." - (let ((face (if (active) 'doom-modeline-buffer-path))) - (concat (if (display-graphic-p) " ") - (all-the-icons-octicon - "file-directory" - :face face - :v-adjust -0.05 - :height 1.25) - (propertize (concat " " (abbreviate-file-name default-directory)) - 'face face)))) - -(def-modeline-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 (cond (buffer-read-only - (concat (all-the-icons-octicon - "lock" - :face 'doom-modeline-warning - :v-adjust -0.05) - " ")) - ((buffer-modified-p) - (concat (all-the-icons-faicon - "floppy-o" - :face 'doom-modeline-buffer-modified - :v-adjust -0.0575) - " ")) - ((and buffer-file-name - (not (file-exists-p buffer-file-name))) - (concat (all-the-icons-octicon - "circle-slash" - :face 'doom-modeline-urgent - :v-adjust -0.05) - " ")) - ((buffer-narrowed-p) - (concat (all-the-icons-octicon - "fold" - :face 'doom-modeline-warning - :v-adjust -0.05) - " "))) - (if buffer-file-name - (+doom-modeline-buffer-file-name) - "%b"))) - -(def-modeline-segment! buffer-info-simple - "Display only the current buffer's name, but with fontification." - (propertize - "%b" - 'face (cond ((and buffer-file-name (buffer-modified-p)) - 'doom-modeline-buffer-modified) - ((active) 'doom-modeline-buffer-file)))) - -;; (defvar +doom-modeline--encoding nil) -;; (def-modeline-segment! buffer-encoding -;; "TODO" -;; +doom-modeline--encoding) - -;; (add-variable-watcher -;; 'buffer-file-coding-system -;; (lambda (_sym val op _where) -;; (when (eq op 'set) -;; (setq +doom-modeline--encoding -;; (concat (pcase (coding-system-eol-type val) -;; (0 "LF ") -;; (1 "CRLF ") -;; (2 "CR ")) -;; (let ((sys (coding-system-plist val))) -;; (if (memq (plist-get sys :category) '(coding-category-undecided coding-category-utf-8)) -;; "UTF-8" -;; (upcase (symbol-name (plist-get sys :name))))) -;; " "))))) - -(def-modeline-segment! buffer-encoding - "Displays the encoding and eol style of the buffer the same way Atom does." - (concat (pcase (coding-system-eol-type buffer-file-coding-system) - (0 "LF ") - (1 "CRLF ") - (2 "CR ")) - (let ((sys (coding-system-plist buffer-file-coding-system))) - (cond ((memq (plist-get sys :category) '(coding-category-undecided coding-category-utf-8)) - "UTF-8") - (t (upcase (symbol-name (plist-get sys :name)))))) - " ")) - - -;; -;; major-mode - -(def-modeline-segment! major-mode - "The major mode, including process, environment and text-scale info." - (propertize - (concat (format-mode-line mode-name) - (when (stringp mode-line-process) - mode-line-process) - (and (boundp 'text-scale-mode-amount) - (/= text-scale-mode-amount 0) - (format " (%+d)" text-scale-mode-amount))) - 'face (if (active) 'doom-modeline-buffer-major-mode))) - - -;; -;; vcs - -(defvar-local +doom-modeline--vcs nil) -(defun +doom-modeline--update-vcs () - (setq +doom-modeline--vcs - (when (and vc-mode buffer-file-name) - (let* ((backend (vc-backend buffer-file-name)) - (state (vc-state buffer-file-name backend))) - (let ((face 'mode-line-inactive) - (active (active)) - (all-the-icons-default-adjust -0.1)) - (concat " " - (cond ((memq state '(edited added)) - (if active (setq face 'doom-modeline-info)) - (all-the-icons-octicon - "git-compare" - :face face - :v-adjust -0.05)) - ((eq state 'needs-merge) - (if active (setq face 'doom-modeline-info)) - (all-the-icons-octicon "git-merge" :face face)) - ((eq state 'needs-update) - (if active (setq face 'doom-modeline-warning)) - (all-the-icons-octicon "arrow-down" :face face)) - ((memq state '(removed conflict unregistered)) - (if active (setq face 'doom-modeline-urgent)) - (all-the-icons-octicon "alert" :face face)) - (t - (if active (setq face 'font-lock-doc-face)) - (all-the-icons-octicon - "git-compare" - :face face - :v-adjust -0.05))) - " " - (propertize (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)) - 'face (if active face)) - " ")))))) -(add-hook 'after-revert-hook #'+doom-modeline--update-vcs) -(add-hook 'after-save-hook #'+doom-modeline--update-vcs) -(add-hook 'find-file-hook #'+doom-modeline--update-vcs t) -(advice-add #'vc-refresh-state :after #'+doom-modeline--update-vcs) - -(def-modeline-segment! vcs - "Displays the current branch, colored based on its state." - +doom-modeline--vcs) - - -;; -;; flycheck - -(defvar +doom-modeline-vspc - (propertize " " 'face 'variable-pitch) - "TODO") - -(defun +doom-ml-icon (icon &optional text face voffset) - "Displays an octicon ICON with FACE, followed by TEXT. Uses -`all-the-icons-octicon' to fetch the icon." - (concat (if vc-mode " " " ") - (when icon - (concat - (all-the-icons-material icon :face face :height 1.1 :v-adjust (or voffset -0.2)) - (if text +doom-modeline-vspc))) - (if text (propertize text 'face face)) - (if vc-mode " " " "))) - -(defvar-local +doom-modeline--flycheck nil) -(add-hook 'flycheck-status-changed-functions #'+doom-modeline|update-flycheck-segment) -(add-hook 'flycheck-mode-hook #'+doom-modeline|update-flycheck-segment) - -(defun +doom-modeline|update-flycheck-segment (&optional status) - (setq +doom-modeline--flycheck - (pcase status - ('finished (if flycheck-current-errors - (let-alist (flycheck-count-errors flycheck-current-errors) - (let ((sum (+ (or .error 0) (or .warning 0)))) - (+doom-ml-icon "do_not_disturb_alt" - (number-to-string sum) - (if .error 'doom-modeline-urgent 'doom-modeline-warning) - -0.25))) - (+doom-ml-icon "check" nil 'doom-modeline-info))) - ('running (+doom-ml-icon "access_time" nil 'font-lock-doc-face -0.25)) - ('no-checker (+doom-ml-icon "sim_card_alert" "-" 'font-lock-doc-face)) - ('errored (+doom-ml-icon "sim_card_alert" "Error" 'doom-modeline-urgent)) - ('interrupted (+doom-ml-icon "pause" "Interrupted" 'font-lock-doc-face))))) - -(def-modeline-segment! flycheck - "Displays color-coded flycheck error status in the current buffer with pretty -icons." - +doom-modeline--flycheck) - - -;; -;; selection-info - -(defsubst doom-column (pos) - (save-excursion (goto-char pos) - (current-column))) - -(defvar-local +doom-modeline-enable-word-count nil - "If non-nil, a word count will be added to the selection-info modeline -segment.") - -(defun +doom-modeline|enable-word-count () (setq +doom-modeline-enable-word-count t)) -(add-hook 'text-mode-hook #'+doom-modeline|enable-word-count) - -(def-modeline-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 (active) (or mark-active (eq evil-state 'visual))) - (cl-destructuring-bind (beg . end) - (if (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 (cond ((or (bound-and-true-p rectangle-mark-mode) - (eq 'block evil-visual-selection)) - (let ((cols (abs (- (doom-column end) - (doom-column beg))))) - (format "%dx%dB" lines cols))) - ((eq evil-visual-selection 'line) - (format "%dL" lines)) - ((> lines 1) - (format "%dC %dL" (- end beg) lines)) - ((format "%dC" (- end beg)))) - (when +doom-modeline-enable-word-count - (format " %dW" (count-words beg end))))) - 'face 'doom-modeline-highlight)))) - - -;; -;; matches (anzu, evil-substitute, iedit, macro) - -(defun +doom-modeline--macro-recording () - "Display current Emacs or evil macro being recorded." - (when (and (active) (or defining-kbd-macro executing-kbd-macro)) - (let ((sep (propertize " " 'face 'doom-modeline-panel))) - (concat sep - (propertize (if (bound-and-true-p evil-this-macro) - (char-to-string evil-this-macro) - "Macro") - 'face 'doom-modeline-panel) - sep - (all-the-icons-octicon "triangle-right" - :face 'doom-modeline-panel - :v-adjust -0.05) - sep)))) - -(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 anzu--state (not iedit-mode)) - (propertize - (let ((here anzu--current-position) - (total anzu--total-matched)) - (cond ((eq anzu--state 'replace-query) - (format " %d replace " total)) - ((eq anzu--state 'replace) - (format " %d/%d " here total)) - (anzu--overflow-p - (format " %s+ " total)) - (t - (format " %s/%d " here total)))) - 'face (if (active) 'doom-modeline-panel)))) - -(defsubst +doom-modeline--evil-substitute () - "Show number of matches for evil-ex substitutions and highlights in real time." - (when (and evil-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 (active) 'doom-modeline-panel)))) - -(defun doom-themes--overlay-sort (a 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 iedit-mode iedit-occurrences-overlays) - (propertize - (let ((this-oc (or (let ((inhibit-message t)) - (iedit-find-current-occurrence-overlay)) - (progn (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-themes--overlay-sort))) - -1) - "-") - length)) - 'face (if (active) 'doom-modeline-panel)))) - -(def-modeline-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." - (let ((meta (concat (+doom-modeline--macro-recording) - (+doom-modeline--anzu) - (+doom-modeline--evil-substitute) - (+doom-modeline--iedit)))) - (or (and (not (equal meta "")) meta) - (if buffer-file-name " %I ")))) - - -;; -;; media-info - -(def-modeline-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) - (image-size (image-get-display-property) :pixels) - (format " %dx%d " width height))))) - - -;; -;; bar - -(defvar +doom-modeline--bar-active nil) -(defvar +doom-modeline--bar-inactive nil) -(def-modeline-segment! bar - "The bar regulates the height of the mode-line in GUI Emacs. -Returns \"\" to not break --no-window-system." - (if window-system - (if (active) - +doom-modeline--bar-active - +doom-modeline--bar-inactive) - "")) - -(when EMACS26+ - (add-variable-watcher - '+doom-modeline-height - (lambda (_sym val op _where) - (when (and (eq op 'set) (integerp val)) - (+doom-modeline|refresh-bars +doom-modeline-bar-width val)))) - - (add-variable-watcher - '+doom-modeline-bar-width - (lambda (_sym val op _where) - (when (and (eq op 'set) (integerp val)) - (+doom-modeline|refresh-bars val +doom-modeline-height)))) - - (add-hook 'doom-big-font-mode-hook #'+doom-modeline|resize-for-big-font)) - - -;; -;; Mode lines - -(def-modeline! 'main - '(bar matches " " buffer-info " %l:%c %p " selection-info) - '(buffer-encoding major-mode vcs flycheck)) - -(def-modeline! 'minimal - '(bar matches " " buffer-info) - '(media-info major-mode)) - -(def-modeline! 'special - '(bar matches " " buffer-info-simple " %l:%c %p " selection-info) - '(buffer-encoding major-mode flycheck)) - -(def-modeline! 'project - '(bar buffer-default-directory) - '(major-mode)) - -(def-modeline! 'media - '(bar " %b ") - '(media-info major-mode)) - - -;; -;; Hooks - -(defun +doom-modeline|refresh-bars (&optional width height) - (setq +doom-modeline--bar-active - (+doom-modeline--make-xpm 'doom-modeline-bar - (or width +doom-modeline-bar-width) - (or height +doom-modeline-height)) - +doom-modeline--bar-inactive - (+doom-modeline--make-xpm 'doom-modeline-inactive-bar - (or width +doom-modeline-bar-width) - (or height +doom-modeline-height)))) - -(defun +doom-modeline|init () - ;; Create bars - (+doom-modeline|refresh-bars) - (unless after-init-time - ;; These buffers are already created and don't get modelines. For the love - ;; of Emacs, someone give the man a modeline! - (dolist (bname '("*scratch*" "*Messages*")) - (with-current-buffer bname - (doom-set-modeline 'main))))) - -(defun +doom-modeline|set-special-modeline () - (doom-set-modeline 'special)) - -(defun +doom-modeline|set-media-modeline () - (doom-set-modeline 'media)) - -(defun +doom-modeline|set-project-modeline () - (doom-set-modeline 'project)) - - -;; -;; Bootstrap - -(doom-set-modeline 'main t) ; set default modeline - -(add-hook 'doom-load-theme-hook #'+doom-modeline|init) -(add-hook 'doom-scratch-buffer-hook #'+doom-modeline|set-special-modeline) -(add-hook '+doom-dashboard-mode-hook #'+doom-modeline|set-project-modeline) - -(add-hook 'image-mode-hook #'+doom-modeline|set-media-modeline) -(add-hook 'circe-mode-hook #'+doom-modeline|set-special-modeline) - -;; Ensure modeline is inactive when Emacs is unfocused (and active otherwise) -(defvar +doom-modeline-remap-face-cookie nil) -(defun +doom-modeline|focus () - (when +doom-modeline-remap-face-cookie - (require 'face-remap) - (face-remap-remove-relative +doom-modeline-remap-face-cookie))) -(defun +doom-modeline|unfocus () - (setq +doom-modeline-remap-face-cookie (face-remap-add-relative 'mode-line 'mode-line-inactive))) - -(add-hook 'focus-in-hook #'+doom-modeline|focus) -(add-hook 'focus-out-hook #'+doom-modeline|unfocus) diff --git a/modules/ui/doom-modeline/packages.el b/modules/ui/doom-modeline/packages.el deleted file mode 100644 index 72f5044df..000000000 --- a/modules/ui/doom-modeline/packages.el +++ /dev/null @@ -1,20 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; ui/doom-modeline/packages.el - -;;; These are the invisible dependencies -;; Required -;;(require 'evil) -;;(require 'projectile) -;;(require 'all-the-icons) - -;; Optional -;;(require 'flycheck) -;;(require 'iedit) -;;(require 'evil-multiedit) - -(package! anzu) - -(when (featurep! :feature evil) - (package! evil-anzu)) - -(package! shrink-path) diff --git a/modules/ui/modeline/autoload.el b/modules/ui/modeline/autoload.el new file mode 100644 index 000000000..0c0a8a955 --- /dev/null +++ b/modules/ui/modeline/autoload.el @@ -0,0 +1,35 @@ +;;; ui/modeline/autoload/modeline.el -*- lexical-binding: t; -*- + +;;;###autodef +(defalias 'def-modeline-format! 'doom-modeline-def-segment) + +;;;###autodef +(defalias 'def-modeline-segment! 'doom-modeline-def-modeline) + +;;;###autodef +(defalias 'set-modeline! 'doom-modeline-set-modeline) + + +(defvar +modeline--old-bar-height nil) +;;;###autoload +(defun +modeline|resize-for-big-font () + "Adjust the modeline's height when `doom-big-font-mode' is enabled. This was +made to be added to `doom-big-font-mode-hook'." + (unless +modeline--old-bar-height + (setq +modeline--old-bar-height doom-modeline-height)) + (let ((default-height +modeline--old-bar-height)) + (if doom-big-font-mode + (let* ((font-size (font-get doom-font :size)) + (big-size (font-get doom-big-font :size)) + (ratio (/ (float big-size) font-size))) + (setq doom-modeline-height (ceiling (* default-height ratio 0.75)))) + (setq doom-modeline-height default-height)) + ;; already has a variable watcher in Emacs 26+ + (unless EMACS26+ (doom-modeline-refresh-bars)))) + +;;;###autoload +(defun +modeline|update-env-in-all-windows (&rest _) + "" + (dolist (window (window-list)) + (with-selected-window window + (doom-modeline-update-env)))) diff --git a/modules/ui/modeline/autoload/modeline.el b/modules/ui/modeline/autoload/modeline.el deleted file mode 100644 index ef9d21a59..000000000 --- a/modules/ui/modeline/autoload/modeline.el +++ /dev/null @@ -1,19 +0,0 @@ -;;; ui/modeline/autoload/modeline.el -*- lexical-binding: t; -*- - -;; (defvar +modeline--old-bar-height nil) -;; ;;;###autoload -;; (defun +modeline|resize-for-big-font () -;; "Adjust the modeline's height when `doom-big-font-mode' is enabled. This was -;; made to be added to `doom-big-font-mode-hook'." -;; (unless +modeline--old-bar-height -;; (setq +modeline--old-bar-height +doom-modeline-height)) -;; (let ((default-height +modeline--old-bar-height)) -;; (if doom-big-font-mode -;; (let* ((font-size (font-get doom-font :size)) -;; (big-size (font-get doom-big-font :size)) -;; (ratio (/ (float big-size) font-size))) -;; (setq +doom-modeline-height (ceiling (* default-height ratio 0.75)))) -;; (setq +doom-modeline-height default-height)) -;; ;; already has a variable watcher in Emacs 26+ -;; (unless EMACS26+ (+doom-modeline|refresh-bars)))) - diff --git a/modules/ui/modeline/autoload/settings.el b/modules/ui/modeline/autoload/settings.el deleted file mode 100644 index 3e0441aae..000000000 --- a/modules/ui/modeline/autoload/settings.el +++ /dev/null @@ -1,104 +0,0 @@ -;;; ui/modeline/autoload/settings.el -*- lexical-binding: t; -*- - -(defvar +modeline--alist nil) - -(defun +modeline--segment-active-p (segment xs) - (cond ((null xs) nil) - ((listp xs) - (or (+modeline--segment-active-p segment (car xs)) - (+modeline--segment-active-p segment (cdr xs)))) - ((eq xs segment)))) - -;;;###autoload -(defun +modeline-segment-active-p (segment) - (or (+modeline--segment-active-p segment +modeline-format-left) - (+modeline--segment-active-p segment +modeline-format-right))) - -;;;###autodef -(defun def-modeline-format! (name left &optional right) - "Define a preset modeline format by name. - -NAME is a symbol. The convention is to use keywords for global formats, like -:main or :project, but to use regular symbols for buffer-local formats, like -'twitter and 'pdf. - -LEFT and RIGHT are lists that assume the same structure as `mode-line-format', -and make up the mode-line in two parts, separated by variable-width space, to -keep them left and right aligned respectively." - (setf (alist-get name +modeline--alist) (list left right))) - -;;;###autodef -(defmacro def-modeline-segment! (name &rest rest) - "TODO" - (declare (doc-string 2)) - (let ((docstring (if (and (stringp (car rest)) (cdr rest)) (pop rest))) - body) - (macroexp-progn - (if (not (keywordp (car rest))) - (append `((defvar-local ,name nil ,docstring) - (put ',name 'risky-local-variable t)) - (if (or (stringp (car rest)) - (memq (car (car-safe rest)) '(:eval :propertize))) - `((setq-default ,name ,(car rest))) - (let ((fn (intern (format "+modeline--%s" name)))) - `((fset ',fn (lambda () ,@rest)) - (byte-compile ',fn) - (setq-default ,name (quote (:eval (,fn)))))))) - ;; isolate body - (setq body rest) - (while (keywordp (car body)) - (setq body (cddr body))) - ;; - (cl-destructuring-bind (&key init faces on-hooks on-set &allow-other-keys) - rest - (let ((realvar (if (and body faces) - (intern (format "+modeline--var-%s" name)) - name))) - (append (when body - (if (or on-hooks on-set) - (let ((setterfn (intern (format "+modeline--set-%s" name))) - (varsetterfn (intern (format "+modeline--setvar-%s" name)))) - (append `((fset ',setterfn - (lambda (&rest _) - (when (+modeline-segment-active-p ',name) - (setq-local ,realvar ,(macroexp-progn body))))) - (byte-compile ',setterfn)) - (mapcar (lambda (hook) `(add-hook ',hook #',setterfn)) - on-hooks) - (when on-set - `((fset ',varsetterfn - (lambda (sym val op where) - (and (eq op 'set) where - (with-current-buffer where - (set sym val) - (,setterfn))))) - ,@(mapcan (lambda (var) `((add-variable-watcher ',var #',varsetterfn))) - on-set))))) - (setq init `(quote (:eval ,(macroexp-progn body)))) - nil)) - (if (eq realvar name) - `((defvar-local ,name nil ,docstring) - (setq-default ,name ,init)) - `((defvar-local ,realvar ,init) - (defvar-local ,name nil ,docstring) - (setq-default - ,name '(:eval (cond ((active) ,realvar) - (,realvar (substring-no-properties ,realvar))))))) - `((put ',name 'risky-local-variable t))))))))) - -;;;###autodef -(defun set-modeline! (name &optional default) - "Replace the current buffer's modeline with a preset mode-line format defined -with `def-modeline-format!'. - -If DEFAULT is non-nil, make it the default mode-line for all buffers." - (cl-check-type name symbol) - (let ((modeline (cdr (assq name +modeline--alist)))) - (unless modeline - (error "The %s modeline format does not exist" name)) - (if default - (setq-default +modeline-format-left `("" ,@(car modeline)) - +modeline-format-right `("" ,@(cadr modeline))) - (setq +modeline-format-left `("" ,@(car modeline)) - +modeline-format-right `("" ,@(cadr modeline)))) - (force-mode-line-update))) diff --git a/modules/ui/modeline/config.el b/modules/ui/modeline/config.el index 2c0da1d02..121221daa 100644 --- a/modules/ui/modeline/config.el +++ b/modules/ui/modeline/config.el @@ -1,750 +1,53 @@ ;;; ui/modeline/config.el -*- lexical-binding: t; -*- -;; This mode-line is experimental, Emacs 26+ only, may have buggy and is likely -;; to change. It also isn't feature complete, compared to :ui doom-modeline, but -;; it will eventually replace it. -;; -;; However, it is at least ten times faster than the original modeline, and more -;; flexible, what with `+modeline-format-left', `+modeline-format-right', and a -;; more powerful API for defining modelines and modeline segments. +;; TODO Add themes (default, minimal, spacemacs, etc) -;;;; Benchmarks -;; (benchmark-run 1000 (format-mode-line mode-line-format)) -;; Old system: ~0.563 - 0.604 -;; New system: ~0.036 - 0.061 +(def-package! doom-modeline + :hook (doom-post-init . doom-modeline-mode) + :preface + ;; prevent flash of unstyled modeline at startup + (setq-default mode-line-format nil) + ;; We display project info in the modeline ourselves + (setq projectile-dynamic-mode-line nil) + :init + (setq doom-modeline-bar-width 3 + doom-modeline-github nil + doom-modeline-mu4e nil + doom-modeline-persp-name nil + doom-modeline-checker-simple-format nil + doom-modeline-minor-modes nil + doom-modeline-major-mode-icon nil + doom-modeline-buffer-file-name-style 'relative-from-project) -(defvar +modeline-width 3 - "How wide the mode-line bar should be (only respected in GUI emacs).") + (add-hook 'doom-modeline-mode-hook #'size-indication-mode) ; filesize in modeline + (add-hook 'doom-modeline-mode-hook #'column-number-mode) ; cursor column in modeline -(defvar +modeline-height 25 - "How tall the mode-line should be (only respected in GUI emacs).") + :config + (add-hook 'doom-big-font-mode-hook #'+modeline|resize-for-big-font) -(defvar +modeline-bar-at-end nil - "If non-nil, the bar is placed at the end, instead of at the beginning of the -modeline.") + (add-hook 'doom-load-theme-hook #'doom-modeline-refresh-bars) + (add-hook '+doom-dashboard-mode-hook #'doom-modeline-set-project-modeline) -(defvar +modeline-bar-invisible nil - "If non-nil, the bar is transparent, and only used to police the height of the -mode-line.") + ;; Remove unused segments & extra padding + (doom-modeline-def-modeline 'main + '(bar matches buffer-info remote-host buffer-position selection-info) + '(misc-info persp-name irc mu4e github debug input-method buffer-encoding lsp major-mode process vcs checker)) -(defvar +modeline-buffer-path-function #'+modeline-file-path-with-project - "A function that returns, in list form, components of the buffer file name -display in the mode-line. + (doom-modeline-def-modeline 'special + '(bar matches buffer-info-simple buffer-position selection-info) + '(misc-info persp-name debug input-method irc-buffers buffer-encoding lsp major-mode process checker)) -Each item should either be a string or a a cons cell whose CAR is the path -component and CDR is the name of a face. - -Currently available functions: - -+ `+modeline-file-path-with-project': project/src/lib/file.c -+ `+modeline-file-path-from-project': src/lib/file.c -+ `+modeline-file-path-truncated-with-project': project/s/l/file.c -+ `+modeline-file-path-truncated-upto-project': ~/w/project/src/lib/file.c -+ `+modeline-file-path-truncated-upto-project-root': ~/w/p/s/lib/file.c -+ `+modeline-file-path-truncated': ~/w/p/s/l/file.c -+ `+modeline-file-name': file.c") - -;; Convenience aliases -(defvaralias 'mode-line-format-left '+modeline-format-left) -(defvaralias 'mode-line-format-right '+modeline-format-right) -;; -(defvar-local +modeline-format-left () "TODO") -(defvar-local +modeline-format-right () "TODO") -(put '+modeline-format-left 'risky-local-variable t) -(put '+modeline-format-right 'risky-local-variable t) - -;; Otherwise appended segments will produce *Invalid* -(setq global-mode-string '("")) -;; We handle this ourselves -(setq projectile-dynamic-mode-line nil) - -;; -(defvar +modeline--vspc (propertize " " 'face 'variable-pitch)) - -;; externs -(defvar anzu--state nil) -(defvar evil-mode nil) -(defvar evil-state nil) -(defvar evil-visual-selection nil) -(defvar evil-visual-beginning nil) -(defvar evil-visual-end nil) -(defvar iedit-mode nil) -(defvar all-the-icons-scale-factor) -(defvar all-the-icons-default-adjust) + (doom-modeline-def-modeline 'project + '(bar buffer-default-directory) + '(misc-info mu4e github debug fancy-battery " " major-mode))) ;; -;; Custom faces - -(defgroup +modeline nil - "TODO" - :group 'faces) - -(defface doom-modeline-buffer-path - '((t (:inherit (mode-line-emphasis bold)))) - "Face used for the dirname part of the buffer path." - :group '+modeline) - -(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 '+modeline) - -(defface doom-modeline-buffer-project-root - '((t (:inherit doom-modeline-buffer-path))) - "Face used for the project root at the beginning of the mode-line path." - :group '+modeline) - -(defface doom-modeline-buffer-modified '((t (:inherit (error bold) :background nil))) - "Face used for the 'unsaved' symbol in the mode-line." - :group '+modeline) - -(defface doom-modeline-buffer-major-mode '((t (:inherit (mode-line-emphasis bold)))) - "Face used for the major-mode segment in the mode-line." - :group '+modeline) - -(defface doom-modeline-highlight '((t (:inherit mode-line-emphasis))) - "Face for bright segments of the mode-line." - :group '+modeline) - -(defface doom-modeline-panel '((t (:inherit mode-line-highlight))) - "Face for 'X out of Y' segments, such as `+modeline--anzu', -`+modeline--evil-substitute' and `iedit'" - :group '+modeline) - -(defface doom-modeline-info `((t (:inherit (success bold)))) - "Face for info-level messages in the modeline. Used by `*vc'." - :group '+modeline) - -(defface doom-modeline-warning `((t (:inherit (warning bold)))) - "Face for warnings in the modeline. Used by `*flycheck'" - :group '+modeline) - -(defface doom-modeline-urgent `((t (:inherit (error bold)))) - "Face for errors in the modeline. Used by `*flycheck'" - :group '+modeline) - -(defface doom-modeline-bar '((t (:inherit highlight))) - "The face used for the left-most bar on the mode-line of an active window." - :group '+modeline) - - -;; -;; Packages +;; Extensions (def-package! anzu - :after-call isearch-mode - :config - (setq anzu-cons-mode-line-p nil - anzu-minimum-input-length 1 - anzu-search-threshold 250) - (global-anzu-mode +1) - - (defun +modeline*fix-anzu-count (positions 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 #'+modeline*fix-anzu-count) - - ;; Avoid anzu conflicts across 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)) - ;; Ensure anzu state is cleared when searches & iedit are done - (add-hook 'isearch-mode-end-hook #'anzu--reset-status t) - (add-hook 'doom-escape-hook #'anzu--reset-status t) - (add-hook 'iedit-mode-end-hook #'anzu--reset-status)) - + :after-call isearch-mode) (def-package! evil-anzu :when (featurep! :feature evil) :after-call (evil-ex-start-search evil-ex-start-word-search)) - - -;; -;; Hacks - -;; Keep `+modeline-current-window' up-to-date -(defvar +modeline-current-window (frame-selected-window)) - -(defun +modeline|set-selected-window (&rest _) - "Sets `+modeline-current-window' appropriately" - (when-let* ((win (frame-selected-window))) - (unless (minibuffer-window-active-p win) - (setq +modeline-current-window win) - (force-mode-line-update)))) - -(defun +modeline|unset-selected-window () - (setq +modeline-current-window nil) - (force-mode-line-update)) - -(add-hook 'window-configuration-change-hook #'+modeline|set-selected-window) -(add-hook 'doom-enter-window-hook #'+modeline|set-selected-window) -(if (not (boundp 'after-focus-change-function)) - (progn - (add-hook 'focus-in-hook #'+modeline|set-selected-window) - (add-hook 'focus-out-hook #'+modeline|unset-selected-window)) - (defun +modeline|refresh-frame () - (setq +modeline-current-window nil) - (cl-loop for frame in (frame-list) - if (eq (frame-focus-state frame) t) - return (setq +modeline-current-window (frame-selected-window frame))) - (force-mode-line-update t)) - (add-function :after after-focus-change-function #'+modeline|refresh-frame)) - -(defsubst active () - (eq (selected-window) +modeline-current-window)) - -;; Ensure modeline is inactive when Emacs is unfocused (and active otherwise) -(defvar +modeline-remap-face-cookies nil) - -(defun +modeline|focus-all-windows (&rest _) - (cl-loop for (buffer . cookie) in +modeline-remap-face-cookies - if (buffer-live-p buffer) - do (with-current-buffer buffer - (face-remap-remove-relative cookie)))) - -(defun +modeline|unfocus-all-windows (&rest _) - (setq +modeline-remap-face-cookies - (cl-loop for window in (window-list) - for buffer = (window-buffer window) - if (buffer-live-p buffer) - collect - (with-current-buffer buffer - (cons buffer - (face-remap-add-relative 'mode-line - 'mode-line-inactive)))))) - -(add-hook 'focus-in-hook #'+modeline|focus-all-windows) -(add-hook 'focus-out-hook #'+modeline|unfocus-all-windows) -(advice-add #'posframe-hide :after #'+modeline|focus-all-windows) -(advice-add #'posframe-delete :after #'+modeline|focus-all-windows) -(when (featurep! :completion helm) - (add-hook 'helm-before-initialize-hook #'+modeline|unfocus-all-windows) - (add-hook 'helm-cleanup-hook #'+modeline|focus-all-windows)) - - -;; -;; Helpers - -(defun +modeline--make-xpm (width height &optional color) - "Create an XPM bitmap. Inspired by `powerline''s `pl/make-xpm'." - (propertize - " " 'display - (let ((data (make-list height (make-list width 1))) - (color (or color "None"))) - (ignore-errors - (create-image - (concat - (format "/* XPM */\nstatic char * percent[] = {\n\"%i %i 2 1\",\n\". c %s\",\n\" c %s\"," - (length (car data)) (length data) color color) - (cl-loop with idx = 0 - with len = (length data) - for dl in data - do (cl-incf idx) - concat "\"" - concat (cl-loop for d in dl - if (= d 0) collect (string-to-char " ") - else collect (string-to-char ".")) - concat (if (eq idx len) "\"};" "\",\n"))) - 'xpm t :ascent 'center))))) - -(defun +modeline-build-path (path) - "Construct the file path for the `+modeline-buffer-id' segment using -`+mdoeline-buffer-path-function'. If the buffer has no `buffer-file-name', just -use `buffer-name'." - (let ((buffer-file-name (or path buffer-file-name))) - (if (or (eq major-mode 'dired-mode) - (null buffer-file-name)) - (propertize "%s" 'face 'doom-modeline-buffer-path) - (cl-loop for spec in (funcall +modeline-buffer-path-function) - if (stringp spec) concat spec - else if (not (null spec)) - concat (propertize (car spec) 'face (cdr spec)))))) - - -;; -;; Buffer file path styles - -(defun +modeline-file-path-with-project () - "Returns the unaltered buffer file path relative to the project root's -parent. - -e.g. project/src/lib/file.c" - (let* ((base (buffer-base-buffer)) - (filename (file-truename (buffer-file-name base)))) - (append (if (doom-project-p) - (let* ((project-root (doom-project-root)) - (relative-dirs (file-relative-name (file-name-directory filename) - (file-truename project-root)))) - (list (cons (concat (doom-project-name) "/") - 'doom-modeline-buffer-project-root) - (unless (equal "./" relative-dirs) - (cons relative-dirs 'doom-modeline-buffer-path)))) - (list nil (cons (abbreviate-file-name (file-name-directory filename)) - 'doom-modeline-buffer-path))) - (list (cons (file-name-nondirectory filename) - 'doom-modeline-buffer-file))))) - -(defun +modeline-file-path-from-project () - "Returns file path relative to the project root. - -e.g. src/lib/file.c - -Meant for `+modeline-buffer-path-function'." - (cdr (+modeline-file-path-with-project))) - -(defun +modeline-file-path-truncated-with-project () - "Returns file path relative to (and including) project root, with descendent -folders truncated. - -e.g. project/s/l/file.c - -Meant for `+modeline-buffer-path-function'." - (let* ((parts (+modeline-file-path-with-project)) - (dirs (car (nth 1 parts)))) - (setcar (nth 1 parts) - (shrink-path--dirs-internal dirs t)) - parts)) - -(defun +modeline-file-path-truncated-upto-project () - "Returns file path, truncating segments prior to the project. - -e.g. ~/w/project/src/lib/file.c - -Meant for `+modeline-buffer-path-function'." - (pcase-let - ((`(,root-parent ,root ,dir, file) - (let ((buffer-file-name (or buffer-file-name (buffer-file-name (buffer-base-buffer))))) - (shrink-path-file-mixed (or (doom-project-root) default-directory) - (file-name-directory buffer-file-name) - buffer-file-name)))) - (list (cons root-parent 'font-lock-comment-face) - (cons root 'doom-modeline-buffer-project-root) - (cons (concat "/" dir) 'doom-modeline-buffer-path) - (cons file 'doom-modeline-buffer-file)))) - -(defun +modeline-file-path-truncated-upto-project-root () - "Return file path, truncating segemnts prior to (and including) the project -root. - -e.g. ~/w/p/src/lib/file.c - -Meant for `+modeline-buffer-path-function'." - (let* ((parts (+modeline-file-path-truncated-upto-project)) - (root (car (nth 1 parts)))) - (setcar (nth 1 parts) - (let ((first (substring root 0 1))) - (if (equal first ".") - (substring root 0 2) - first))) - parts)) - -(defun +modeline-file-path-truncated () - "Return absolute file path with all directories truncated. - -e.g. ~/w/p/s/l/file.c - -Meant for `+modeline-buffer-path-function'." - (pcase-let ((`(,dir . ,file) - (shrink-path-prompt (buffer-file-name (buffer-base-buffer))))) - (list (cons dir 'doom-modeline-buffer-path) - (cons file 'doom-modeline-buffer-file)))) - -(defun +modeline-file-name () - "Return buffer name. - -e.g. file.c - -Meant for `+modeline-buffer-path-function'." - (list (cons "%b" 'doom-modeline-buffer-path))) - - -;; -;; Bars - -(defvar +modeline-bar-start nil "TODO") -(put '+modeline-bar-start 'risky-local-variable t) -(defvar +modeline-bar-end nil "TODO") -(put '+modeline-bar-end 'risky-local-variable t) - -(defvar +modeline-bar-active nil "TODO") -(defvar +modeline-bar-inactive nil "TODO") -(defun +modeline|setup-bars () - (setq +modeline-bar-active - (+modeline--make-xpm +modeline-width +modeline-height - (unless +modeline-bar-invisible - (face-background 'doom-modeline-bar nil t))) - +modeline-bar-inactive - (+modeline--make-xpm +modeline-width +modeline-height)) - (setq +modeline-bar-start nil - +modeline-bar-end nil) - (if +modeline-bar-at-end - (setq +modeline-bar-end '+modeline-bar) - (setq +modeline-bar-start '+modeline-bar))) -(add-hook 'doom-load-theme-hook #'+modeline|setup-bars) - -(defun +modeline|setup-bars-after-change (sym val op _where) - (when (eq op 'set) - (set sym val) - (+modeline|setup-bars))) -(add-variable-watcher '+modeline-width #'+modeline|setup-bars-after-change) -(add-variable-watcher '+modeline-height #'+modeline|setup-bars-after-change) -(add-variable-watcher '+modeline-bar-at-end #'+modeline|setup-bars-after-change) -(add-variable-watcher '+modeline-bar-invisible #'+modeline|setup-bars-after-change) - -(def-modeline-segment! +modeline-bar - (if (active) +modeline-bar-active +modeline-bar-inactive)) - - -;; -;; Segments - -(def-modeline-segment! +modeline-buffer-state - (let* ((base (buffer-base-buffer)) - (icon (cond (buffer-read-only - (all-the-icons-octicon - "lock" - :face 'doom-modeline-warning - :v-adjust -0.05)) - ((buffer-modified-p base) - (all-the-icons-faicon - "floppy-o" - :face 'doom-modeline-buffer-modified - :v-adjust -0.05)) - ((and (buffer-file-name base) - (not (file-exists-p (buffer-file-name base)))) - (all-the-icons-octicon - "circle-slash" - :face 'doom-modeline-urgent - :v-adjust -0.05))))) - (if icon (concat icon " ")))) - -(def-modeline-segment! +modeline-buffer-id - :on-hooks (find-file-hook after-save-hook after-revert-hook) - :init (propertize "%b" 'face 'doom-modeline-buffer-file) - :faces t - (let ((file-path (buffer-file-name (buffer-base-buffer)))) - (propertize (+modeline-build-path file-path) - 'help-echo file-path))) - -(def-modeline-segment! +modeline-buffer-directory - (let ((face (if (active) 'doom-modeline-buffer-path))) - (propertize - (concat (if (display-graphic-p) " ") - (all-the-icons-octicon - "file-directory" - :face face - :v-adjust -0.1 - :height 1.25) - " " - (propertize (abbreviate-file-name default-directory) - 'face face)) - 'help-echo default-directory))) - -(def-modeline-segment! +modeline-vcs - :on-set (vc-mode) - (when (and vc-mode buffer-file-name) - (let* ((backend (vc-backend buffer-file-name)) - (state (vc-state buffer-file-name backend))) - (let ((face 'mode-line-inactive) - (active (active)) - (all-the-icons-default-adjust -0.1)) - (concat (cond ((memq state '(edited added)) - (if active (setq face 'doom-modeline-info)) - (all-the-icons-octicon - "git-compare" - :face face - :v-adjust -0.05)) - ((eq state 'needs-merge) - (if active (setq face 'doom-modeline-info)) - (all-the-icons-octicon "git-merge" :face face)) - ((eq state 'needs-update) - (if active (setq face 'doom-modeline-warning)) - (all-the-icons-octicon "arrow-down" :face face)) - ((memq state '(removed conflict unregistered)) - (if active (setq face 'doom-modeline-urgent)) - (all-the-icons-octicon "alert" :face face)) - (t - (if active (setq face 'font-lock-doc-face)) - (all-the-icons-octicon - "git-compare" - :face face - :v-adjust -0.05))) - +modeline--vspc - (propertize (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)) - 'face (if active face))))))) - -(def-modeline-segment! +modeline-indent-style - :on-hooks (after-revert-hook after-save-hook find-file-hook) - :on-set (indent-tabs-mode tab-width) - (propertize (format "%s%d " - (if indent-tabs-mode "⭾" "␣") - tab-width) - 'help-echo - (format "Indentation: %d %s wide" - tab-width - (if indent-tabs-mode "tabs" "spaces")))) - -(def-modeline-segment! +modeline-encoding - :on-hooks (after-revert-hook after-save-hook find-file-hook) - :on-set (buffer-file-coding-system) - (concat (pcase (coding-system-eol-type buffer-file-coding-system) - (0 (propertize "LF" 'help-echo "EOL convention: \\n (Unix)")) - (1 (propertize "CRLF" 'help-echo "EOL convention: \\r\\n (Windows, Symbian OS, etc)")) - (2 (propertize "CR" 'help-echo "EOL convention: \\r (pre-OSX MacOS)"))) - " " - (let* ((sys (coding-system-plist buffer-file-coding-system)) - (category (plist-get sys :category))) - (propertize - (cond ((eq category 'coding-category-undecided) - "") - ((or (eq category 'coding-category-utf-8) - (string-match-p "utf-8" (symbol-name (plist-get sys :name)))) - "") - ((concat (upcase (symbol-name (plist-get sys :name))) - " "))) - 'help-echo (plist-get (coding-system-plist buffer-file-coding-system) :docstring))))) - -(def-modeline-segment! +modeline-major-mode - (propertize (format-mode-line mode-name) - 'face (if (active) 'doom-modeline-buffer-major-mode))) - -(defun +modeline--macro-recording () - "Display current Emacs or evil macro being recorded." - (when (and (active) (or defining-kbd-macro executing-kbd-macro)) - (let ((sep (propertize " " 'face 'doom-modeline-panel))) - (concat sep - (propertize (if (bound-and-true-p evil-this-macro) - (char-to-string evil-this-macro) - "Macro") - 'face 'doom-modeline-panel) - sep - (all-the-icons-octicon "triangle-right" - :face 'doom-modeline-panel - :v-adjust -0.05) - sep)))) - -(defsubst +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 anzu--state (not iedit-mode)) - (propertize - (let ((here anzu--current-position) - (total anzu--total-matched)) - (cond ((eq anzu--state 'replace-query) - (format " %d replace " total)) - ((eq anzu--state 'replace) - (format " %d/%d " here total)) - (anzu--overflow-p - (format " %s+ " total)) - ((format " %s/%d " here total)))) - 'face (if (active) 'doom-modeline-panel)))) - -(defsubst +modeline--evil-substitute () - "Show number of matches for evil-ex substitutions and highlights in real time." - (when (and evil-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 (active) 'doom-modeline-panel)))) - -(defun doom-themes--overlay-sort (a b) - (< (overlay-start a) (overlay-start b))) - -(defsubst +modeline--iedit () - "Show the number of iedit regions matches + what match you're on." - (when (and iedit-mode iedit-occurrences-overlays) - (propertize - (let ((this-oc (or (let ((inhibit-message t)) - (iedit-find-current-occurrence-overlay)) - (progn (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-themes--overlay-sort))) - -1) - "-") - length)) - 'face (if (active) 'doom-modeline-panel)))) - -(defun +doom-ml-octicon (icon &optional text face voffset padding) - "Displays an octicon ICON with FACE, followed by TEXT. Uses -`all-the-icons-octicon' to fetch the icon." - (let ((padding-str (if padding (propertize (make-string padding ? ) 'face face)))) - (concat padding-str - (when icon - (all-the-icons-octicon icon :face face :height 1.1 :v-adjust (or voffset -0.2))) - (if text (propertize (concat " " text) 'face face)) - padding-str))) - -(defsubst +modeline--multiple-cursors () - "Show the number of multiple cursors." - (cond ((bound-and-true-p multiple-cursors-mode) - (propertize - (concat " mc " (eval (cadadr mc/mode-line)) " ") - 'face (if (active) 'doom-modeline-panel))) - ((bound-and-true-p evil-mc-cursor-list) - (+doom-ml-octicon (if evil-mc-frozen "pin" "pencil") - (number-to-string (length evil-mc-cursor-list)) - (if (active) 'doom-modeline-panel) - 0 - 1)))) - -(def-modeline-segment! +modeline-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." - (let ((meta (concat (+modeline--macro-recording) - (+modeline--anzu) - (+modeline--evil-substitute) - (+modeline--iedit) - (+modeline--multiple-cursors) - " "))) - (or (and (not (equal meta " ")) meta) - (if buffer-file-name " %I ")))) - -;; -(defsubst doom-column (pos) - (save-excursion (goto-char pos) - (current-column))) - -(defvar-local +modeline-enable-word-count nil - "If non-nil, a word count will be added to the selection-info modeline -segment.") - -(defun +modeline|enable-word-count () - (setq +modeline-enable-word-count t)) -(add-hook 'text-mode-hook #'+modeline|enable-word-count) - -(def-modeline-segment! +modeline-selection-info - (let ((beg (or evil-visual-beginning (region-beginning))) - (end (or evil-visual-end (region-end)))) - (propertize - (let ((lines (count-lines beg (min end (point-max))))) - (concat (cond ((or (bound-and-true-p rectangle-mark-mode) - (eq 'block evil-visual-selection)) - (let ((cols (abs (- (doom-column end) - (doom-column beg))))) - (format "%dx%dB" lines cols))) - ((eq evil-visual-selection 'line) - (format "%dL" lines)) - ((> lines 1) - (format "%dC %dL" (- end beg) lines)) - ((format "%dC" (- end beg)))) - (when +modeline-enable-word-count - (format " %dW" (count-words beg end))))) - 'face 'doom-modeline-highlight))) - -(defun +modeline|enable-selection-info () - (add-to-list '+modeline-format-left '+modeline-selection-info t #'eq)) -(defun +modeline|disable-selection-info () - (setq +modeline-format-left (delq '+modeline-selection-info +modeline-format-left))) -(cond ((featurep 'evil) - (add-hook 'evil-visual-state-entry-hook #'+modeline|enable-selection-info) - (add-hook 'evil-visual-state-exit-hook #'+modeline|disable-selection-info)) - ((add-hook 'activate-mark-hook #'+modeline|enable-selection-info) - (add-hook 'deactivate-mark-hook #'+modeline|disable-selection-info))) - -;; flycheck -(defun +doom-ml-icon (icon &optional text face voffset) - "Displays an octicon ICON with FACE, followed by TEXT. Uses -`all-the-icons-octicon' to fetch the icon." - (concat (when icon - (concat - (all-the-icons-material icon :face face :height 1.1 :v-adjust (or voffset -0.2)) - (if text +modeline--vspc))) - (if text (propertize text 'face face)))) - -(defun +modeline-flycheck-status (status) - (pcase status - (`finished (if flycheck-current-errors - (let-alist (flycheck-count-errors flycheck-current-errors) - (let ((sum (+ (or .error 0) (or .warning 0)))) - (+doom-ml-icon "do_not_disturb_alt" - (number-to-string sum) - (if .error 'doom-modeline-urgent 'doom-modeline-warning) - -0.25))) - (+doom-ml-icon "check" nil 'doom-modeline-info))) - (`running (+doom-ml-icon "access_time" nil 'font-lock-doc-face -0.25)) - ;; (`no-checker (+doom-ml-icon "sim_card_alert" "-" 'font-lock-doc-face)) - (`errored (+doom-ml-icon "sim_card_alert" "Error" 'doom-modeline-urgent)) - (`interrupted (+doom-ml-icon "pause" "Interrupted" 'font-lock-doc-face)))) - -(defun +doom-modeline|update-flycheck-segment (&optional status) - (setq +modeline-flycheck - (when-let* ((status-str (+modeline-flycheck-status status))) - (concat +modeline--vspc status-str " ")))) -(add-hook 'flycheck-mode-hook #'+doom-modeline|update-flycheck-segment) -(add-hook 'flycheck-status-changed-functions #'+doom-modeline|update-flycheck-segment) - -(def-modeline-segment! +modeline-flycheck - "Displays color-coded flycheck error status in the current buffer with pretty -icons." - :init nil) - - -;; -;; Preset modeline formats - -(def-modeline-format! :main - '(+modeline-matches " " - +modeline-buffer-state - +modeline-buffer-id - " %2l:%c %p ") - `(mode-line-misc-info - +modeline-indent-style - +modeline-encoding - +modeline-major-mode " " - (vc-mode (" " +modeline-vcs " ")) - mode-line-process - +modeline-flycheck)) - -(def-modeline-format! :minimal - '(+modeline-matches " " - +modeline-buffer-state - +modeline-buffer-id) - '(+modeline-major-mode)) - -(def-modeline-format! :special - '(+modeline-matches +modeline-buffer-state " %b " +modeline-buffer-position) - '(+modeline-encoding +modeline-major-mode mode-line-process)) - -(def-modeline-format! :project - '(+modeline-buffer-directory) - '(+modeline-major-mode)) - - -;; -(def-modeline-segment! +modeline--rest - (let ((rhs-str (format-mode-line +modeline-format-right))) - (list (propertize - " " 'display - `((space :align-to (- (+ right right-fringe right-margin) - ,(1+ (string-width rhs-str)))))) - rhs-str))) - -(setq-default mode-line-format '("" +modeline-bar-start +modeline-format-left +modeline--rest +modeline-bar-end)) - - -;; Set the default modeline as late as possible, giving users a chance to change -;; the above formats. -(add-hook! 'after-init-hook (set-modeline! :main t)) - -;; Set special modelines for special buffers -(add-hook! '+doom-dashboard-mode-hook (set-modeline! :project)) -(add-hook! 'doom-scratch-buffer-hook (set-modeline! :special)) diff --git a/modules/ui/modeline/packages.el b/modules/ui/modeline/packages.el index 9c484100f..5933333f4 100644 --- a/modules/ui/modeline/packages.el +++ b/modules/ui/modeline/packages.el @@ -1,20 +1,7 @@ ;; -*- no-byte-compile: t; -*- ;;; ui/modeline/packages.el -;;; These are the invisible dependencies -;; Required -;;(require 'evil) -;;(require 'projectile) -;;(require 'all-the-icons) - -;; Optional -;;(require 'flycheck) -;;(require 'iedit) -;;(require 'evil-multiedit) - +(package! doom-modeline) (package! anzu) - (when (featurep! :feature evil) (package! evil-anzu)) - -(package! shrink-path)