Updating Doom Emacs.

This commit is contained in:
Derek Taylor
2020-06-19 22:43:40 -05:00
parent 0f664d532a
commit a5c86c514a
453 changed files with 13527 additions and 12455 deletions

View File

@@ -3,21 +3,35 @@
(use-package! deft
:commands deft
:init
(setq deft-extensions '("org" "md" "tex" "txt")
deft-default-extension "org"
(setq deft-default-extension "org"
;; de-couples filename and note title:
deft-use-filename-as-title nil
deft-use-filter-string-for-filename t
deft-org-mode-title-prefix t
;; disable auto-save
deft-auto-save-interval -1.0
;; converts the filter string into a readable file-name using kebab-case:
deft-file-naming-rules
'((noslash . "-")
(nospace . "-")
(case-fn . downcase)))
'((noslash . "-")
(nospace . "-")
(case-fn . downcase)))
:config
(add-to-list 'deft-extensions "tex")
(add-hook 'deft-mode-hook #'doom-mark-buffer-as-real-h)
;; start filtering immediately
(set-evil-initial-state! 'deft-mode 'insert)
(map! :map deft-mode-map
:n "gr" #'deft-refresh
:n "C-s" #'deft-filter
:i "C-n" #'deft-new-file
:i "C-m" #'deft-new-file-named
:i "C-d" #'deft-delete-file
:i "C-r" #'deft-rename-file
:n "r" #'deft-rename-file
:n "a" #'deft-new-file
:n "A" #'deft-new-file-named
:n "d" #'deft-delete-file
:n "D" #'deft-archive-file
:n "q" #'kill-current-buffer
:localleader
"RET" #'deft-new-file-named
"a" #'deft-archive-file

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/deft/packages.el
(package! deft)
(package! deft :pin "fca9ea05ef4fdac825e2ad3921baa7042f6b82c8")

View File

@@ -1,20 +1,88 @@
#+TITLE: ui/doom-dashboard
#+DATE: October 9, 2019
#+SINCE: v1.3
#+STARTUP: inlineimages
#+STARTUP: inlineimages nofold
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]
- [[#module-flags][Module Flags]]
- [[#prerequisites][Prerequisites]]
- [[#configuration][Configuration]]
- [[#a-custom-banner][A custom banner]]
- [[#adding-text-to-the-dashboard][Adding text to the dashboard]]
- [[#customizing-faces][Customizing Faces]]
* Description
This module gives Doom Emacs a dashboard buffer.
This module adds a minimalistic, Atom-inspired dashboard to Emacs.
It is loosely inspired by Atom's dashboard.
Besides eye candy, the dashboard serves two other purposes:
1. To improve Doom's startup times (the dashboard is lighter than the scratch
buffer in many cases).
2. And to preserve the "last open directory" you were in. Occasionally, I kill
the last buffer in my project and I end up who-knows-where (in the working
directory of another buffer/project). It can take some work to find my way
back to where I was. Not with the Dashboard.
Since the dashboard cannot be killed, and it remembers the working directory
of the last open buffer, ~M-x find-file~ will work from the directory I
expect.
** Module Flags
This module provides no flags.
* Prerequisites
This module only requires that ~all-the-icons~'s icon fonts are installed. Use ~M-x all-the-icons-install-fonts~ to do so.
This module only requires that ~all-the-icons~'s icon fonts are installed.
It should've been installed when you first installed Doom, but ~M-x
all-the-icons-install-fonts~ will install them again.
* Configuration
** A custom banner
To use a custom image as your banner, change ~fancy-splash-image~:
#+BEGIN_SRC elisp
(setq fancy-splash-image "~/my/banners/image.png")
#+END_SRC
#+begin_quote
Doom will fall back to its ASCII banner in Terminal Emacs. To replace the ASCII
banner, replace the ~doom-dashboard-widget-banner~ function in
~+doom-dashboard-functions~ with a function that inserts your new banner into
the current file.
#+end_quote
** Adding text to the dashboard
Doom's dashboard iterates over ~+doom-dashboard-functions~ when it is told to
redraw. Add your own functions to operate on the buffer and potentially add
whatever you like to Doom's splash screen.
#+begin_quote
Keep in mind that inserting text from expensive sources, e.g. your org agenda,
will negate most of Doom's startup benefits.
#+end_quote
** Customizing Faces
Doom's dashboard defaults to inheriting faces set by the current theme. If you wish
to customize it independently of the theme (or just inherit a different color
from the theme) you can make use of ~custom-set-faces!~ or ~custom-theme-set-faces!~
#+BEGIN_SRC elisp
(custom-set-faces!
'(doom-dashboard-banner :foreground "red" :background "#000000" :weight bold)
'(doom-dashboard-footer :inherit font-lock-constant-face)
'(doom-dashboard-footer-icon :inherit all-the-icons-red)
'(doom-dashboard-loaded :inherit font-lock-warning-face)
'(doom-dashboard-menu-desc :inherit font-lock-string-face)
'(doom-dashboard-menu-title :inherit font-lock-function-name-face))
#+END_SRC
or for a per-theme setting
#+BEGIN_SRC elisp
(custom-theme-set-faces! 'doom-tomorrow-night
'(doom-dashboard-banner :foreground "red" :background "#000000" :weight bold)
'(doom-dashboard-footer :inherit font-lock-constant-face)
'(doom-dashboard-footer-icon :inherit all-the-icons-red)
'(doom-dashboard-loaded :inherit font-lock-warning-face)
'(doom-dashboard-menu-desc :inherit font-lock-string-face)
'(doom-dashboard-menu-title :inherit font-lock-function-name-face))
#+END_SRC

View File

@@ -19,7 +19,7 @@ relative to `+doom-dashboard-banner-dir'. If nil, always use the ASCII banner.")
(defvar +doom-dashboard-banner-dir (concat (dir!) "/banners/")
"Where to look for `+doom-dashboard-banner-file'.")
(defvar +doom-dashboard-banner-padding '(4 . 4)
(defvar +doom-dashboard-banner-padding '(0 . 4)
"Number of newlines to pad the banner with, above and below, respectively.")
(defvar +doom-dashboard-inhibit-refresh nil
@@ -43,33 +43,33 @@ Possible values:
(defvar +doom-dashboard-menu-sections
'(("Reload last session"
:icon (all-the-icons-octicon "history" :face 'font-lock-keyword-face)
:icon (all-the-icons-octicon "history" :face 'doom-dashboard-menu-title)
:when (cond ((require 'persp-mode nil t)
(file-exists-p (expand-file-name persp-auto-save-fname persp-save-dir)))
((require 'desktop nil t)
(file-exists-p (desktop-full-file-name))))
:face (:inherit (font-lock-keyword-face bold))
:face (:inherit (doom-dashboard-menu-title bold))
:action doom/quickload-session)
("Open org-agenda"
:icon (all-the-icons-octicon "calendar" :face 'font-lock-keyword-face)
:icon (all-the-icons-octicon "calendar" :face 'doom-dashboard-menu-title)
:when (fboundp 'org-agenda)
:action org-agenda)
("Recently opened files"
:icon (all-the-icons-octicon "file-text" :face 'font-lock-keyword-face)
:icon (all-the-icons-octicon "file-text" :face 'doom-dashboard-menu-title)
:action recentf-open-files)
("Open project"
:icon (all-the-icons-octicon "briefcase" :face 'font-lock-keyword-face)
:icon (all-the-icons-octicon "briefcase" :face 'doom-dashboard-menu-title)
:action projectile-switch-project)
("Jump to bookmark"
:icon (all-the-icons-octicon "bookmark" :face 'font-lock-keyword-face)
:icon (all-the-icons-octicon "bookmark" :face 'doom-dashboard-menu-title)
:action bookmark-jump)
("Open private configuration"
:icon (all-the-icons-octicon "tools" :face 'font-lock-keyword-face)
:icon (all-the-icons-octicon "tools" :face 'doom-dashboard-menu-title)
:when (file-directory-p doom-private-dir)
:action doom/open-private-config)
("Search Documentation"
:icon (all-the-icons-octicon "book" :face 'font-lock-keyword-face)
:action doom/help-search))
("Open documentation"
:icon (all-the-icons-octicon "book" :face 'doom-dashboard-menu-title)
:action doom/help))
"An alist of menu buttons used by `doom-dashboard-widget-shortmenu'. Each
element is a cons cell (LABEL . PLIST). LABEL is a string to display after the
icon and before the key string.
@@ -125,10 +125,45 @@ PLIST can have the following properties:
;; `persp-mode' integration: update `default-directory' when switching perspectives
(add-hook 'persp-created-functions #'+doom-dashboard--persp-record-project-h)
(add-hook 'persp-activated-functions #'+doom-dashboard--persp-detect-project-h)
;; HACK Fix #2219 where, in GUI daemon frames, the dashboard loses center
;; alignment after switching (or killing) workspaces.
(when (daemonp)
(add-hook 'persp-activated-functions #'+doom-dashboard-reload-maybe-h))
(add-hook 'persp-before-switch-functions #'+doom-dashboard--persp-record-project-h)))
(add-hook 'doom-init-ui-hook #'+doom-dashboard-init-h)
;;
;;; Faces
(defgroup doom-dashboard nil
"Manage how doom-dashboard is coloured and themed."
:prefix "doom-dashboard"
:group 'doom-themes)
(defface doom-dashboard-banner '((t (:inherit font-lock-comment-face)))
"Face used for the DOOM banner on the dashboard"
:group 'doom-dashboard)
(defface doom-dashboard-footer '((t (:inherit font-lock-keyword-face)))
"Face used for the footer on the dashboard"
:group 'doom-dashboard)
(defface doom-dashboard-footer-icon '((t (:inherit all-the-icons-green)))
"Face used for the icon of the footer on the dashboard"
:group 'doom-dashboard)
(defface doom-dashboard-loaded '((t (:inherit font-lock-comment-face)))
"Face used for the loaded packages benchmark"
:group 'doom-dashboard)
(defface doom-dashboard-menu-desc '((t (:inherit font-lock-constant-face)))
"Face used for the key description of menu widgets on the dashboard"
:group 'doom-dashboard)
(defface doom-dashboard-menu-title '((t (:inherit font-lock-keyword-face)))
"Face used for the title of menu widgets on the dashboard"
:group 'doom-dashboard)
;;
;;; Major mode
@@ -202,7 +237,7 @@ PLIST can have the following properties:
(goto-char (point-min))
(forward-button 1))))
(defun +doom-dashboard-reload-maybe-h ()
(defun +doom-dashboard-reload-maybe-h (&rest _)
"Reload the dashboard or its state.
If this isn't a dashboard buffer, move along, but record its `default-directory'
@@ -245,10 +280,10 @@ whose dimensions may not be fully initialized by the time this is run."
(save-excursion (skip-chars-forward "\n")
(point)))
(insert (make-string
(max 0 (- (/ (window-height (get-buffer-window)) 2)
(round (/ (+ (count-lines (point-min) (point-max))
(car +doom-dashboard-banner-padding))
2))))
(+ (max 0 (- (/ (window-height (get-buffer-window)) 2)
(round (/ (count-lines (point-min) (point-max))
2))))
(car +doom-dashboard-banner-padding))
?\n)))))))))
(defun +doom-dashboard--persp-detect-project-h (&rest _)
@@ -348,7 +383,7 @@ controlled by `+doom-dashboard-pwd-policy'."
(let ((point (point)))
(mapc (lambda (line)
(insert (propertize (+doom-dashboard--center +doom-dashboard--width line)
'face 'font-lock-comment-face) " ")
'face 'doom-dashboard-banner) " ")
(insert "\n"))
'("================= =============== =============== ======== ========"
"\\\\ . . . . . . .\\\\ //. . . . . . .\\\\ //. . . . . . .\\\\ \\\\. . .\\\\// . . //"
@@ -393,7 +428,7 @@ controlled by `+doom-dashboard-pwd-policy'."
(+doom-dashboard--center
+doom-dashboard--width
(doom-display-benchmark-h 'return))
'face 'font-lock-comment-face)
'face 'doom-dashboard-loaded)
"\n"))
(defun doom-dashboard-widget-shortmenu ()
@@ -418,11 +453,11 @@ controlled by `+doom-dashboard-pwd-policy'."
`(lambda (_)
(call-interactively (or (command-remapping #',action)
#',action)))
'face (or face 'font-lock-keyword-face)
'face (or face 'doom-dashboard-menu-title)
'follow-link t
'help-echo
(format "%s (%s)" label
(propertize (symbol-name action) 'face 'font-lock-constant-face)))
(propertize (symbol-name action) 'face 'doom-dashboard-menu-desc)))
(format "%-37s" (buffer-string)))
;; Lookup command keys dynamically
(or (when-let (key (where-is-internal action nil t))
@@ -434,7 +469,7 @@ controlled by `+doom-dashboard-pwd-policy'."
(upcase (if (< (length str) 3)
str
(substring str 0 3))))))
(propertize (buffer-string) 'face 'font-lock-constant-face)))
(propertize (buffer-string) 'face 'doom-dashboard-menu-desc)))
""))))
(if (display-graphic-p)
"\n\n"
@@ -446,8 +481,8 @@ controlled by `+doom-dashboard-pwd-policy'."
(+doom-dashboard--center
(- +doom-dashboard--width 2)
(with-temp-buffer
(insert-text-button (or (all-the-icons-octicon "octoface" :face 'all-the-icons-green :height 1.3 :v-adjust -0.15)
(propertize "github" 'face 'font-lock-keyword-face))
(insert-text-button (or (all-the-icons-octicon "octoface" :face 'doom-dashboard-footer-icon :height 1.3 :v-adjust -0.15)
(propertize "github" 'face 'doom-dashboard-footer))
'action (lambda (_) (browse-url "https://github.com/hlissner/doom-emacs"))
'follow-link t
'help-echo "Open Doom Emacs github page")

View File

@@ -1,7 +1,7 @@
#+TITLE: ui/doom
#+DATE: October 9, 2019
#+SINCE: v1.3
#+STARTUP: inlineimages
#+STARTUP: inlineimages nofold
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]

View File

@@ -1,36 +1,15 @@
;;; ui/doom/config.el -*- lexical-binding: t; -*-
(defvar +doom-solaire-themes
'((doom-challenger-deep . t)
(doom-city-lights . t)
(doom-dracula . t)
(doom-molokai)
(doom-nord . t)
(doom-nord-light . t)
(doom-nova)
(doom-one . t)
(doom-one-light . t)
(doom-opera . t)
(doom-snazzy . t)
(doom-solarized-dark . t)
(doom-solarized-light)
(doom-spacegrey . t)
(doom-tomorrow-day . t)
(doom-tomorrow-night . t)
(doom-vibrant))
"An alist of themes that support `solaire-mode'. If CDR is t, then
`solaire-mode-swap-bg' will be used automatically, when the theme is loaded.")
;;;###package pos-tip
(setq pos-tip-internal-border-width 6
pos-tip-border-width 1)
;;
;;; Packages
(use-package! doom-themes
:defer t
:init
(unless doom-theme
(setq doom-theme 'doom-one))
:config
;; improve integration w/ org-mode
(add-hook 'doom-load-theme-hook #'doom-themes-org-config)
;; more Atom-esque file icons for neotree/treemacs
@@ -45,52 +24,64 @@
(use-package! solaire-mode
:when (or (daemonp) (display-graphic-p))
:defer t
:init
(add-hook! 'doom-load-theme-hook :append
(defun +doom-solaire-mode-swap-bg-maybe-h ()
(pcase-let ((`(,_theme . ,swap) (assq doom-theme +doom-solaire-themes)))
(require 'solaire-mode)
(if swap (solaire-mode-swap-bg)))))
:hook (doom-load-theme . solaire-global-mode)
:config
;; fringe can become unstyled when deleting or focusing frames
(add-hook 'focus-in-hook #'solaire-mode-reset)
;; Prevent color glitches when reloading either DOOM or loading a new theme
(add-hook! '(doom-load-theme-hook doom-reload-hook) :append
#'solaire-mode-reset)
;; org-capture takes an org buffer and narrows it. The result is erroneously
;; considered an unreal buffer, so solaire-mode must be restored.
(add-hook 'org-capture-mode-hook #'turn-on-solaire-mode)
(when (daemonp)
(add-hook! '(doom-switch-frame-hook after-make-frame-functions)
(defun +doom-disable-solaire-mode-maybe-h (&optional frame)
(if (display-graphic-p frame)
(unless solaire-global-mode
(solaire-global-mode +1))
(when solaire-global-mode
(solaire-global-mode -1))))))
;; On Emacs 26+, when point is on the last line and solaire-mode is remapping
;; the hl-line face, hl-line's highlight bleeds into the rest of the window
;; after eob. On Emacs 27 this no longer happens.
(add-hook! 'solaire-global-mode-hook
(defun +doom-solaire-swap-bg-faces-maybe-h ()
(and solaire-global-mode
(string-prefix-p "doom-" (symbol-name doom-theme))
(solaire-mode-swap-bg))))
;; DEPRECATED No longer needed in Emacs 27+
(unless EMACS27+
;; HACK On Emacs <=26, when point is on the last (or second to last) line
;; and solaire-mode is remapping the hl-line face, hl-line's highlight
;; bleeds into the rest of the window after eob. On Emacs 27 this no
;; longer happens. This tries to fix it for 26 users, but it imposes
;; another problem: the 2nd-to-last line will only be highlighted up to
;; the (n-1)th character, but I think that is the lesser evil.
(defun +doom--line-range-fn ()
(cons (line-beginning-position)
(cond ((let ((eol (line-end-position)))
(and (= eol (point-max))
(/= eol (line-beginning-position))))
(1- (line-end-position)))
((or (eobp)
(= (line-end-position 2) (point-max)))
(line-end-position))
((line-beginning-position 2)))))
(setq hl-line-range-function #'+doom--line-range-fn))
(if solaire-mode
(let ((bol (line-beginning-position))
(eol (line-end-position))
(eob (point-max)))
(cond ((= bol eob)
nil)
((= (1+ eol) eob)
(cons bol (1- eob)))
((or (= eol eob) (eobp))
(cons bol eol))
((cons bol (line-beginning-position 2)))))
(cons (line-beginning-position)
(line-beginning-position 2))))
(setq hl-line-range-function #'+doom--line-range-fn)
;; Because fringes can't be given a buffer-local face, they can look odd, so
;; we remove them in the minibuffer and which-key popups (they serve no
;; purpose there anyway).
(add-hook! 'solaire-mode-hook
(defun +doom-disable-fringes-in-minibuffer-h (&rest _)
(set-window-fringes (minibuffer-window) 0 0 nil)))
;; HACK The fringe cannot have a buffer-local remapping on Emacs <= 26, so
;; we jump through hoops to reset it (globally) whenever it is likely
;; that the fringe will have lost its background color.
(add-hook! '(doom-load-theme-hook doom-reload-hook) :append
#'solaire-mode-reset)
(defadvice! +doom--no-fringes-in-which-key-buffer-a (&rest _)
:after 'which-key--show-buffer-side-window
(+doom-disable-fringes-in-minibuffer-h)
(set-window-fringes (get-buffer-window which-key--buffer) 0 0 nil))
;; fringe can become unstyled when deleting or focusing frames
(add-hook 'focus-in-hook #'solaire-mode-reset)
(add-hook! '(minibuffer-setup-hook window-configuration-change-hook)
#'+doom-disable-fringes-in-minibuffer-h)
(solaire-global-mode +1))
;; A global fringe color means the minibuffer (with its fringes) will always
;; stand out, so we remove them (in which-key popups too).
(add-hook! 'solaire-mode-hook
(defun +doom-disable-fringes-in-minibuffer-h (&rest _)
(set-window-fringes (minibuffer-window) 0 0 nil)))
(defadvice! +doom--no-fringes-in-which-key-buffer-a (&rest _)
:after 'which-key--show-buffer-side-window
(+doom-disable-fringes-in-minibuffer-h)
(set-window-fringes (get-buffer-window which-key--buffer) 0 0 nil))
(add-hook! '(minibuffer-setup-hook window-configuration-change-hook)
#'+doom-disable-fringes-in-minibuffer-h)))

View File

@@ -1,6 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; ui/doom/packages.el
(package! doom-themes)
(package! solaire-mode)
(package! doom-themes :pin "b1c43a324d3000bd9972030aecf98c9cc8376337")
(package! solaire-mode :pin "25d1aafc03e3c7f9487532464dbffacce10d0c5d")

View File

@@ -1,5 +1,7 @@
;;; ui/fill-column/autoload.el -*- lexical-binding: t; -*-
;; DEPRECATED Replaced by `display-fill-column-indicator-mode' in Emacs 27+
;;;###autoload (autoload 'hl-fill-column-mode "hl-fill-column" nil t)
;;;###autoload

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/fill-column/packages.el
(package! hl-fill-column)
(package! hl-fill-column :pin "43cb3c35a92c912b7205b8a36f1ad0ec0a5b4a22")

View File

@@ -5,13 +5,30 @@
:config
(setq hl-todo-highlight-punctuation ":"
hl-todo-keyword-faces
`(("TODO" warning bold)
("FIXME" error bold)
("HACK" font-lock-constant-face bold)
("REVIEW" font-lock-keyword-face bold)
("NOTE" success bold)
`(;; For things that need to be done, just not today.
("TODO" warning bold)
;; For problems that will become bigger problems later if not
;; fixed ASAP.
("FIXME" error bold)
;; For tidbits that are unconventional and not intended uses of the
;; constituent parts, and may break in a future update.
("HACK" font-lock-constant-face bold)
;; For things that were done hastily and/or hasn't been thoroughly
;; tested. It may not even be necessary!
("REVIEW" font-lock-keyword-face bold)
;; For especially important gotchas with a given implementation,
;; directed at another user other than the author.
("NOTE" success bold)
;; For things that just gotta go and will soon be gone.
("DEPRECATED" font-lock-doc-face bold)))
(defadvice! +hl-todo-clamp-font-lock-fontify-region-a (orig-fn &rest args)
"Fix an `args-out-of-range' error in some modes."
:around #'hl-todo-mode
(letf! (defun font-lock-fontify-region (beg end &optional loudly)
(funcall font-lock-fontify-region (max beg 1) end loudly))
(apply orig-fn args)))
;; Use a more primitive todo-keyword detection method in major modes that
;; don't use/have a valid syntax table entry for comments.
(add-hook! '(pug-mode-hook haml-mode-hook)

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/hl-todo/packages.el
(package! hl-todo)
(package! hl-todo :pin "3bba4591c54951d2abab113ec5e58a6319808ca9")

View File

@@ -1,7 +1,7 @@
;;; ui/hydra/autoload/windows.el -*- lexical-binding: t; -*-
;;;###autoload (autoload '+hydra/text-zoom/body "ui/hydra/autoload/windows" nil t)
(defhydra +hydra/text-zoom (:hint t :color red)
(defhydra +hydra/text-zoom (:hint nil :color red)
"
Text zoom: _j_:zoom in, _k_:zoom out, _0_:reset
"

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/hydra/packages.el
(package! hydra)
(package! hydra :pin "87873d788891029d9e44fa5458321d6a05849b94")

View File

@@ -5,9 +5,21 @@
:init
(setq highlight-indent-guides-method 'character)
:config
(add-hook 'focus-in-hook #'highlight-indent-guides-auto-set-faces)
;; `highlight-indent-guides' breaks in these modes
(add-hook! '(visual-line-mode-hook org-indent-mode-hook)
(defun +indent-guides-init-faces-h ()
(when (display-graphic-p)
(highlight-indent-guides-auto-set-faces)))
;; HACK `highlight-indent-guides' calculates its faces from the current theme,
;; but is unable to do so properly in terminal Emacs, where it only has
;; access to 256 colors. So if the user uses a daemon we must wait for
;; the first graphical frame to be available to do.
(add-hook (if (daemonp)
'server-after-make-frame-hook
'doom-load-theme-hook)
#'+indent-guides-init-faces-h)
;; `highlight-indent-guides' breaks when `org-indent-mode' is active
(add-hook! 'org-indent-mode-hook
(defun +indent-guides-disable-maybe-h ()
(when highlight-indent-guides-mode
(highlight-indent-guides-mode -1)))))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/indent-guides/packages.el
(package! highlight-indent-guides)
(package! highlight-indent-guides :pin "1b12c7b440ff988c7237936187c1375ac4ddc7f4")

View File

@@ -50,17 +50,17 @@ side of the modeline, and whose CDR is the right-hand side.")
;;
;;; Faces
(defface +modeline-bar '((t (:inherit highlight)))
(defface doom-modeline-bar '((t (:inherit highlight)))
"Face used for left-most bar on the mode-line of an active window.")
(defface +modeline-bar-inactive '((t (:inherit mode-line-inactive)))
(defface doom-modeline-bar-inactive '((t (:inherit mode-line-inactive)))
"Face used for left-most bar on the mode-line of an inactive window.")
(defface +modeline-highlight
(defface doom-modeline-highlight
'((t (:inherit mode-line-highlight)))
"Face used for highlighted modeline panels (like search counts).")
(defface +modeline-alternate-highlight
(defface doom-modeline-alternate-highlight
'((t (:inherit mode-line-highlight)))
"Alternative face used for highlighted modeline panels (like search counts).")
@@ -68,14 +68,6 @@ side of the modeline, and whose CDR is the right-hand side.")
;;
;;; Helpers
(defvar +modeline--redisplayed-p nil)
(defadvice! modeline-recalculate-height-a (&optional _force &rest _ignored)
"Ensure that window resizing functions take modeline height into account."
:before '(fit-window-to-buffer resize-temp-buffer-window)
(unless +modeline--redisplayed-p
(setq-local +modeline--redisplayed-p t)
(redisplay t)))
;;; `active'
(defvar +modeline--active-window (selected-window))
@@ -144,19 +136,20 @@ If DEFAULT is non-nil, apply to all future buffers. Modelines are defined with
See `def-modeline!' on how modelines are defined."
(let ((fn (intern (format "+modeline-set-%s-format-h" name))))
(dolist (hook (doom-enlist hooks))
(when after-init-time
(dolist (name (mapcar #'car +modeline-format-alist))
(remove-hook hook (intern (format "+modeline-set-%s-format-h" name)))))
(add-hook hook fn))))
(defmacro def-modeline! (name lhs rhs)
(defun def-modeline! (name lhs rhs)
"Define a modeline format by NAME.
LHS and RHS are the formats representing the left and right hand side of the
mode-line, respectively. See the variable `format-mode-line' for details on what
LHS and RHS will accept."
`(progn
(setf (alist-get ',name +modeline-format-alist)
(cons ,lhs ,rhs))
(defun ,(intern (format "+modeline-set-%s-format-h" name)) (&rest _)
"TODO"
(set-modeline! ',name))))
(setf (alist-get name +modeline-format-alist)
(cons lhs rhs))
(fset (intern (format "+modeline-set-%s-format-h" name))
(lambda (&rest _) (set-modeline! name))))
(defmacro def-modeline-var! (name body &optional docstring &rest plist)
"TODO"
@@ -182,178 +175,177 @@ LHS and RHS will accept."
;;; `+modeline-bar'
(progn
(def-modeline-var! +modeline-bar "")
(def-modeline-var! +modeline-inactive-bar "")
(def-modeline-var! +modeline-bar "")
(add-hook! '(doom-init-ui-hook doom-load-theme-hook) :append
(defun +modeline-refresh-bars-h ()
(let ((width (or +modeline-bar-width 1))
(height (max +modeline-height 0)))
(setq +modeline-bar
(+modeline--make-xpm
(and +modeline-bar-width
(face-background '+modeline-bar nil 'inherit))
width height)
+modeline-inactive-bar
(+modeline--make-xpm
(and +modeline-bar-width
(face-background '+modeline-bar-inactive nil 'inherit))
width height)))))
(defvar +modeline-active-bar "")
(defvar +modeline-inactive-bar "")
(add-hook! 'doom-change-font-size-hook
(defun +modeline-adjust-height-h ()
(defvar +modeline--old-height +modeline-height)
(let ((default-height +modeline--old-height)
(scale (or (frame-parameter nil 'font-scale) 0)))
(setq +modeline-height
(if (> scale 0)
(+ default-height (* (or (frame-parameter nil 'font-scale) 1)
doom-font-increment))
default-height))
(when doom-init-time
(+modeline-refresh-bars-h))))))
(add-hook! '(doom-init-ui-hook doom-load-theme-hook) :append
(defun +modeline-refresh-bars-h ()
(let ((width (or +modeline-bar-width 1))
(height (max +modeline-height 0))
(active-bg (face-background 'doom-modeline-bar nil t))
(inactive-bg (face-background 'doom-modeline-bar-inactive nil t)))
(when (or (null +modeline-bar-width)
(= +modeline-bar-width 0))
(setq active-bg nil
inactive-bg nil))
(setq +modeline-active-bar
(+modeline--make-xpm (and +modeline-bar-width active-bg)
width height)
+modeline-inactive-bar
(+modeline--make-xpm (and +modeline-bar-width inactive-bg)
width height)
+modeline-bar
'(:eval (if (+modeline-active)
+modeline-active-bar
+modeline-inactive-bar))))))
(add-hook! 'doom-change-font-size-hook
(defun +modeline-adjust-height-h ()
(defvar +modeline--old-height +modeline-height)
(let ((default-height +modeline--old-height)
(scale (or (frame-parameter nil 'font-scale) 0)))
(setq +modeline-height
(if (> scale 0)
(+ default-height (* (or (frame-parameter nil 'font-scale) 1)
doom-font-increment))
default-height))
(when doom-init-time
(+modeline-refresh-bars-h)))))
;;; `+modeline-matches'
(progn
(use-package! anzu
:after-call isearch-mode
:config
;; anzu and evil-anzu expose current/total state that can be displayed in the
;; mode-line.
(defadvice! +modeline-fix-anzu-count-a (positions here)
"Calulate anzu counts via POSITIONS and HERE."
:override #'anzu--where-is-here
(cl-loop for (start . end) in positions
collect t into before
when (and (>= here start) (<= here end))
return (length before)
finally return 0))
(use-package! anzu
:after-call isearch-mode
:config
;; We manage our own modeline segments
(setq anzu-cons-mode-line-p nil)
;; Ensure anzu state is cleared when searches & iedit are done
(add-hook 'iedit-mode-end-hook #'anzu--reset-status)
(advice-add #'evil-force-normal-state :before #'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)))
(setq anzu-cons-mode-line-p nil) ; manage modeline segment ourselves
;; Ensure anzu state is cleared when searches & iedit are done
(add-hook 'isearch-mode-end-hook #'anzu--reset-status 'append)
(add-hook 'iedit-mode-end-hook #'anzu--reset-status)
(advice-add #'evil-force-normal-state :before #'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)))
(use-package! evil-anzu
:when (featurep! :editor evil)
:after-call evil-ex-start-search evil-ex-start-word-search evil-ex-search-activate-highlight
:config (global-anzu-mode +1))
(use-package! evil-anzu
:when (featurep! :editor evil)
:after-call (evil-ex-start-search evil-ex-start-word-search evil-ex-search-activate-highlight))
(defun +modeline--anzu ()
"Show the match index and total number thereof.
(defun +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 (+modeline-active) '+modeline-highlight))))
(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 " (1+ here) total))
(anzu--overflow-p
(format " %s+ " total))
(t
(format " %s/%d " here total))))
'face (if (+modeline-active) 'doom-modeline-highlight))))
(defun +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 (+modeline-active) '+modeline-highlight))))
(defun +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 (+modeline-active) 'doom-modeline-highlight))))
(defun +modeline--multiple-cursors ()
"Show the number of multiple cursors."
(when (bound-and-true-p evil-mc-cursor-list)
(let ((count (length evil-mc-cursor-list)))
(when (> count 0)
(let ((face (cond ((not (+modeline-active)) 'mode-line-inactive)
(evil-mc-frozen '+modeline-highlight)
('+modeline-alternate-highlight))))
(concat (propertize " " 'face face)
(all-the-icons-faicon "i-cursor" :face face :v-adjust -0.0575)
(propertize " " 'face `(:inherit (variable-pitch ,face)))
(propertize (format "%d " count)
'face face)))))))
(defun +modeline--multiple-cursors ()
"Show the number of multiple cursors."
(when (bound-and-true-p evil-mc-cursor-list)
(let ((count (length evil-mc-cursor-list)))
(when (> count 0)
(let ((face (cond ((not (+modeline-active)) 'mode-line-inactive)
(evil-mc-frozen 'doom-modeline-highlight)
('doom-modeline-alternate-highlight))))
(concat (propertize " " 'face face)
(all-the-icons-faicon "i-cursor" :face face :v-adjust -0.0575)
(propertize " " 'face `(:inherit (variable-pitch ,face)))
(propertize (format "%d " count)
'face face)))))))
(defun +modeline--overlay< (a b)
"Sort overlay A and B."
(< (overlay-start a) (overlay-start b)))
(defun +modeline--overlay< (a b)
"Sort overlay A and B."
(< (overlay-start a) (overlay-start b)))
(defun +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)
#'+modeline--overlay<)))
-1)
"-")
length))
'face (if (+modeline-active) '+modeline-highlight))))
(defun +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)
#'+modeline--overlay<)))
-1)
"-")
length))
'face (if (+modeline-active) 'doom-modeline-highlight))))
(defun +modeline--macro-recording ()
"Display current Emacs or evil macro being recorded."
(when (and (+modeline-active)
(or defining-kbd-macro
executing-kbd-macro))
(let ((sep (propertize " " 'face '+modeline-highlight)))
(concat sep
(propertize (if (bound-and-true-p evil-this-macro)
(char-to-string evil-this-macro)
"Macro")
'face '+modeline-highlight)
sep
(all-the-icons-octicon "triangle-right"
:face '+modeline-highlight
:v-adjust -0.05)
sep))))
(defun +modeline--macro-recording ()
"Display current Emacs or evil macro being recorded."
(when (and (+modeline-active)
(or defining-kbd-macro
executing-kbd-macro))
(let ((sep (propertize " " 'face 'doom-modeline-highlight)))
(concat sep
(propertize (if (bound-and-true-p evil-this-macro)
(char-to-string evil-this-macro)
"Macro")
'face 'doom-modeline-highlight)
sep
(all-the-icons-octicon "triangle-right"
:face 'doom-modeline-highlight
:v-adjust -0.05)
sep))))
(def-modeline-var! +modeline-matches
'(:eval
(let ((meta (concat (+modeline--macro-recording)
(+modeline--anzu)
(+modeline--evil-substitute)
(+modeline--iedit)
(+modeline--multiple-cursors))))
(or (and (not (equal meta "")) meta)
" %I ")))))
(def-modeline-var! +modeline-matches
'(:eval
(let ((meta (concat (+modeline--macro-recording)
(+modeline--anzu)
(+modeline--evil-substitute)
(+modeline--iedit)
(+modeline--multiple-cursors))))
(or (and (not (equal meta "")) meta)
" %I "))))
;;; `+modeline-modes'
(def-modeline-var! +modeline-modes ; remove minor modes
'(""
(:propertize mode-name
face bold
mouse-face +modeline-highlight)
face bold
mouse-face doom-modeline-highlight)
mode-line-process
"%n"
" "))
@@ -382,103 +374,104 @@ Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with
;;; `+modeline-checker'
(progn
(def-modeline-var! +modeline-checker nil
"Displays color-coded error status & icon for the current buffer."
:local t)
(def-modeline-var! +modeline-checker nil
"Displays color-coded error status & icon for the current buffer."
:local t)
(add-hook! '(flycheck-status-changed-functions
flycheck-mode-hook)
(defun +modeline-checker-update (&optional status)
"Update flycheck text via STATUS."
(setq +modeline-checker
(pcase status
(`finished
(if flycheck-current-errors
(let-alist (flycheck-count-errors flycheck-current-errors)
(let ((error (or .error 0))
(warning (or .warning 0))
(info (or .info 0)))
(+modeline-format-icon "do_not_disturb_alt"
(number-to-string (+ error warning info))
(cond ((> error 0) 'error)
((> warning 0) 'warning)
('success))
(format "Errors: %d, Warnings: %d, Debug: %d"
error
warning
info))))
(+modeline-format-icon "check" "" 'success)))
(`running (+modeline-format-icon "access_time" "*" 'font-lock-comment-face "Running..."))
(`errored (+modeline-format-icon "sim_card_alert" "!" 'error "Errored!"))
(`interrupted (+modeline-format-icon "pause" "!" 'font-lock-comment-face "Interrupted"))
(`suspicious (+modeline-format-icon "priority_high" "!" 'error "Suspicious")))))))
(add-hook! '(flycheck-status-changed-functions
flycheck-mode-hook)
(defun +modeline-checker-update (&optional status)
"Update flycheck text via STATUS."
(setq +modeline-checker
(pcase status
(`finished
(if flycheck-current-errors
(let-alist (flycheck-count-errors flycheck-current-errors)
(let ((error (or .error 0))
(warning (or .warning 0))
(info (or .info 0)))
(+modeline-format-icon "do_not_disturb_alt"
(number-to-string (+ error warning info))
(cond ((> error 0) 'error)
((> warning 0) 'warning)
('success))
(format "Errors: %d, Warnings: %d, Debug: %d"
error
warning
info))))
(+modeline-format-icon "check" "" 'success)))
(`running (+modeline-format-icon "access_time" "*" 'font-lock-comment-face "Running..."))
(`errored (+modeline-format-icon "sim_card_alert" "!" 'error "Errored!"))
(`interrupted (+modeline-format-icon "pause" "!" 'font-lock-comment-face "Interrupted"))
(`suspicious (+modeline-format-icon "priority_high" "!" 'error "Suspicious"))))))
;;; `+modeline-selection-info'
(progn
(defsubst +modeline--column (pos)
"Get the column of the position `POS'."
(save-excursion (goto-char pos)
(current-column)))
(defsubst +modeline--column (pos)
"Get the column of the position `POS'."
(save-excursion (goto-char pos)
(current-column)))
(def-modeline-var! +modeline-selection-info
'(:eval
(when (or mark-active
(and (bound-and-true-p evil-local-mode)
(eq evil-state 'visual)))
(cl-destructuring-bind (beg . end)
(if (boundp 'evil-local-mode)
(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)
(and (bound-and-true-p evil-visual-selection)
(eq 'block evil-visual-selection)))
(let ((cols (abs (- (+modeline--column end)
(+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))
((format "%dC" (- end beg))))
(when (derived-mode-p 'text-mode)
(format " %dW" (count-words beg end)))
" "))
'face (if (+modeline-active) 'success)))))
"Information about the current selection, such as how many characters and
(def-modeline-var! +modeline-selection-info
'(:eval
(when (or (and (bound-and-true-p evil-local-mode)
(eq evil-state 'visual))
mark-active)
(cl-destructuring-bind (beg . end)
(if (bound-and-true-p evil-visual-selection)
(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)
(and (bound-and-true-p evil-visual-selection)
(eq 'block evil-visual-selection)))
(let ((cols (abs (- (+modeline--column end)
(+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))
((format "%dC" (- end beg))))
(when (derived-mode-p 'text-mode)
(format " %dW" (count-words beg end)))
" "))
'face (if (+modeline-active) 'success)))))
"Information about the current selection, such as how many characters and
lines are selected, or the NxM dimensions of a block selection.")
(defun +modeline-add-selection-segment-h ()
(add-to-list '+modeline-format-left '+modeline-selection-info 'append))
(defun +modeline-remove-selection-segment-h ()
(delq! '+modeline-selection-info +modeline-format-left))
(defun +modeline-add-selection-segment-h ()
(add-to-list '+modeline-format-left '+modeline-selection-info 'append))
(defun +modeline-remove-selection-segment-h ()
(delq! '+modeline-selection-info +modeline-format-left))
(if (featurep 'evil)
(progn
(add-hook 'evil-visual-state-entry-hook #'+modeline-add-selection-segment-h)
(add-hook 'evil-visual-state-exit-hook #'+modeline-remove-selection-segment-h))
(add-hook 'activate-mark-hook #'+modeline-add-selection-segment-h)
(add-hook 'deactivate-mark-hook #'+modeline-remove-selection-segment-h)))
(if (featurep 'evil)
(progn
(add-hook 'evil-visual-state-entry-hook #'+modeline-add-selection-segment-h)
(add-hook 'evil-visual-state-exit-hook #'+modeline-remove-selection-segment-h))
(add-hook 'activate-mark-hook #'+modeline-add-selection-segment-h)
(add-hook 'deactivate-mark-hook #'+modeline-remove-selection-segment-h))
;;; `+modeline-encoding'
(def-modeline-var! +modeline-encoding
'(:eval
(concat (pcase (coding-system-eol-type buffer-file-coding-system)
(0 " LF ")
(1 " RLF ")
(2 " CR "))
(concat (coding-system-eol-type-mnemonic buffer-file-coding-system)
" "
(let ((sys (coding-system-plist buffer-file-coding-system)))
(if (memq (plist-get sys :category)
'(coding-category-undecided coding-category-utf-8))
"UTF-8"
(upcase (symbol-name (plist-get sys :name)))))
" ")))
(upcase (symbol-name (plist-get sys :name))))))))
;; Clearer mnemonic labels for EOL styles
(setq eol-mnemonic-dos "CRLF"
eol-mnemonic-mac "CR"
eol-mnemonic-unix "LF"
eol-mnemonic-undecided "??")
;;
@@ -490,33 +483,35 @@ lines are selected, or the NxM dimensions of a block selection.")
" "
+modeline-buffer-identification
+modeline-position)
'(""
`(""
mode-line-misc-info
+modeline-modes
(vc-mode (" "
,(all-the-icons-octicon "git-branch" :v-adjust 0.0)
vc-mode " "))
" "
" "
+modeline-encoding
" "
(+modeline-checker ("" +modeline-checker " "))))
(def-modeline! project
(def-modeline! 'project
`(" "
,(all-the-icons-octicon
"file-directory"
:face 'bold
:v-adjust -0.05
:height 1.25)
:v-adjust -0.06
:height 1.1)
(:propertize (" " (:eval (abbreviate-file-name default-directory)))
face bold))
'("" +modeline-modes))
'("" mode-line-misc-info +modeline-modes))
(def-modeline! special
(def-modeline! 'special
'("" +modeline-matches
" " +modeline-buffer-identification)
'("" +modeline-modes))
;; TODO (def-modeline! pdf ...)
;; (def-modeline! pdf
;; '("" +modeline-matches))
;; TODO (def-modeline! helm ...)
@@ -545,7 +540,7 @@ lines are selected, or the NxM dimensions of a block selection.")
;; Other modes
(set-modeline! :main 'default)
(set-modeline-hook! '+doom-dashboard-mode-hook 'project)
(set-modeline-hook! 'pdf-tools-enabled-hook 'pdf)
;; (set-modeline-hook! 'pdf-tools-enabled-hook 'pdf)
(set-modeline-hook! '(special-mode-hook
image-mode-hook
circe-mode-hook)

View File

@@ -20,6 +20,7 @@
- [[#troubleshooting][Troubleshooting]]
- [[#where-are-my-minor-modes][Where are my minor modes?]]
- [[#icons-in-my-modeline-look-strange][Icons in my modeline look strange]]
- [[#the-right-side-of-the-modeline-is-cut-off][The right side of the modeline is cut off]]
- [[#appendix][Appendix]]
- [[#autodefs][Autodefs]]
- [[#variables][Variables]]
@@ -30,7 +31,8 @@ This module provides an Atom-inspired, minimalistic modeline for Doom Emacs,
powered by [[https://github.com/seagle0128/doom-modeline][the doom-modeline package]] (where you can find screenshots).
** Module Flags
This module provides no flags.
+ =+light= Enables a lighter, less featureful version of the modeline that does
not depend on ~doom-modeline~, which has performances issues in some cases.
** Plugins
+ [[https://github.com/seagle0128/doom-modeline][doom-modeline]]
@@ -62,6 +64,31 @@ I rarely need to know what minor modes are active, so I removed them. ~M-x
doom/describe-active-minor-mode~ was written to substitute for it.
** TODO Icons in my modeline look strange
** TODO The right side of the modeline is cut off
I believe the consensus is: this is due to oversized icons, i.e. a font issue. Some possible solutions:
1. Tweak ~all-the-icons-scale-factor~ (1.2 by default): ~(setq
all-the-icons-scale-factor 1.1)~
2. Add some padding to the modeline definition:
#+BEGIN_SRC elisp
(after! doom-modeline
(doom-modeline-def-modeline 'main
'(bar matches buffer-info remote-host buffer-position parrot selection-info)
'(misc-info minor-modes checker input-method buffer-encoding major-mode process vcs " "))) ; <-- added padding here
#+END_SRC
3. Use another font for the mode line (or a different ~:height~) (source)
#+BEGIN_SRC elisp
(custom-set-faces!
'(mode-line :family "Noto Sans" :height 0.9)
'(mode-line-inactive :family "Noto Sans" :height 0.9))
#+END_SRC
(Mentioned in #1680, #278 and seagle0128/doom-modeline#334)
* Appendix
** Autodefs

View File

@@ -1,15 +1,5 @@
;;; ui/modeline/autoload/modeline.el -*- lexical-binding: t; -*-
;;;###autodef
(defalias 'def-modeline-format! #'doom-modeline-def-modeline)
;;;###autodef
(defalias 'def-modeline-segment! #'doom-modeline-def-segment)
;;;###autodef
(defalias 'set-modeline! #'doom-modeline-set-modeline)
(defvar +modeline--old-bar-height nil)
;;;###autoload
(defun +modeline-resize-for-font-h ()
@@ -21,28 +11,26 @@ Meant for `doom-change-font-size-hook'."
(setq +modeline--old-bar-height doom-modeline-height))
(let ((default-height +modeline--old-bar-height)
(scale (or (frame-parameter nil 'font-scale) 0)))
(if (> scale 0)
(let* ((font-size (string-to-number
(aref (doom--font-name (frame-parameter nil 'font)
(selected-frame))
xlfd-regexp-pixelsize-subnum)))
(scale (frame-parameter nil 'font-scale)))
(setq doom-modeline-height (+ default-height (* scale doom-font-increment))))
(setq doom-modeline-height default-height))))
(setq doom-modeline-height
(if (> scale 0)
(+ default-height (* scale doom-font-increment))
default-height))))
;;;###autoload
(defun +modeline-update-env-in-all-windows-h (&rest _)
"Update version strings in all buffers."
(dolist (window (window-list))
(with-selected-window window
(doom-modeline-update-env)
(when (fboundp 'doom-modeline-update-env)
(doom-modeline-update-env))
(force-mode-line-update))))
;;;###autoload
(defun +modeline-clear-env-in-all-windows-h (&rest _)
"Blank out version strings in all buffers."
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(setq doom-modeline-env--version
(bound-and-true-p doom-modeline-load-string))))
(unless (featurep! +light)
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(setq doom-modeline-env--version
(bound-and-true-p doom-modeline-load-string)))))
(force-mode-line-update t))

View File

@@ -4,9 +4,20 @@
(load! "+light"))
(defvar +modeline--redisplayed-p nil)
(defadvice! modeline-recalculate-height-a (&optional _force &rest _ignored)
"Ensure that window resizing functions take modeline height into account."
:before '(fit-window-to-buffer resize-temp-buffer-window)
(unless +modeline--redisplayed-p
(setq-local +modeline--redisplayed-p t)
(redisplay t)))
(use-package! doom-modeline
:unless (featurep! +light)
:hook (after-init . doom-modeline-mode)
:hook (doom-modeline-mode . size-indication-mode) ; filesize in modeline
:hook (doom-modeline-mode . column-number-mode) ; cursor column in modeline
:init
(unless after-init-time
;; prevent flash of unstyled modeline at startup
@@ -34,10 +45,7 @@
(defvar mouse-wheel-down-event nil)
(defvar mouse-wheel-up-event nil)
(size-indication-mode +1) ; filesize in modeline
(column-number-mode +1) ; cursor column in modeline
(add-hook 'doom-change-font-size-hook #'+modeline-resize-for-font-h)
(add-hook 'after-setting-font-hook #'+modeline-resize-for-font-h)
(add-hook 'doom-load-theme-hook #'doom-modeline-refresh-bars)
(add-hook '+doom-dashboard-mode-hook #'doom-modeline-set-project-modeline)
@@ -46,22 +54,9 @@
(defun +modeline-hide-in-non-status-buffer-h ()
"Show minimal modeline in magit-status buffer, no modeline elsewhere."
(if (eq major-mode 'magit-status-mode)
(doom-modeline-set-project-modeline)
(doom-modeline-set-vcs-modeline)
(hide-mode-line-mode))))
;; Remove unused segments & extra padding
(doom-modeline-def-modeline 'main
'(bar window-number matches buffer-info remote-host buffer-position selection-info)
'(objed-state misc-info persp-name irc mu4e github debug input-method buffer-encoding lsp major-mode process vcs checker))
(doom-modeline-def-modeline 'special
'(bar window-number matches buffer-info-simple buffer-position selection-info)
'(objed-state misc-info persp-name debug input-method irc-buffers buffer-encoding lsp major-mode process checker))
(doom-modeline-def-modeline 'project
'(bar window-number buffer-default-directory)
'(misc-info mu4e github debug battery " " major-mode process))
;; Some functions modify the buffer, causing the modeline to show a false
;; modified state, so force them to behave.
(defadvice! +modeline--inhibit-modification-hooks-a (orig-fn &rest args)
@@ -76,4 +71,5 @@
(use-package! evil-anzu
:when (featurep! :editor evil)
:after-call evil-ex-start-search evil-ex-start-word-search evil-ex-search-activate-highlight))
:after-call evil-ex-start-search evil-ex-start-word-search evil-ex-search-activate-highlight
:config (global-anzu-mode +1)))

View File

@@ -2,7 +2,7 @@
;;; ui/modeline/packages.el
(unless (featurep! +light)
(package! doom-modeline))
(package! anzu)
(package! doom-modeline :pin "2b308857677e983ca4eaedc36438ed94aadf9e65"))
(package! anzu :pin "7b8688c84d6032300d0c415182c7c1ad6cb7f819")
(when (featurep! :editor evil)
(package! evil-anzu))
(package! evil-anzu :pin "d3f6ed4773b48767bd5f4708c7f083336a8a8a86"))

View File

@@ -5,6 +5,10 @@
org-find-file org-find-file-at-mouse)
"A list of commands that should not trigger nav-flash.")
;;
;;; Packages
(use-package! nav-flash
:defer t
:init
@@ -30,4 +34,8 @@
(advice-add #'evil-window-bottom :after #'+nav-flash-blink-cursor-a)
;; Bound to `ga' for evil users
(advice-add #'what-cursor-position :after #'+nav-flash-blink-cursor-a))
(advice-add #'what-cursor-position :after #'+nav-flash-blink-cursor-a)
:config
(when (fboundp 'set-face-extend)
(set-face-extend 'nav-flash-face t)))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/nav-flash/packages.el
(package! nav-flash)
(package! nav-flash :pin "dbb91216637e0a1e8bfd59aa883c75d45db70daf")

View File

@@ -39,10 +39,9 @@
"Collapse an expanded directory node or go to the parent node."
(interactive)
(when-let (node (neo-buffer--get-filename-current-line))
(if (file-directory-p node)
(if (neo-buffer--expanded-node-p node)
(+neotree/collapse)
(neotree-select-up-node))
(if (and (file-directory-p node)
(neo-buffer--expanded-node-p node))
(+neotree/collapse)
(neotree-select-up-node))))
;;;###autoload

View File

@@ -8,12 +8,12 @@
neotree-find
neo-global--with-buffer
neo-global--window-exists-p)
:config
:init
(setq neo-create-file-auto-open nil
neo-auto-indent-point nil
neo-autorefresh nil
neo-mode-line-type 'none
neo-window-width 24
neo-window-width 30
neo-show-updir-line nil
neo-theme 'icons
neo-banner-message nil
@@ -35,6 +35,7 @@
"~$"
"^#.*#$"))
:config
(set-popup-rule! "^ ?\\*NeoTree" :ignore t)
(after! winner
@@ -54,28 +55,19 @@
(skip-chars-forward " \t\r"))
(map! :map neotree-mode-map
:n "g" nil
:n "TAB" #'neotree-quick-look
:n "RET" #'neotree-enter
:n [tab] #'neotree-quick-look
:n [return] #'neotree-enter
:n "DEL" #'evil-window-prev
:n "c" #'neotree-create-node
:n "r" #'neotree-rename-node
:n "d" #'neotree-delete-node
:n "j" #'neotree-next-line
:n "k" #'neotree-previous-line
:n "n" #'neotree-next-line
:n "p" #'neotree-previous-line
:n "h" #'+neotree/collapse-or-up
:n "l" #'+neotree/expand-or-open
:n "J" #'neotree-select-next-sibling-node
:n "K" #'neotree-select-previous-sibling-node
:n "H" #'neotree-select-up-node
:n "L" #'neotree-select-down-node
:n "G" #'evil-goto-line
:n "gg" #'evil-goto-first-line
:n "v" #'neotree-enter-vertical-split
:n "s" #'neotree-enter-horizontal-split
:n "q" #'neotree-hide
:n "R" #'neotree-refresh))
:n [tab] (neotree-make-executor
:dir-fn #'neo-open-dir
:file-fn #'neotree-quick-look)
:n "DEL" #'evil-window-prev
:n "n" #'neotree-next-line
:n "p" #'neotree-previous-line
:m "h" #'+neotree/collapse-or-up
:m "l" #'+neotree/expand-or-open
:n "J" #'neotree-select-next-sibling-node
:n "K" #'neotree-select-previous-sibling-node
:n "H" #'neotree-select-up-node
:n "L" #'neotree-select-down-node
:n "G" #'evil-goto-line
:n "gg" #'evil-goto-first-line
:n "v" (neotree-make-executor :file-fn 'neo-open-file-vertical-split)
:n "s" (neotree-make-executor :file-fn 'neo-open-file-horizontal-split)))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/neotree/packages.el
(package! neotree)
(package! neotree :pin "5e1271655170f4cdc6849258e383c548a4e6e3d0")

View File

@@ -2,7 +2,7 @@
(use-package! evil-goggles
:when (featurep! :editor evil)
:after-call pre-command-hook
:hook (doom-first-input . evil-goggles-mode)
:init
(setq evil-goggles-duration 0.1
evil-goggles-pulse nil ; too slow
@@ -12,6 +12,10 @@
evil-goggles-enable-change nil)
:config
(pushnew! evil-goggles--commands
'(evil-magit-yank-whole-line
:face evil-goggles-yank-face
:switch evil-goggles-enable-yank
:advice evil-goggles--generic-async-advice)
'(+evil:yank-unindented
:face evil-goggles-yank-face
:switch evil-goggles-enable-yank
@@ -19,15 +23,13 @@
'(+eval:region
:face evil-goggles-yank-face
:switch evil-goggles-enable-yank
:advice evil-goggles--generic-async-advice))
(evil-goggles-mode +1))
:advice evil-goggles--generic-async-advice)))
(use-package! volatile-highlights
:unless (featurep! :editor evil)
:after-call pre-command-hook
:hook (doom-first-input . volatile-highlights-mode)
:config
(volatile-highlights-mode)
(after! undo-tree
(vhl/define-extension 'undo-tree 'undo-tree-yank 'undo-tree-move)
(vhl/install-extension 'undo-tree)))
(after! undo-fu
(vhl/define-extension 'undo-fu 'undo-fu-only-undo 'undo-fu-only-redo)
(vhl/install-extension 'undo-fu)))

View File

@@ -2,5 +2,5 @@
;;; ui/ophints/packages.el
(if (featurep! :editor evil)
(package! evil-goggles)
(package! volatile-highlights))
(package! evil-goggles :pin "08a22058fd6a167f9f1b684c649008caef571459")
(package! volatile-highlights :pin "9a20091f0ce7fc0a6b3e641a6a46d5f3ac4d8392"))

View File

@@ -9,7 +9,7 @@
;; other windows just to pop up one tiny window).
;; 2. Forcing plugins to use `display-buffer' and `pop-to-buffer' instead of
;; `switch-to-buffer' (which is unaffected by `display-buffer-alist', which
;; this module heavily relies on).
;; we must rely on, heavily).
;; 3. Closing popups (temporarily) before functions that are highly destructive
;; to the illusion of popup control get run (with the use of the
;; `save-popups!' macro).
@@ -26,6 +26,15 @@
;;
;;; Core functions
(defadvice! +popup--make-case-sensitive-a (orig-fn &rest args)
"Make regexps in `display-buffer-alist' case-sensitive.
To reduce fewer edge cases and improve performance when `display-buffer-alist'
grows larger."
:around #'display-buffer-assq-regexp
(let (case-fold-search)
(apply orig-fn args)))
;; Don't try to resize popup windows
(advice-add #'balance-windows :around #'+popup-save-a)
@@ -37,8 +46,8 @@ to this commmand."
(let ((orig-buffer (current-buffer)))
(quit-window)
(when (and (eq orig-buffer (current-buffer))
(+popup-window-p))
(+popup/close))))
(+popup-buffer-p))
(+popup/close nil 'force))))
(global-set-key [remap quit-window] #'+popup/quit-window)
@@ -186,30 +195,28 @@ the command buffer."
;; Fix #897: "cannot open side window" error when TAB-completing file links
(defadvice! +popup--helm-hide-org-links-popup-a (orig-fn &rest args)
:around #'org-insert-link
(cl-letf* ((old-org-completing-read (symbol-function 'org-completing-read))
((symbol-function 'org-completing-read)
(lambda (&rest args)
(when-let (win (get-buffer-window "*Org Links*"))
;; While helm is opened as a popup, it will mistaken the
;; *Org Links* popup for the "originated window", and will
;; target it for actions invoked by the user. However, since
;; *Org Links* is a popup too (they're dedicated side
;; windows), Emacs complains about being unable to split a
;; side window. The simple fix: get rid of *Org Links*!
(delete-window win)
;; But it must exist for org to clean up later.
(get-buffer-create "*Org Links*"))
(apply old-org-completing-read args))))
(letf! ((defun org-completing-read (&rest args)
(when-let (win (get-buffer-window "*Org Links*"))
;; While helm is opened as a popup, it will mistaken the *Org
;; Links* popup for the "originated window", and will target it
;; for actions invoked by the user. However, since *Org Links*
;; is a popup too (they're dedicated side windows), Emacs
;; complains about being unable to split a side window. The
;; simple fix: get rid of *Org Links*!
(delete-window win)
;; ...but it must exist for org to clean up later.
(get-buffer-create "*Org Links*"))
(apply org-completing-read args)))
(apply #'funcall-interactively orig-fn args)))
;; Fix left-over popup window when closing persistent help for `helm-M-x'
(defadvice! +popup--helm-elisp--persistent-help-a (candidate _fun &optional _name)
:before #'helm-elisp--persistent-help
(let (win)
(when (and (helm-attr 'help-running-p)
(string= candidate (helm-attr 'help-current-symbol))
(setq win (get-buffer-window (get-buffer (help-buffer)))))
(delete-window win)))))
(and (helm-attr 'help-running-p)
(string= candidate (helm-attr 'help-current-symbol))
(setq win (get-buffer-window (get-buffer (help-buffer))))
(delete-window win)))))
;;;###package Info
@@ -219,32 +226,37 @@ the command buffer."
(when (+popup-window-p win)
(select-window win))))
;;;###package multi-term
(setq multi-term-buffer-name "doom terminal")
;;;###package neotree
(after! neotree
(advice-add #'neo-util--set-window-width :override #'ignore)
(advice-remove #'balance-windows #'ad-Advice-balance-windows))
;;;###package org
(after! org
;; Org has a scorched-earth window management policy I'm not fond of. i.e. it
;; kills all other windows just so it can monopolize the frame. No thanks. We
;; can do better ourselves.
;; can do better.
(defadvice! +popup--suppress-delete-other-windows-a (orig-fn &rest args)
:around '(org-add-log-note
org-capture-place-template
org-export--dispatch-ui
org-agenda-get-restriction-and-command
org-goto-location
org-fast-tag-selection
org-fast-todo-selection)
(if +popup-mode
(cl-letf (((symbol-function #'delete-other-windows)
(symbol-function #'ignore)))
(letf! ((#'delete-other-windows #'ignore)
(#'delete-window #'ignore))
(apply orig-fn args))
(apply orig-fn args)))
(defadvice! +popup--org-fix-goto-a (orig-fn &rest args)
"`org-goto' uses `with-output-to-temp-buffer' to display its help buffer,
for some reason, which is very unconventional, and so requires these gymnastics
to tame (i.e. to get the popup manager to handle it)."
:around #'org-goto-location
(if +popup-mode
(letf! (defun internal-temp-output-buffer-show (buffer)
(let ((temp-buffer-show-function
(doom-rpartial #'+popup-display-buffer-stacked-side-window-fn nil)))
(with-current-buffer buffer
(hide-mode-line-mode +1))
(funcall internal-temp-output-buffer-show buffer)))
(apply orig-fn args))
(apply orig-fn args)))
@@ -255,16 +267,14 @@ Ugh, such an ugly hack."
:around '(org-fast-tag-selection
org-fast-todo-selection)
(if +popup-mode
(cl-letf* ((old-fit-buffer-fn (symbol-function #'org-fit-window-to-buffer))
((symbol-function #'org-fit-window-to-buffer)
(lambda (&optional window max-height min-height shrink-only)
(when-let (buf (window-buffer window))
(delete-window window)
(select-window
(setq window (display-buffer-at-bottom buf nil)))
(with-current-buffer buf
(setq mode-line-format nil)))
(funcall old-fit-buffer-fn window max-height min-height shrink-only))))
(letf! ((defun org-fit-window-to-buffer (&optional window max-height min-height shrink-only)
(when-let (buf (window-buffer window))
(delete-window window)
(select-window
(setq window (display-buffer-at-bottom buf nil)))
(with-current-buffer buf
(setq mode-line-format nil)))
(funcall org-fit-window-to-buffer window max-height min-height shrink-only)))
(apply orig-fn args))
(apply orig-fn args)))
@@ -274,7 +284,24 @@ Ugh, such an ugly hack."
:around #'org-switch-to-buffer-other-window
(if +popup-mode
(pop-to-buffer buf nil norecord)
(funcall orig-fn buf norecord))))
(funcall orig-fn buf norecord)))
;; HACK `pop-to-buffer-same-window' consults `display-buffer-alist', which is
;; what our popup manager uses to manage popup windows. However,
;; `org-src-switch-to-buffer' already does its own window management
;; prior to calling `pop-to-buffer-same-window', so there's no need to
;; _then_ hand off the buffer to the pop up manager.
(defadvice! +popup--org-src-switch-to-buffer-a (orig-fn &rest args)
:around #'org-src-switch-to-buffer
(letf! ((#'pop-to-buffer-same-window #'switch-to-buffer))
(apply orig-fn args))))
;;;###package org-journal
(defadvice! +popup--use-popup-window-a (orig-fn &rest args)
:around #'org-journal-search-by-string
(letf! ((#'switch-to-buffer #'pop-to-buffer))
(apply orig-fn args)))
;;;###package persp-mode
@@ -304,8 +331,7 @@ Ugh, such an ugly hack."
;;;###package profiler
(defadvice! +popup--profiler-report-find-entry-in-other-window-a (orig-fn function)
:around #'profiler-report-find-entry
(cl-letf (((symbol-function 'find-function)
(symbol-function 'find-function-other-window)))
(letf! ((#'find-function #'find-function-other-window))
(funcall orig-fn function)))
@@ -320,14 +346,16 @@ Ugh, such an ugly hack."
(after! which-key
(when (eq which-key-popup-type 'side-window)
(setq which-key-popup-type 'custom
which-key-custom-popup-max-dimensions-function (lambda (_) (which-key--side-window-max-dimensions))
which-key-custom-popup-max-dimensions-function
(lambda (_) (which-key--side-window-max-dimensions))
which-key-custom-hide-popup-function #'which-key--hide-buffer-side-window
which-key-custom-show-popup-function
(lambda (act-popup-dim)
(cl-letf (((symbol-function 'display-buffer-in-side-window)
(lambda (buffer alist)
(+popup-display-buffer-stacked-side-window-fn
buffer (append '((vslot . -9999)) alist)))))
(letf! ((defun display-buffer-in-side-window (buffer alist)
(+popup-display-buffer-stacked-side-window-fn
buffer (append '((vslot . -9999)) alist))))
;; HACK Fix #2219 where the which-key popup would get cut off.
(setcar act-popup-dim (1+ (car act-popup-dim)))
(which-key--show-buffer-side-window act-popup-dim))))))
@@ -336,9 +364,8 @@ Ugh, such an ugly hack."
(defadvice! +popup--ignore-window-parameters-a (orig-fn &rest args)
"Allow *interactive* window moving commands to traverse popups."
:around '(windmove-up windmove-down windmove-left windmove-right)
(cl-letf (((symbol-function #'windmove-find-other-window)
(lambda (dir &optional arg window)
(window-in-direction
(pcase dir (`up 'above) (`down 'below) (_ dir))
window (bound-and-true-p +popup-mode) arg windmove-wrap-around t))))
(letf! ((defun windmove-find-other-window (dir &optional arg window)
(window-in-direction
(pcase dir (`up 'above) (`down 'below) (_ dir))
window (bound-and-true-p +popup-mode) arg windmove-wrap-around t)))
(apply orig-fn args)))

View File

@@ -13,26 +13,27 @@
(defun +popup--kill-buffer (buffer ttl)
"Tries to kill BUFFER, as was requested by a transient timer. If it fails, eg.
the buffer is visible, then set another timer and try again later."
(when (buffer-live-p buffer)
(let ((inhibit-quit t)
(kill-buffer-hook (remq '+popup-kill-buffer-hook-h kill-buffer-hook)))
(cond ((get-buffer-window buffer t)
(let ((inhibit-quit t))
(cond ((not (buffer-live-p buffer)))
((not (get-buffer-window buffer t))
(with-demoted-errors "Error killing transient buffer: %s"
(with-current-buffer buffer
(let ((kill-buffer-hook (remq '+popup-kill-buffer-hook-h kill-buffer-hook))
confirm-kill-processes)
(when-let (process (get-buffer-process buffer))
(kill-process process))
(let (kill-buffer-query-functions)
;; HACK The debugger backtrace buffer, when killed, called
;; `top-level'. This causes jumpiness when the popup
;; manager tries to clean it up.
(cl-letf (((symbol-function #'top-level) #'ignore))
(kill-buffer buffer)))))))
((let ((ttl (if (= ttl 0)
(or (plist-get +popup-defaults :ttl) 3)
ttl)))
(with-current-buffer buffer
(setq +popup--timer
(run-at-time ttl nil #'+popup--kill-buffer buffer ttl))))
((eq ttl 0)
(kill-buffer buffer))
((with-demoted-errors "Error killing transient buffer: %s"
(with-current-buffer buffer
(let (confirm-kill-processes)
(when-let (process (get-buffer-process buffer))
(kill-process process))
(let (kill-buffer-query-functions)
;; HACK The debugger backtrace buffer, when killed, called
;; `top-level'. This causes jumpiness when the popup
;; manager tries to clean it up.
(cl-letf (((symbol-function #'top-level) #'ignore))
(kill-buffer buffer)))))))))))
(run-at-time ttl nil #'+popup--kill-buffer buffer ttl))))))))
(defun +popup--delete-window (window)
"Do housekeeping before destroying a popup window.
@@ -180,8 +181,7 @@ and enables `+popup-buffer-mode'."
(let ((window (or window (selected-window))))
(and (windowp window)
(window-live-p window)
(or (window-parameter window 'popup)
(window-parameter window 'no-other-window))
(window-parameter window 'popup)
window))))
;;;###autoload
@@ -393,8 +393,8 @@ This window parameter is ignored if FORCE-P is non-nil."
;;;###autoload
(defun +popup/toggle ()
"If popups are open, close them. If they aren't, restore the last one or open
the message buffer in a popup window."
"Toggle any visible popups.
If no popups are available, display the *Messages* buffer in a popup window."
(interactive)
(let ((+popup--inhibit-transient t))
(cond ((+popup-windows) (+popup/close-all t))
@@ -415,8 +415,9 @@ the message buffer in a popup window."
;;;###autoload
(defun +popup/raise (window &optional arg)
"Raise the current popup window into a regular window.
If prefix ARG, raise the current popup into a new window."
"Raise the current popup window into a regular window and
return it. If prefix ARG, raise the current popup into a new
window and return that window."
(interactive
(list (selected-window) current-prefix-arg))
(cl-check-type window window)
@@ -428,19 +429,21 @@ If prefix ARG, raise the current popup into a new window."
(+popup/close window 'force)
(if arg
(pop-to-buffer buffer)
(switch-to-buffer buffer))))
(switch-to-buffer buffer))
(selected-window)))
;;;###autoload
(defun +popup/diagnose ()
"Reveal what popup rule will be used for the current buffer."
(interactive)
(or (cl-loop with bname = (buffer-name)
for (pred . action) in display-buffer-alist
if (and (functionp pred) (funcall pred bname action))
return (cons pred action)
else if (and (stringp pred) (string-match-p pred bname))
return (cons pred action))
(message "No popup rule for this buffer")))
(if-let (rule (cl-loop with bname = (buffer-name)
for (pred . action) in display-buffer-alist
if (and (functionp pred) (funcall pred bname action))
return (cons pred action)
else if (and (stringp pred) (string-match-p pred bname))
return (cons pred action)))
(message "Rule matches: %s" rule)
(message "No popup rule for this buffer")))
;;

View File

@@ -68,7 +68,7 @@ PLIST can be made up of any of the following properties:
is in :actions or `+popup-default-display-buffer-actions'.
:size/:width/:height FLOAT|INT|FN
Determines the size of the popup. If more tha one of these size properties are
Determines the size of the popup. If more than one of these size properties are
given :size always takes precedence, and is mapped with window-width or
window-height depending on what :side the popup is opened. Setting a height
for a popup that opens on the left or right is harmless, but comes into play

View File

@@ -110,6 +110,7 @@ prevent the popup(s) from messing up the UI (or vice versa)."
`(let* ((in-popup-p (+popup-buffer-p))
(popups (+popup-windows))
(+popup--inhibit-transient t)
buffer-list-update-hook
+popup--last)
(dolist (p popups)
(+popup/close p 'force))
@@ -131,20 +132,22 @@ prevent the popup(s) from messing up the UI (or vice versa)."
("^ \\*" :slot 1 :vslot -1 :size +popup-shrink-to-fit)))
(when (featurep! +defaults)
'(("^\\*Completions" :ignore t)
("^\\*Local variables\\*$"
:vslot -1 :slot 1 :size +popup-shrink-to-fit)
("^\\*\\(?:[Cc]ompil\\(?:ation\\|e-Log\\)\\|Messages\\)"
:vslot -2 :size 0.3 :autosave t :quit t :ttl nil)
("^\\*\\(?:doom \\|Pp E\\)" ; transient buffers (no interaction required)
:vslot -3 :size +popup-shrink-to-fit :autosave t :select ignore :quit t :ttl 0)
("^\\*doom:" ; editing buffers (interaction required)
:vslot -4 :size 0.35 :autosave t :select t :modeline t :quit nil :ttl t)
("^\\*doom:\\(?:v?term\\|eshell\\)-popup" ; editing buffers (interaction required)
:vslot -5 :size 0.35 :select t :modeline t :quit nil :ttl nil)
("^\\*doom:\\(?:v?term\\|e?shell\\)-popup" ; editing buffers (interaction required)
:vslot -5 :size 0.35 :select t :modeline nil :quit nil :ttl nil)
("^\\*\\(?:Wo\\)?Man "
:vslot -6 :size 0.45 :select t :quit t :ttl 0)
("^\\*Calc"
:vslot -7 :side bottom :size 0.4 :select t :quit nil :ttl 0)
("^\\*Customize"
:slot 2 :side right :select t :quit t)
:slot 2 :side right :size 0.5 :select t :quit nil)
("^ \\*undo-tree\\*"
:slot 2 :side left :size 20 :select t :quit t)
;; `help-mode', `helpful-mode'

View File

@@ -110,10 +110,15 @@
("~>" . #Xe167)
("~~" . #Xe168)
("~~>" . #Xe169)
("%%" . #Xe16a)))
("%%" . #Xe16a)
("x" . #Xe16b)
(":" . #Xe16c)
("+" . #Xe16d)
("+" . #Xe16e)
("*" . #Xe16f)))
(defun +pretty-code-setup-fira-ligatures-h ()
(set-fontset-font t '(#Xe100 . #Xe16f) +pretty-code-fira-code-font-name)
(set-fontset-font t '(#Xe100 . #Xe16f) +pretty-code-fira-code-font-name nil 'prepend)
(setq-default prettify-symbols-alist
(append prettify-symbols-alist
(mapcar #'+pretty-code--correct-symbol-bounds

View File

@@ -49,7 +49,7 @@
(defun +pretty-code-setup-hasklig-ligatures-h ()
(set-fontset-font t '(#Xe100 . #Xe129) +pretty-code-hasklig-font-name)
(set-fontset-font t '(#Xe100 . #Xe129) +pretty-code-hasklig-font-name nil 'prepend)
(setq-default prettify-symbols-alist
(append prettify-symbols-alist
(mapcar #'+pretty-code--correct-symbol-bounds

View File

@@ -224,7 +224,7 @@
"Defines the character mappings for ligatures for Iosevka.")
(defun +pretty-code-setup-iosevka-ligatures-h ()
(set-fontset-font t '(#Xe100 . #Xe1cc) +pretty-code-iosevka-font-name)
(set-fontset-font t '(#Xe100 . #Xe1cc) +pretty-code-iosevka-font-name nil 'prepend)
(setq-default prettify-symbols-alist
(append prettify-symbols-alist
+pretty-code-iosevka-font-ligatures)))

View File

@@ -1,55 +0,0 @@
;;; ui/pretty-code/settings.el -*- lexical-binding: t; -*-
;;;###autoload
(defvar +pretty-code-symbols-alist '((t))
"An alist containing a mapping of major modes to its value for
`prettify-symbols-alist'.")
;;;###autodef
(defun set-pretty-symbols! (modes &rest plist)
"Associates string patterns with icons in certain major-modes.
MODES is a major mode symbol or a list of them.
PLIST is a property list whose keys must match keys in `+pretty-code-symbols',
and whose values are strings representing the text to be replaced with that
symbol. If the car of PLIST is nil, then unset any pretty symbols previously
defined for MODES.
The following properties are special:
:alist ALIST
Appends ALIST to `prettify-symbols-alist' literally, without mapping text to
`+pretty-code-symbols'.
:merge BOOL
If non-nil, merge with previously defined `prettify-symbols-alist',
otherwise overwrite it.
For example, the rule for emacs-lisp-mode is very simple:
(set-pretty-symbols! 'emacs-lisp-mode
:lambda \"lambda\")
This will replace any instances of \"lambda\" in emacs-lisp-mode with the symbol
assicated with :lambda in `+pretty-code-symbols'.
Pretty symbols can be unset for emacs-lisp-mode with:
(set-pretty-symbols! 'emacs-lisp-mode nil)"
(declare (indent defun))
(if (null (car-safe plist))
(dolist (mode (doom-enlist modes))
(delq (assq mode +pretty-code-symbols-alist)
+pretty-code-symbols-alist))
(let (results merge key)
(while plist
(pcase (setq key (pop plist))
(:merge (setq merge (pop plist)))
(:alist (setq results (append (pop plist) results)))
(_
(when-let (char (plist-get +pretty-code-symbols key))
(push (cons (pop plist) char) results)))))
(dolist (mode (doom-enlist modes))
(unless merge
(delq (assq mode +pretty-code-symbols-alist)
+pretty-code-symbols-alist))
(push (cons mode results) +pretty-code-symbols-alist)))))

View File

@@ -5,6 +5,8 @@
:name "»"
:src_block "»"
:src_block_end "«"
:quote ""
:quote_end ""
;; Functional
:lambda "λ"
:def "ƒ"
@@ -18,6 +20,7 @@
:float ""
:str "𝕊"
:bool "𝔹"
:list "𝕃"
;; Flow
:not ""
:in ""
@@ -29,6 +32,9 @@
:return ""
:yield ""
;; Other
:union ""
:intersect ""
:diff ""
:tuple ""
:pipe "" ;; FIXME: find a non-private char
:dot "")
@@ -38,6 +44,65 @@ This should not contain any symbols from the Unicode Private Area! There is no
universal way of getting the correct symbol as that area varies from font to
font.")
(defvar +pretty-code-enabled-modes t
"List of major modes in which `prettify-symbols-mode' should be enabled.
If t, enable it everywhere. If the first element is 'not, enable it in any mode
besides what is listed.")
(defvar +pretty-code-symbols-alist '((t))
"An alist containing a mapping of major modes to its value for
`prettify-symbols-alist'.")
;;; Automatic font-specific ligatures
(defvar +prog-ligatures-alist
'((?! . "\\(?:!\\(?:==\\|[!=]\\)\\)") ; (regexp-opt '("!!" "!=" "!=="))
(?# . "\\(?:#\\(?:###?\\|_(\\|[#(:=?[_{]\\)\\)") ; (regexp-opt '("##" "###" "####" "#(" "#:" "#=" "#?" "#[" "#_" "#_(" "#{"))
(?$ . "\\(?:\\$>>?\\)") ; (regexp-opt '("$>" "$>>"))
(?% . "\\(?:%%%?\\)") ; (regexp-opt '("%%" "%%%"))
(?& . "\\(?:&&&?\\)") ; (regexp-opt '("&&" "&&&"))
(?* . "\\(?:\\*\\(?:\\*[*/]\\|[)*/>]\\)?\\)") ; (regexp-opt '("*" "**" "***" "**/" "*/" "*>" "*)"))
(?+ . "\\(?:\\+\\(?:\\+\\+\\|[+:>]\\)?\\)") ; (regexp-opt '("+" "++" "+++" "+>" "+:"))
(?- . "\\(?:-\\(?:-\\(?:->\\|[>-]\\)\\|<[<-]\\|>[>-]\\|[:<>|}~-]\\)\\)") ; (regexp-opt '("--" "---" "-->" "--->" "->-" "-<" "-<-" "-<<" "->" "->>" "-}" "-~" "-:" "-|"))
(?. . "\\(?:\\.\\(?:\\.[.<]\\|[.=>-]\\)\\)") ; (regexp-opt '(".-" ".." "..." "..<" ".=" ".>"))
(?/ . "\\(?:/\\(?:\\*\\*\\|//\\|==\\|[*/=>]\\)\\)") ; (regexp-opt '("/*" "/**" "//" "///" "/=" "/==" "/>"))
(?: . "\\(?::\\(?:::\\|[+:<=>]\\)?\\)") ; (regexp-opt '(":" "::" ":::" ":=" ":<" ":=" ":>" ":+"))
(?\; . ";;") ; (regexp-opt '(";;"))
(?0 . "0\\(?:\\(x[a-fA-F0-9]\\).?\\)") ; Tries to match the x in 0xDEADBEEF
;; (?x . "x") ; Also tries to match the x in 0xDEADBEEF
;; (regexp-opt '("<!--" "<$" "<$>" "<*" "<*>" "<**>" "<+" "<+>" "<-" "<--" "<---" "<->" "<-->" "<--->" "</" "</>" "<<" "<<-" "<<<" "<<=" "<=" "<=<" "<==" "<=>" "<===>" "<>" "<|" "<|>" "<~" "<~~" "<." "<.>" "<..>"))
(?< . "\\(?:<\\(?:!--\\|\\$>\\|\\*\\(?:\\*?>\\)\\|\\+>\\|-\\(?:-\\(?:->\\|[>-]\\)\\|[>-]\\)\\|\\.\\(?:\\.?>\\)\\|/>\\|<[<=-]\\|=\\(?:==>\\|[<=>]\\)\\||>\\|~~\\|[$*+./<=>|~-]\\)\\)")
(?= . "\\(?:=\\(?:/=\\|:=\\|<<\\|=[=>]\\|>>\\|[=>]\\)\\)") ; (regexp-opt '("=/=" "=:=" "=<<" "==" "===" "==>" "=>" "=>>"))
(?> . "\\(?:>\\(?:->\\|=>\\|>[=>-]\\|[:=>-]\\)\\)") ; (regexp-opt '(">-" ">->" ">:" ">=" ">=>" ">>" ">>-" ">>=" ">>>"))
(?? . "\\(?:\\?[.:=?]\\)") ; (regexp-opt '("??" "?." "?:" "?="))
(?\[ . "\\(?:\\[\\(?:|]\\|[]|]\\)\\)") ; (regexp-opt '("[]" "[|]" "[|"))
(?\\ . "\\(?:\\\\\\\\[\\n]?\\)") ; (regexp-opt '("\\\\" "\\\\\\" "\\\\n"))
(?^ . "\\(?:\\^==?\\)") ; (regexp-opt '("^=" "^=="))
(?w . "\\(?:wwww?\\)") ; (regexp-opt '("www" "wwww"))
(?{ . "\\(?:{\\(?:|\\(?:|}\\|[|}]\\)\\|[|-]\\)\\)") ; (regexp-opt '("{-" "{|" "{||" "{|}" "{||}"))
(?| . "\\(?:|\\(?:->\\|=>\\||=\\|[]=>|}-]\\)\\)") ; (regexp-opt '("|=" "|>" "||" "||=" "|->" "|=>" "|]" "|}" "|-"))
(?_ . "\\(?:_\\(?:|?_\\)\\)") ; (regexp-opt '("_|_" "__"))
(?\( . "\\(?:(\\*\\)") ; (regexp-opt '("(*"))
(?~ . "\\(?:~\\(?:~>\\|[=>@~-]\\)\\)")) ; (regexp-opt '("~-" "~=" "~>" "~@" "~~" "~~>"))
"An alist of all ligatures used by `+prog-ligatures-modes'.
The car is the character ASCII number, cdr is a regex which will call
`font-shape-gstring' when matched.
Because of the underlying code in :ui pretty-code module, the regex should match
a string starting with the character contained in car.
This variable is used only if you built Emacs with Harfbuzz on a version >= 28")
(defvar +prog-ligatures-modes '(not org-mode)
"List of major modes in which ligatures should be enabled.
If t, enable it everywhere. Fundamental mode, and modes derived from special-mode,
comint-mode, eshell-mode and term-mode are *still* excluded.
If the first element is 'not, enable it in any mode besides what is listed.
If nil, fallback to the prettify-symbols based replacement (add +font features to pretty-code).")
(defun +pretty-code--correct-symbol-bounds (ligature-alist)
"Prepend non-breaking spaces to a ligature.
@@ -50,14 +115,6 @@ correct width of the symbols instead of the width measured by `char-width'."
len (1- len)))
(cons (car ligature-alist) acc)))
(defvar +pretty-code-enabled-modes t
"List of major modes in which `prettify-symbols-mode' should be enabled.
If t, enable it everywhere. If the first element is 'not, enable it in any mode
besides what is listed.")
;; When you get to the right edge, it goes back to how it normally prints
(setq prettify-symbols-unprettify-at-point 'right-edge)
(defun +pretty-code-init-pretty-symbols-h ()
"Enable `prettify-symbols-mode'.
@@ -80,14 +137,63 @@ Otherwise it builds `prettify-code-symbols-alist' according to
(prettify-symbols-mode -1))
(prettify-symbols-mode +1))))
(defun +pretty-code-init-ligatures-h ()
"Enable ligatures.
If in fundamental-mode, or a mode derived from special, comint, eshell or term
modes, this function does nothing.
Otherwise it sets the buffer-local composition table to a composition table enhanced with
`+prog-ligatures-alist' ligatures regexes."
(unless (or (eq major-mode 'fundamental-mode)
(eq (get major-mode 'mode-class) 'special)
(derived-mode-p 'comint-mode 'eshell-mode 'term-mode))
(when (or (eq +prog-ligatures-modes t)
(if (eq (car +prog-ligatures-modes) 'not)
(not (memq major-mode (cdr +prog-ligatures-modes)))
(memq major-mode +prog-ligatures-modes)))
(setq-local composition-function-table composition-ligature-table))))
;;
;;; Bootstrap
(add-hook 'after-change-major-mode-hook #'+pretty-code-init-pretty-symbols-h)
;; Font-specific ligature support
(cond ((featurep! +fira)
(load! "+fira"))
((featurep! +iosevka)
(load! "+iosevka"))
((featurep! +hasklig)
(load! "+hasklig"))
((featurep! +pragmata-pro)
(load! "+pragmata-pro")))
;;;###package prettify-symbols
;; When you get to the right edge, it goes back to how it normally prints
(setq prettify-symbols-unprettify-at-point 'right-edge)
(cond
;; The emacs-mac build of Emacs appear to have built-in support for ligatures,
;; using the same composition-function-table method
;; https://bitbucket.org/mituharu/emacs-mac/src/26c8fd9920db9d34ae8f78bceaec714230824dac/lisp/term/mac-win.el?at=master#lines-345:805
;; so use that instead if this module is enabled.
((and IS-MAC (fboundp 'mac-auto-operator-composition-mode))
(mac-auto-operator-composition-mode))
;; Harfbuzz builds do not need font-specific ligature support
;; if they are above emacs-27
((and EMACS28+
(string-match-p "HARFBUZZ" system-configuration-features)
+prog-ligatures-modes
(require 'composite nil t))
(defvar composition-ligature-table (make-char-table nil))
(dolist (char-regexp +prog-ligatures-alist)
(set-char-table-range composition-ligature-table (car char-regexp)
`([,(cdr char-regexp) 0 font-shape-gstring])))
(unless doom-reloading-p
(set-char-table-parent composition-ligature-table composition-function-table))
(add-hook 'after-change-major-mode-hook #'+pretty-code-init-ligatures-h))
;; Font-specific ligature support
((featurep! +fira)
(load! "+fira"))
((featurep! +iosevka)
(load! "+iosevka"))
((featurep! +hasklig)
(load! "+hasklig"))
((featurep! +pragmata-pro)
(load! "+pragmata-pro")))

View File

@@ -1,77 +0,0 @@
;;; ui/tabs/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +tabs-buffer-predicate (buffer)
"TODO"
(or (memq buffer (window-parameter nil 'tab-buffers))
(eq buffer (doom-fallback-buffer))))
;;
;;; Commands
;;;###autoload
(defun +tabs/close-tab-or-window ()
"TODO"
(interactive)
(call-interactively
(cond ((cdr (window-parameter nil 'tab-buffers))
#'kill-current-buffer)
((fboundp '+workspace/close-window-or-workspace)
#'+workspace/close-window-or-workspace)
(#'delete-window))))
;;
;;; Advice
;;;###autoload
(defun +tabs-kill-current-buffer-a (&rest _)
(+tabs-remove-buffer-h))
;;;###autoload
(defun +tabs-bury-buffer-a (orig-fn &rest args)
(if centaur-tabs-mode
(let ((b (current-buffer)))
(apply orig-fn args)
(unless (eq b (current-buffer))
(with-current-buffer b
(+tabs-remove-buffer-h))))
(apply orig-fn args)))
;;;###autoload
(defun +tabs-kill-tab-maybe-a (tab)
(let ((buffer (centaur-tabs-tab-value tab)))
(with-current-buffer buffer
;; `kill-current-buffer' is advised not to kill buffers visible in another
;; window, so it behaves better than `kill-buffer'.
(kill-current-buffer))
(centaur-tabs-display-update)))
;;
;;; Hooks
;;;###autoload
(defun +tabs-add-buffer-h ()
(when (and centaur-tabs-mode
(doom-real-buffer-p (current-buffer)))
(let* ((this-buf (current-buffer))
(buffers (window-parameter nil 'tab-buffers)))
(cl-pushnew this-buf buffers)
(add-hook 'kill-buffer-hook #'+tabs-remove-buffer-h nil t)
(set-window-parameter nil 'tab-buffers buffers))))
;;;###autoload
(defun +tabs-remove-buffer-h ()
(when centaur-tabs-mode
(set-window-parameter
nil
'tab-buffers (delete (current-buffer)
(window-parameter nil 'tab-buffers)))))
;;;###autoload
(defun +tabs-new-window-h ()
(when centaur-tabs-mode
(unless (window-parameter nil 'tab-buffers)
(+tabs-add-buffer-h))))

View File

@@ -1,71 +1,23 @@
;;; ui/tabs/config.el -*- lexical-binding: t; -*-
(use-package! centaur-tabs
:after-call after-find-file dired-initial-position-hook
:hook (doom-first-file . centaur-tabs-mode)
:init
(setq centaur-tabs-height 28
(setq centaur-tabs-set-icons t
centaur-tabs-gray-out-icons 'buffer
centaur-tabs-set-bar 'left
centaur-tabs-set-modified-marker t)
centaur-tabs-set-modified-marker t
centaur-tabs-close-button ""
centaur-tabs-modified-marker ""
;; Scrolling (with the mouse wheel) past the end of the tab list
;; replaces the tab list with that of another Doom workspace. This
;; prevents that.
centaur-tabs-cycle-scope 'tabs)
:config
(add-hook! 'centaur-tabs-mode-hook
(defun +tabs-init-frames-h ()
(dolist (frame (frame-list))
(if (not centaur-tabs-mode)
(set-frame-parameter frame 'buffer-predicate (frame-parameter frame 'old-buffer-predicate))
(set-frame-parameter frame 'old-buffer-predicate (frame-parameter frame 'buffer-predicate))
(set-frame-parameter frame 'buffer-predicate #'+tabs-buffer-predicate)))))
(add-to-list 'window-persistent-parameters '(tab-buffers . t))
(defun +tabs-window-buffer-list-fn ()
(centaur-tabs-filter-out
'centaur-tabs-hide-tab-cached
(delq nil
(cl-mapcar #'(lambda (b)
(cond
;; Always include the current buffer.
((eq (current-buffer) b) b)
((buffer-file-name b) b)
((char-equal ?\ (aref (buffer-name b) 0)) nil)
((buffer-live-p b) b)))
(window-parameter nil 'tab-buffers)))))
(defun +tabs-buffer-groups-fn ()
(list
(cond ((or (string-equal "*" (substring (buffer-name) 0 1))
(memq major-mode '(magit-process-mode
magit-status-mode
magit-diff-mode
magit-log-mode
magit-file-mode
magit-blob-mode
magit-blame-mode
)))
"Emacs")
((derived-mode-p 'eshell-mode)
"EShell")
((derived-mode-p 'dired-mode)
"Dired")
((centaur-tabs-get-group-name (current-buffer))))))
(setq centaur-tabs-buffer-list-function #'+tabs-window-buffer-list-fn
centaur-tabs-buffer-groups-function #'+tabs-buffer-groups-fn)
(advice-add #'centaur-tabs-buffer-close-tab :override #'+tabs-kill-tab-maybe-a)
(advice-add #'bury-buffer :around #'+tabs-bury-buffer-a)
(advice-add #'kill-current-buffer :before #'+tabs-kill-current-buffer-a)
(add-hook 'doom-switch-buffer-hook #'+tabs-add-buffer-h)
(add-hook 'doom-switch-window-hook #'+tabs-new-window-h)
(add-hook '+doom-dashboard-mode-hook #'centaur-tabs-local-mode)
(add-hook '+popup-buffer-mode-hook #'centaur-tabs-local-mode))
(map! (:map centaur-tabs-mode-map
[remap delete-window] #'+tabs/close-tab-or-window
[remap +workspace/close-window-or-workspace] #'+tabs/close-tab-or-window)
(:after persp-mode
:map persp-mode-map
[remap delete-window] #'+tabs/close-tab-or-window
[remap +workspace/close-window-or-workspace] #'+tabs/close-tab-or-window))
(centaur-tabs-mode +1))
;; TODO tab-bar-mode (emacs 27)
;; TODO tab-line-mode (emacs 27)

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/tabs/packages.el
(package! centaur-tabs)
(package! centaur-tabs :pin "2154fa9679c5fa02a2a7e3d4c739256fd991a789")

View File

@@ -1,22 +1,5 @@
;;; ui/treemacs/autoload.el -*- lexical-binding: t; -*-
(defun +treemacs--init ()
(require 'treemacs)
(let ((origin-buffer (current-buffer)))
(cl-letf (((symbol-function 'treemacs-workspace->is-empty?)
(symbol-function 'ignore)))
(treemacs--init))
(dolist (project (treemacs-workspace->projects (treemacs-current-workspace)))
(treemacs-do-remove-project-from-workspace project))
(with-current-buffer origin-buffer
(let ((project-root (or (doom-project-root) default-directory)))
(treemacs-do-add-project-to-workspace
(treemacs--canonical-path project-root)
(doom-project-name project-root)))
(setq treemacs--ready-to-follow t)
(when (or treemacs-follow-after-init treemacs-follow-mode)
(treemacs--follow)))))
;;;###autoload
(defun +treemacs/toggle ()
"Initialize or toggle treemacs.
@@ -29,13 +12,6 @@ Use `treemacs' command for old functionality."
(require 'treemacs)
(pcase (treemacs-current-visibility)
(`visible (delete-window (treemacs-get-local-window)))
(_ (+treemacs--init))))
;;;###autoload
(defun +treemacs/find-file (arg)
"Open treemacs (if necessary) and find current file."
(interactive "P")
(let ((origin-buffer (current-buffer)))
(+treemacs--init)
(with-current-buffer origin-buffer
(treemacs-find-file arg))))
(_ (if (doom-project-p)
(treemacs-add-and-display-current-project)
(treemacs)))))

View File

@@ -1,25 +1,48 @@
;;; ui/treemacs/config.el -*- lexical-binding: t; -*-
(setq treemacs-follow-after-init t
treemacs-is-never-other-window t
treemacs-sorting 'alphabetic-case-insensitive-asc
treemacs-persist-file (concat doom-cache-dir "treemacs-persist")
treemacs-last-error-persist-file (concat doom-cache-dir "treemacs-last-error-persist"))
(defvar +treemacs-git-mode 'simple
"Type of git integration for `treemacs-git-mode'.
There are 3 possible values:
1) `simple', which highlights only files based on their git status, and is
slightly faster,
2) `extended', which highlights both files and directories, but requires
python,
3) `deferred', same as extended, but highlights asynchronously.
This must be set before `treemacs' has loaded.")
(after! treemacs
(set-popup-rule! "^ \\*Treemacs"
:side treemacs-position
:size treemacs-width
:quit nil
:ttl 0)
;;
;;; Packages
(use-package! treemacs
:defer t
:init
(setq treemacs-follow-after-init t
treemacs-is-never-other-window t
treemacs-sorting 'alphabetic-case-insensitive-asc
treemacs-persist-file (concat doom-cache-dir "treemacs-persist")
treemacs-last-error-persist-file (concat doom-cache-dir "treemacs-last-error-persist"))
:config
;; Allow ace-window to target treemacs windows
(after! ace-window
(delq! 'treemacs-mode aw-ignored-buffers))
;; Don't follow the cursor
(treemacs-follow-mode -1)
;; Allow ace-window to target treemacs windows
(after! ace-window
(delq! 'treemacs-mode aw-ignored-buffers)))
(when +treemacs-git-mode
;; If they aren't supported, fall back to simpler methods
(when (and (memq +treemacs-git-mode '(deferred extended))
(not (executable-find "python3")))
(setq +treemacs-git-mode 'simple))
(treemacs-git-mode +treemacs-git-mode)
(setq treemacs-collapse-dirs
(if (memq treemacs-git-mode '(extended deferred))
3
0))))
(use-package! treemacs-evil
@@ -43,3 +66,9 @@
(use-package! treemacs-magit
:when (featurep! :tools magit)
:after treemacs magit)
(use-package! treemacs-persp
:when (featurep! :ui workspaces)
:after treemacs
:config (treemacs-set-scope-type 'Perspectives))

View File

@@ -1,9 +1,12 @@
;; -*- no-byte-compile: t; -*-
;;; ui/treemacs/packages.el
(package! treemacs)
(package! treemacs :pin "327bf63e58348e0b5070054477db801d5392cd75")
;; These packages have no :pin because they're in the same repo
(when (featurep! :editor evil +everywhere)
(package! treemacs-evil))
(package! treemacs-projectile)
(when (featurep! :tools magit)
(package! treemacs-magit))
(when (featurep! :ui workspaces)
(package! treemacs-persp))

View File

@@ -1,10 +1,92 @@
#+TITLE: :ui unicode
#+TITLE: ui/unicode
#+DATE: June 8, 2020
#+SINCE: v2.0
#+STARTUP: inlineimages nofold
This unicode extends Doom's ability to display non-English unicode.
This is for non-English Emacs users, for whom Doom's built-in unicode support in insufficient.
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]
- [[#maintainers][Maintainers]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#features][Features]]
- [[#configuration][Configuration]]
- [[#getting-fonts-with-good-coverage][Getting fonts with good coverage]]
- [[#advanced-configuration][Advanced configuration]]
- [[#troubleshooting][Troubleshooting]]
- [[#emacs-daemon-mode][Emacs daemon mode]]
* Description
This module extends Doom's ability to display non-English unicode.
It is primarily useful for non-English Emacs users, for whom Doom's built-in unicode support in insufficient.
This module relies on the [[https://github.com/rolandwalker/unicode-fonts][unicode-fonts]] package. It tries to setup the default emacs fontset to cover as many unicode glyphs as possible by scanning all available glyphs from all available fonts.
When this module is enabled...
+ Emacs will prefer to use the ~doom-unicode-font~ font to display non-latin glyphs if it provides coverage for them.
+ The first time you run Emacs a unicode cache will be generated -- this will take a while!
+ Doom will ignore the ~doom-unicode-font~ variable and the ~:unicode-font~ setting.
+ The cache will be regenerated every time Emacs is made aware of new fonts or you change the font configuration e.g. by modifying ~doom-unicode-font~.
+ The cache will be stored and should not be regenerated unless font-related configuration or the versions of relevant packages changes.
** Maintainers
This module has no dedicated maintainers.
** Module Flags
This module provides no flags.
** Plugins
+ [[https://github.com/rolandwalker/unicode-fonts][unicode-fonts]]
* Prerequisites
This module has no prerequisites.
* Features
# An in-depth list of features, how to use them, and their dependencies.
* Configuration
The first font that will be analyzed to see if it contains the glyphs of non-latin characters will be ~doom-unicode-font~. To set this font place
#+BEGIN_SRC elisp
(setq doom-unicode-font (font-spec :family "Fira Mono"))
#+END_SRC
in your private =config.el= file. If your ~doom-font~ provides good unicode coverage you just set
#+BEGIN_SRC elisp
(setq doom-unicode-font doom-font)
#+END_SRC
If your font does not provide some glyphs, this package will try its best to find another font that does.
** Getting fonts with good coverage
A list of fonts with good unicode coverage can be found on the page of the [[https://github.com/rolandwalker/unicode-fonts#minimum-useful-fonts][unicode-fonts]] package.
** Advanced configuration
Consult the [[https://github.com/rolandwalker/unicode-font][unicode-fonts]] package documentation for a description of more advanced configuration. The configuration should be placed, as usual, in your private =config.el= wrapped in an ~(after! unicode-fonts)~ block. The variable ~unicode-fonts-blocks~ contains a list of all unicode block names and their character ranges. The default fonts to search for glyphs are in the variable ~unicode-fonts-block-font-mapping~.
If you want to use the font =Symbola= for =Miscellaneous Symbols= by default you could add
#+BEGIN_SRC elisp
(after! unicode-fonts
(push "Symbola" (cadr (assoc "Miscellaneous Symbols" unicode-fonts-block-font-mapping))))
#+END_SRC
to your =config.el=.
If you want to redefine several blocks an efficient way would be
#+BEGIN_SRC elisp
(after! unicode-fonts
(dolist (unicode-block '("Mathematical Alphanumeric Symbols"
"Mathematical Operators"
"Miscellaneous Mathematical Symbols-A"
"Miscellaneous Mathematical Symbols-B"
"Miscellaneous Symbols"
"Miscellaneous Symbols and Arrows"
"Miscellaneous Symbols and Pictographs"))
(push "DejaVu Math TeX Gyre" (cadr (assoc unicode-block unicode-fonts-block-font-mapping)))))
#+END_SRC
You can find a list of fonts available to emacs using ~M-x counsel-fonts~.
* Troubleshooting
# Common issues and their solution, or places to look for help.
** TODO Emacs daemon mode
Currently this module may fail setup fonts when emacs is run in daemon mode. See [[https://github.com/hlissner/doom-emacs/issues/3328][Bug 3328]].

View File

@@ -7,15 +7,21 @@
necessary."
(setq-default bidi-display-reordering t
doom-unicode-font nil)
(if initial-window-system
(if (display-graphic-p)
(+unicode-setup-fonts-h (selected-frame))
(add-hook 'after-make-frame-functions #'+unicode-setup-fonts-h))))
;;;###autoload
(defun +unicode-setup-fonts-h (&optional frame)
"Initialize `unicode-fonts', if in a GUI session."
"Initialize `unicode-fonts', if in a GUI session.
If doom-unicode-font is set, add it as preferred font for all unicode blocks."
(when (and frame (display-graphic-p frame))
(with-selected-frame frame
(require 'unicode-fonts)
(when doom-unicode-font
(let ((doom-unicode-font-family (plist-get (font-face-attributes doom-unicode-font) :family)))
(dolist (unicode-block unicode-fonts-block-font-mapping)
(push doom-unicode-font-family (cadr unicode-block)))))
;; NOTE will impact startup time on first run
(unicode-fonts-setup))))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/unicode/packages.el
(package! unicode-fonts)
(package! unicode-fonts :pin "7b88ae84e589f6c8b9386b2fb5a02ff4ccb91169")

View File

@@ -23,5 +23,12 @@
("m" git-gutter:mark-hunk)
("p" git-gutter:popup-hunk)
("R" git-gutter:set-start-revision)
("q" nil :color blue)
("Q" (git-gutter-mode -1) :color blue))
("q"
(when (get-buffer git-gutter:popup-buffer)
(kill-buffer (get-buffer git-gutter:popup-buffer)))
:color blue)
("Q"
(progn (git-gutter-mode -1)
(when (get-buffer git-gutter:popup-buffer)
(kill-buffer (get-buffer git-gutter:popup-buffer))))
:color blue))

View File

@@ -11,13 +11,13 @@
diffing, even for unsaved buffers.")
(defvar +vc-gutter-default-style t
"If non-nil, enable the default look of the vc gutter. This means subtle thin
bitmaps on the left, an arrow bitmap for flycheck, and flycheck indicators moved
to the right fringe.")
"If non-nil, enable the default look of the vc gutter.
This means subtle thin bitmaps on the left, an arrow bitmap for flycheck, and
flycheck indicators moved to the right fringe.")
;;
;; Packages
;;; Packages
(use-package! git-gutter
:commands git-gutter:revert-hunk git-gutter:stage-hunk
@@ -28,42 +28,43 @@ to the right fringe.")
If the buffer doesn't represent an existing file, `git-gutter-mode's activation
is deferred until the file is saved. Respects `git-gutter:disabled-modes'."
(when (or +vc-gutter-in-remote-files
(not (file-remote-p (or buffer-file-name default-directory))))
(if (not buffer-file-name)
(add-hook 'after-save-hook #'+vc-gutter-init-maybe-h nil 'local)
(when (and (vc-backend buffer-file-name)
(progn
(require 'git-gutter)
(not (memq major-mode git-gutter:disabled-modes))))
(if (and (display-graphic-p)
(require 'git-gutter-fringe nil t))
(progn
(setq-local git-gutter:init-function #'git-gutter-fr:init)
(setq-local git-gutter:view-diff-function #'git-gutter-fr:view-diff-infos)
(setq-local git-gutter:clear-function #'git-gutter-fr:clear)
(setq-local git-gutter:window-width -1))
(setq-local git-gutter:init-function 'nil)
(setq-local git-gutter:view-diff-function #'git-gutter:view-diff-infos)
(setq-local git-gutter:clear-function #'git-gutter:clear-diff-infos)
(setq-local git-gutter:window-width 1))
(git-gutter-mode +1)
(remove-hook 'after-save-hook #'+vc-gutter-init-maybe-h 'local))))))
(let ((file-name (buffer-file-name (buffer-base-buffer))))
(when (or +vc-gutter-in-remote-files
(not (file-remote-p (or file-name default-directory))))
(if (null file-name)
(add-hook 'after-save-hook #'+vc-gutter-init-maybe-h nil 'local)
(when (and (vc-backend file-name)
(progn
(require 'git-gutter)
(not (memq major-mode git-gutter:disabled-modes))))
(if (and (display-graphic-p)
(require 'git-gutter-fringe nil t))
(setq-local git-gutter:init-function #'git-gutter-fr:init
git-gutter:view-diff-function #'git-gutter-fr:view-diff-infos
git-gutter:clear-function #'git-gutter-fr:clear
git-gutter:window-width -1)
(setq-local git-gutter:init-function 'nil
git-gutter:view-diff-function #'git-gutter:view-diff-infos
git-gutter:clear-function #'git-gutter:clear-diff-infos
git-gutter:window-width 1))
(git-gutter-mode +1)
(remove-hook 'after-save-hook #'+vc-gutter-init-maybe-h 'local)))))))
;; Disable in Org mode, as per
;; <https://github.com/syl20bnr/spacemacs/issues/10555> and
;; <https://github.com/syohex/emacs-git-gutter/issues/24>. Apparently, the
;; mode-enabling function for global minor modes gets called for new buffers
;; while they are still in `fundamental-mode', before a major mode has been
;; assigned. I don't know why this is the case, but adding `fundamental-mode'
;; here fixes the issue.
;; Disable in Org mode, as per syl20bnr/spacemacs#10555 and
;; syohex/emacs-git-gutter#24. Apparently, the mode-enabling function for
;; global minor modes gets called for new buffers while they are still in
;; `fundamental-mode', before a major mode has been assigned. I don't know why
;; this is the case, but adding `fundamental-mode' here fixes the issue.
(setq git-gutter:disabled-modes '(fundamental-mode image-mode pdf-view-mode))
;; standardize default fringe width
(if (fboundp 'fringe-mode) (fringe-mode '4))
:config
(set-popup-rule! "^\\*git-gutter" :select nil :size '+popup-shrink-to-fit)
;; Only enable the backends that are available, so it doesn't have to check
;; when opening each buffer.
(setq git-gutter:handled-backends
(cons 'git (cl-remove-if-not #'executable-find (list 'hg 'svn 'bzr)
:key #'symbol-name)))
;; Update git-gutter on focus (in case I was using git externally)
(add-hook 'focus-in-hook #'git-gutter:update-all-windows)
@@ -73,7 +74,8 @@ is deferred until the file is saved. Respects `git-gutter:disabled-modes'."
`doom-escape-hook' hooks."
(when (and git-gutter-mode
(not (memq this-command '(git-gutter:stage-hunk
git-gutter:revert-hunk))))
git-gutter:revert-hunk)))
(not inhibit-redisplay))
(ignore (git-gutter)))))
;; update git-gutter when using magit commands
(advice-add #'magit-stage-file :after #'+vc-gutter-update-h)
@@ -92,8 +94,11 @@ is deferred until the file is saved. Respects `git-gutter:disabled-modes'."
;; subtle diff indicators in the fringe
(when +vc-gutter-default-style
(after! git-gutter-fringe
(after! git-gutter-fringe
(when +vc-gutter-default-style
;; standardize default fringe width
(if (fboundp 'fringe-mode) (fringe-mode '4))
;; places the git gutter outside the margins.
(setq-default fringes-outside-margins t)
;; thin fringe bitmaps
@@ -102,10 +107,12 @@ is deferred until the file is saved. Respects `git-gutter:disabled-modes'."
(define-fringe-bitmap 'git-gutter-fr:modified [224]
nil nil '(center repeated))
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240]
nil nil 'bottom)
nil nil 'bottom)))
(after! flycheck
(when +vc-gutter-default-style
;; let diff have left fringe, flycheck can have right fringe
(after! flycheck
(setq flycheck-indication-mode 'right-fringe)
;; A non-descript, left-pointing arrow
(define-fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
[16 48 112 240 112 48 16] nil nil 'center))))
(setq flycheck-indication-mode 'right-fringe)
;; A non-descript, left-pointing arrow
(define-fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
[16 48 112 240 112 48 16] nil nil 'center)))

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/vc-gutter/packages.el
(package! git-gutter-fringe)
(package! git-gutter-fringe :pin "da19a474137876b29b5658ee7e9ae366f2b65c1d")

View File

@@ -1,4 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/vi-tilde-fringe/packages.el
(package! vi-tilde-fringe)
(package! vi-tilde-fringe :pin "f1597a8d54535bb1d84b442577b2024e6f910308")

View File

@@ -16,8 +16,9 @@
:init
(global-set-key [remap other-window] #'ace-window)
:config
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)
aw-scope 'frame
(unless (featurep! +numbers)
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
(setq aw-scope 'frame
aw-background t))

View File

@@ -2,8 +2,8 @@
;;; ui/window-select/packages.el
(if (featurep! +switch-window)
(package! switch-window)
(package! ace-window))
(package! switch-window :pin "8710f6304d843365fb59b6efe7e1f729d14e557c")
(package! ace-window :pin "7003c88cd9cad58dc35c7cd13ebc61c355fb5be7"))
(when (featurep! +numbers)
(package! winum))
(package! winum :pin "c5455e866e8a5f7eab6a7263e2057aff5f1118b9"))

View File

@@ -68,20 +68,19 @@ error if NAME doesn't exist."
"Return a list of workspace structs (satisifes `+workspace-p')."
;; We don't use `hash-table-values' because it doesn't ensure order in older
;; versions of Emacs
(cdr (cl-loop for persp being the hash-values of *persp-hash*
collect persp)))
(cl-loop for name in persp-names-cache
if (gethash name *persp-hash*)
collect it))
;;;###autoload
(defun +workspace-list-names ()
"Return the list of names of open workspaces."
(mapcar #'safe-persp-name (+workspace-list)))
persp-names-cache)
;;;###autoload
(defun +workspace-buffer-list (&optional persp)
"Return a list of buffers in PERSP.
The buffer list is ordered by recency (same as `buffer-list').
PERSP can be a string (name of a workspace) or a workspace (satisfies
`+workspace-p'). If nil or omitted, it defaults to the current workspace."
(let ((persp (or persp (+workspace-current))))
@@ -174,11 +173,12 @@ throws an error."
(+workspace-new name)
(error "%s is not an available workspace" name)))
(let ((old-name (+workspace-current-name)))
(setq +workspace--last
(or (and (not (string= old-name persp-nil-name))
old-name)
+workspaces-main))
(persp-frame-switch name)
(unless (equal old-name name)
(setq +workspace--last
(or (and (not (string= old-name persp-nil-name))
old-name)
+workspaces-main))
(persp-frame-switch name))
(equal (+workspace-current-name) name)))
@@ -268,13 +268,20 @@ workspace to delete."
('error (+workspace-error ex t))))
;;;###autoload
(defun +workspace/kill-session ()
(defun +workspace/kill-session (&optional interactive)
"Delete the current session, all workspaces, windows and their buffers."
(interactive)
(unless (cl-every #'+workspace-delete (+workspace-list-names))
(+workspace-error "Could not clear session"))
(+workspace-switch +workspaces-main t)
(doom/kill-all-buffers (buffer-list)))
(interactive (list t))
(let ((windows (length (window-list)))
(persps (length (+workspace-list-names)))
(buffers 0))
(let ((persp-autokill-buffer-on-remove t))
(unless (cl-every #'+workspace-delete (+workspace-list-names))
(+workspace-error "Could not clear session")))
(+workspace-switch +workspaces-main t)
(setq buffers (doom/kill-all-buffers (buffer-list)))
(when interactive
(message "Killed %d workspace(s), %d window(s) & %d buffer(s)"
persps windows buffers))))
;;;###autoload
(defun +workspace/kill-session-and-quit ()
@@ -335,7 +342,8 @@ end of the workspace list."
;;;###autoload
(dotimes (i 9)
(defalias (intern (format "+workspace/switch-to-%d" i))
(lambda () (interactive) (+workspace/switch-to i))))
(lambda () (interactive) (+workspace/switch-to i))
(format "Switch to workspace #%d" (1+ i))))
;;;###autoload
(defun +workspace/switch-to-final ()
@@ -396,6 +404,31 @@ the next."
((+workspace-error "Can't delete last workspace" t)))))))
;;;###autoload
(defun +workspace/swap-left (&optional count)
"Swap the current workspace with the COUNTth workspace on its left."
(interactive "p")
(let* ((current-name (+workspace-current-name))
(count (or count 1))
(index (- (cl-position current-name persp-names-cache :test #'equal)
count))
(names (remove current-name persp-names-cache)))
(unless names
(user-error "Only one workspace"))
(let ((index (min (max 0 index) (length names))))
(setq persp-names-cache
(append (cl-subseq names 0 index)
(list current-name)
(cl-subseq names index))))
(when (called-interactively-p 'any)
(+workspace/display))))
;;;###autoload
(defun +workspace/swap-right (&optional count)
"Swap the current workspace with the COUNTth workspace on its right."
(interactive "p")
(funcall-interactively #'+workspace/swap-left (- count)))
;;
;;; Tabs display in minibuffer
@@ -492,32 +525,46 @@ the user to open a file in the new project.
This be hooked to `projectile-after-switch-project-hook'."
(when dir
(setq +workspaces--project-dir dir))
(when (and persp-mode +workspaces--project-dir)
(unwind-protect
(if (and (not (null +workspaces-on-switch-project-behavior))
(or (eq +workspaces-on-switch-project-behavior t)
(+workspace-buffer-list)))
(let* ((persp
(let ((project-name (doom-project-name +workspaces--project-dir)))
(or (+workspace-get project-name t)
(+workspace-new project-name))))
(new-name (persp-name persp)))
(+workspace-switch new-name)
(with-current-buffer (doom-fallback-buffer)
(setq default-directory +workspaces--project-dir))
(unless current-prefix-arg
(funcall +workspaces-switch-project-function +workspaces--project-dir))
(+workspace-message
(format "Switched to '%s' in new workspace" new-name)
'success))
(with-current-buffer (doom-fallback-buffer)
(setq default-directory +workspaces--project-dir)
(message "Switched to '%s'" (doom-project-name +workspaces--project-dir)))
(with-demoted-errors "Workspace error: %s"
(+workspace-rename (+workspace-current-name) (doom-project-name +workspaces--project-dir)))
(unless current-prefix-arg
(funcall +workspaces-switch-project-function +workspaces--project-dir)))
(setq +workspaces--project-dir nil))))
;; HACK Clear projectile-project-root, otherwise cached roots may interfere
;; with project switch (see #3166)
(let (projectile-project-root)
(when (and persp-mode +workspaces--project-dir)
(when projectile-before-switch-project-hook
(with-temp-buffer
;; Load the project dir-local variables into the switch buffer, so the
;; action can make use of them
(setq default-directory +workspaces--project-dir)
(hack-dir-local-variables-non-file-buffer)
(run-hooks 'projectile-before-switch-project-hook)))
(unwind-protect
(if (and (not (null +workspaces-on-switch-project-behavior))
(or (eq +workspaces-on-switch-project-behavior t)
(equal (safe-persp-name (get-current-persp)) persp-nil-name)
(+workspace-buffer-list)))
(let* ((persp
(let ((project-name (doom-project-name +workspaces--project-dir)))
(or (+workspace-get project-name t)
(+workspace-new project-name))))
(new-name (persp-name persp)))
(+workspace-switch new-name)
(with-current-buffer (doom-fallback-buffer)
(setq default-directory +workspaces--project-dir)
(hack-dir-local-variables-non-file-buffer))
(unless current-prefix-arg
(funcall +workspaces-switch-project-function +workspaces--project-dir))
(+workspace-message
(format "Switched to '%s' in new workspace" new-name)
'success))
(with-current-buffer (doom-fallback-buffer)
(setq default-directory +workspaces--project-dir)
(hack-dir-local-variables-non-file-buffer)
(message "Switched to '%s'" (doom-project-name +workspaces--project-dir)))
(with-demoted-errors "Workspace error: %s"
(+workspace-rename (+workspace-current-name) (doom-project-name +workspaces--project-dir)))
(unless current-prefix-arg
(funcall +workspaces-switch-project-function +workspaces--project-dir)))
(run-hooks 'projectile-after-switch-project-hook)
(setq +workspaces--project-dir nil)))))
;;

View File

@@ -50,11 +50,13 @@ stored in `persp-save-dir'.")
(persp-mode +1)))))
:config
(setq persp-autokill-buffer-on-remove 'kill-weak
persp-reset-windows-on-nil-window-conf nil
persp-nil-hidden t
persp-auto-save-fname "autosave"
persp-save-dir (concat doom-etc-dir "workspaces/")
persp-set-last-persp-for-new-frames t
persp-switch-to-added-buffer nil
persp-kill-foreign-buffer-behaviour 'kill
persp-remove-buffers-from-nil-persp-behaviour nil
persp-auto-resume-time -1 ; Don't auto-load on startup
persp-auto-save-opt (if noninteractive 0 1)) ; auto-save on kill
@@ -62,28 +64,36 @@ stored in `persp-save-dir'.")
(advice-add #'persp-asave-on-exit :around #'+workspaces-autosave-real-buffers-a)
(add-hook! '(persp-mode-hook persp-after-load-state-functions)
(defun +workspaces-ensure-main-workspace-h (&rest _)
"Ensure the main workspace exists and the nil workspace is never active."
(defun +workspaces-ensure-no-nil-workspaces-h (&rest _)
(when persp-mode
(let (persp-before-switch-functions)
;; The default perspective persp-mode creates (`persp-nil-name') is
;; special and doesn't represent a real persp object, so buffers can't
;; really be assigned to it, among other quirks. We create a *real* main
;; workspace to fill this role.
(unless (persp-get-by-name +workspaces-main)
(persp-add-new +workspaces-main))
;; Switch to it if we're in the nil perspective
(dolist (frame (frame-list))
(when (string= (safe-persp-name (get-current-persp frame)) persp-nil-name)
(persp-frame-switch +workspaces-main frame)
;; Fix #319: the warnings buffer gets swallowed by creating
;; `+workspaces-main', so we display it manually, if it exists.
(when-let (warnings (get-buffer "*Warnings*"))
(save-excursion
(display-buffer-in-side-window
warnings '((window-height . shrink-window-if-larger-than-buffer)))))))))))
(dolist (frame (frame-list))
(when (string= (safe-persp-name (get-current-persp frame)) persp-nil-name)
;; Take extra steps to ensure no frame ends up in the nil perspective
(persp-frame-switch (or (cadr (hash-table-keys *persp-hash*))
+workspaces-main)
frame))))))
(add-hook! 'persp-mode-hook
(defun +workspaces-init-first-workspace-h (&rest _)
"Ensure a main workspace exists."
(when persp-mode
(let (persp-before-switch-functions)
;; The default perspective persp-mode creates is special and doesn't
;; represent a real persp object, so buffers can't really be assigned
;; to it, among other quirks, so we get rid of it...
(when (equal (car persp-names-cache) persp-nil-name)
(pop persp-names-cache))
;; ...and create a *real* main workspace to fill this role.
(unless (or (persp-get-by-name +workspaces-main)
;; Start from 2 b/c persp-mode counts the nil workspace
(> (hash-table-count *persp-hash*) 2))
(persp-add-new +workspaces-main))
;; HACK Fix #319: the warnings buffer gets swallowed when creating
;; `+workspaces-main', so display it ourselves, if it exists.
(when-let (warnings (get-buffer "*Warnings*"))
(save-excursion
(display-buffer-in-side-window
warnings '((window-height . shrink-window-if-larger-than-buffer))))))))
(defun +workspaces-init-persp-mode-h ()
(cond (persp-mode
;; `uniquify' breaks persp-mode. It renames old buffers, which causes
@@ -108,15 +118,15 @@ stored in `persp-save-dir'.")
;; add buffers when they are switched to.
(setq persp-add-buffer-on-find-file nil
persp-add-buffer-on-after-change-major-mode nil)
(add-hook! '(doom-switch-buffer-hook server-visit-hook)
(defun +workspaces-add-current-buffer-h ()
"Add current buffer to focused perspective."
(and persp-mode
(not (persp-buffer-filtered-out-p
(current-buffer)
persp-add-buffer-on-after-change-major-mode-filter-functions))
(persp-add-buffer (current-buffer) (get-current-persp) nil nil))))
(or (not persp-mode)
(persp-buffer-filtered-out-p
(or (buffer-base-buffer (current-buffer))
(current-buffer))
persp-add-buffer-on-after-change-major-mode-filter-functions)
(persp-add-buffer (current-buffer) (get-current-persp) nil nil))))
(add-hook 'persp-add-buffer-on-after-change-major-mode-filter-functions
#'doom-unreal-buffer-p)
@@ -171,7 +181,10 @@ stored in `persp-save-dir'.")
("xt" counsel-projectile-switch-project-action-run-term "invoke term from project root")
("X" counsel-projectile-switch-project-action-org-capture "org-capture into project")))
(add-hook 'projectile-after-switch-project-hook #'+workspaces-switch-to-project-h)
(when (featurep! :completion helm)
(after! helm-projectile
(setcar helm-source-projectile-projects-actions
'("Switch to Project" . +workspaces-switch-to-project-h))))
;; Fix #1973: visual selection surviving workspace changes
(add-hook 'persp-before-deactivate-functions #'deactivate-mark)

View File

@@ -1,5 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; ui/workspaces/packages.el
(package! persp-mode)
(package! persp-mode :pin "391a7dc248c9c04b7ad424c696bdff578e14dd2c")