Merge remote-tracking branch 'origin/develop' into download-iosevka

This commit is contained in:
James Ravn 2020-02-25 19:50:12 +00:00
commit 3a257cfc56
No known key found for this signature in database
GPG key ID: 52C372C72159D6EE
428 changed files with 9639 additions and 6497 deletions

View file

@ -1,43 +1,41 @@
---
name: Bug report
about: Something went wrong, please fix it!
about: Doom might be misbehaving
labels: is:bug
title: "[BUG] "
assignees: ''
---
**Describe the issue**
Start with a brief 1 or 2 sentence summary of issue.
**What did you expect to happen?**
...
Then follow with a longer explanation, if necessary. Here are some suggestions
on what to include:
- What you expected vs what actually happened
- Screenshots/casts of your issue
- A link to your private config
- Labels for any keys you reference (use `SPC h k` to inspect a key)
- Any warnings or errors logged to \*Messages\* (`SPC h e` or `M-x
view-echo-area-messages`).
**What actually happened?**
...
**Additional details:**
- Include a link to your private config
- Include screenshots/casts of your issue
- If you mention key sequences, include what commands they're bound to (use `SPC
h k KEY` or `C-h h k KEY` to inspect keys).
- Include any warnings or errors logged to \*Messages\* (use `M-x
view-echo-area-messages` to see it).
<details><pre>
If available, please a backtrace of the error here.
If an error message is involved include a backtrace of it.
To acquire a backtrace, enable `debug-on-error` then recreate the error. Here
are ways to enable `debug-on-error`:
- `M-x toggle-debug-on-error`,
- Start Emacs with `emacs --debug-init`
- If the error occurred while using `bin/doom`, use the `-d`/`--debug`
- switches or the `DEBUG` environment variable.
How to acquire a backtrace:
https://github.com/hlissner/doom-emacs/blob/develop/docs/getting_started.org#how-to-extract-a-backtrace-from-an-error
</pre></details>
**Steps to reproduce**
**Steps to reproduce:**
1. Select these example steps,
2. Delete them,
3. And replace them with precise steps to reproduce your issue.
4. Fill in "system information" below.
**System information**
**System information:**
<details><pre>
Place the output of `M-x doom/info` or `~/.emacs.d/bin/doom info` here.
</pre></details>

View file

@ -1,28 +1,20 @@
---
name: Feature request
about: Make suggestions for improving Doom Emacs
labels: is:request
title: "[REQUEST] "
assignees: ''
about: It'd be cool if Doom did/had/would...
labels: is:new
---
**Describe the feature**
Start with a brief 1 or 2 sentence summary of feature.
Then follow up with an extended explanation, if necessary. Here are some
suggestions on what to include:
- How is it helpful?
- How is the feature used?
- If the feature involves new plugins, include links to them
- iF the feature involves replacement of current functionality, describe how the
new functionality is better.
- If the feature is implemented in another editor Emacs distro:
- Include screenshots or screencasts of it
- Include links to its implementation
- Include names of commands (and not just the keybinds to invoke them)
- If the feature involves replacement of current functionality, how the new
functionality is better?
- If the feature is implemented in another editor or Emacs distro, include:
- Screenshots or screencasts of it
- Links to its implementation
- Names of relevant commands (and not only the keybinds to invoke them)
**System information**
<details><pre>
Include the output of `M-x doom/info` or `~/.emacs.d/bin/doom info` here.
Place the output of `M-x doom/info` or `~/.emacs.d/bin/doom info` here.
</pre></details>

View file

@ -1,23 +1,26 @@
---
name: How do I...
about: How to get Doom/Emacs to behave a certain way
labels: is:howto, status:pending-review
title: "[HOWTO] "
assignees: ''
labels: is:question
---
**What I want to achieve**
Start with a brief 1 or 2 sentence summary of what you're trying to achieve.
> Please visit our Discord server to ask how-to and workflow questions:
> https://discord.gg/qvGgnVx -- post on Doom's issue tracker as a last resort.
Follow up with an expanded explanation, if necessary. A few suggestions of what
you could include are:
- Code or steps you've tried that did not yield the results you wanted.
- Screenshots/casts of a proposed workflow in another editor or Emacs distro,
- Additional material or links to resources that could help clarify what you are
trying to do.
- A link to your private config, if available.
- The names of commands available in other Emacs distros (rather than just the
keybinds that invoke them).
**What are you trying to achieve?**
...
**What have you tried?**
...
**Additional information**
- Do you have screenshots/casts of this workflow in another editor or Emacs
distro? (If possible, include names of specific commands or functions from
other editors/emacs distros)
- Do you have additional material or links to resources that could help clarify
what you are trying to do?
**System information**

View file

@ -1,9 +0,0 @@
---
name: Question
about: A question about the project or maintainer
labels: is:question, status:pending-review
title: "[QUESTION] "
assignees: ''
---
What would you like to know?

30
.github/PULL_REQUEST/bump.md vendored Normal file
View file

@ -0,0 +1,30 @@
---
name: Bump a package
about: Update a pinned package to a new commit
labels: is:update re:packages
---
> You're about to request a package be bumped to a newer commit.
>
> 1. Please make sure this PR targets the `develop` branch and not `master`.
> 2. Describe why these bumps are necessary below
> 3. Please conform your commit messages to one of the following formats:
>
> Bump to username/repo@a1b2c3d
>
> From username/repo@z9y8x7w
>
> OR, if multiple packages are bumped in one commit:
>
> Bump package1, package2 & package 3
>
> emacs-lsp/lsp-mode@91e37a6 -> emacs-lsp/lsp-mode@c8188ef
> emacs-lsp/lsp-ui@cf6906c -> emacs-lsp/lsp-ui@582e153
>
> (Commit hashes should be limited to 7 characters)
>
> 4. You've included links to relevant issues, if any
> 5. You've deleted this template
>
> Thank you for contributing to Doom Emacs! <3
Explain why this bump is necessary here...

View file

@ -1,6 +1,10 @@
> To ensure that this PR is processed as quickly as possible, please ensure the
> following steps have been taken:
> - [ ] This PR targets the develop branch and not master
---
name: General Contribution
about: A general code or documentation PR
---
> Please follow these steps before submitting your PR:
>
> - [ ] This PR targets the `develop` branch and not `master`
> - [ ] If your PR is a work in progress, include [WIP] in its title
> - [ ] Its commits' summaries are reasonably descriptive
> - [ ] You've described what this PR addresses below

5
.gitignore vendored
View file

@ -7,12 +7,15 @@ modules/private
.cask/
cask/
elpa/
test/.local*/
# emacs tempfiles that shouldn't be there
.mc-lists.el
.org-id-locations
.tern-port
auto-save-list
.extension/
.dap-breakpoints
auto-save-list/
semanticdb
ede-projects.el
tramp

View file

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016-2019 Henrik Lissner.
Copyright (c) 2016-2020 Henrik Lissner.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,85 +0,0 @@
DOOM = "bin/doom"
MODULES = $(patsubst modules/%/, %, $(sort $(dir $(wildcard modules/*/ modules/*/*/))))
all: deprecated
@$(DOOM) refresh
deprecated:
@echo "Using make to manage your Doom config is deprecated"
@echo
@echo "Use the 'bin/doom' script instead. The equivalent of 'make' is 'doom refresh'."
@echo
@echo "See 'doom help' for a list of commands"
@echo
@read -p "Press enter to continue"
## Shortcuts
a: autoloads
i: install
u: update
U: upgrade
r: autoremove
c: compile
cc: compile-core
cp: compile-plugins
re: recompile
d: doctor
quickstart: install
## Package management
install: deprecated
@$(DOOM) install
update: deprecated
@$(DOOM) update
autoremove: deprecated
@$(DOOM) autoremove
autoloads: deprecated
@$(DOOM) autoloads
upgrade: deprecated
@$(DOOM) upgrade
## Byte compilation
compile: deprecated
@$(DOOM) compile
compile-core: deprecated
@$(DOOM) compile :core
compile-private: deprecated
@$(DOOM) compile :private
compile-plugins: deprecated
@$(DOOM) build
recompile: deprecated
@$(DOOM) recompile
clean: deprecated
@$(DOOM) clean
# compile-module
# compile-module/submodule
$(patsubst %, compile-%, $(MODULES)): | .local/autoloads.el
@$(DOOM) $@ $(subst compile-, , $@)
## Unit tests
test:
@$(DOOM) test
test-core:
@$(DOOM) test :core
# test-module
# test-module/submodule
$(patsubst %, test-%, $(MODULES)):
@$(DOOM) test $(subst test-, , $@)
## Utility tasks
# Runs Emacs from a different folder than ~/.emacs.d; only use this for testing!
run:
@$(DOOM) run $(ARGS)
# Prints debug info about your current setup
info:
@$(DOOM) info
# Diagnoses potential OS/environment issues
doctor:
@$(DOOM) doctor
.PHONY: all compile test testi clean

View file

@ -7,7 +7,7 @@
<a href="https://github.com/hlissner/doom-emacs/actions">
<img src="https://github.com/hlissner/doom-emacs/workflows/CI/badge.svg" alt="Build status: develop">
</a>
<a href="https://discord.gg/bcZ6P3y">
<a href="https://discord.gg/qvGgnVx">
<img src="https://img.shields.io/badge/Discord-blue.svg?logo=discord&label=join" alt="Join our discord server" align="right">
</a>
<br><br>
@ -35,6 +35,9 @@ git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
~/.emacs.d/bin/doom install
```
More details, including dependencies and how to install Emacs, can be found [in
the documentation](docs/getting_started.org#install).
**Table of Contents**
- [What is Doom Emacs](#what-is-doom-emacs)
@ -55,46 +58,47 @@ It is a story as old as time. A stubborn, shell-dwelling, and melodramatic
vimmer -- envious of the features of modern text editors -- spirals into despair
before succumbing to the [dark side][url:evil-mode]. This is his config.
Doom is a configuration for [GNU Emacs](https://www.gnu.org/software/emacs/)
designed to make Emacs faster and easier to customize. It can serve as framework
for your own configuration or a resource for fellow Emacs enthusiasts who want
to learn more about our favorite OS.
Doom is a configuration framework for [GNU
Emacs](https://www.gnu.org/software/emacs/) tailored for Emacs bankruptcy
veterans who want less framework in their frameworks and the performance of a
hand rolled config (or better). It can be a foundation for your own config or a
resource for Emacs enthusiasts to learn more about our favorite OS.
## Doom's mantras
- **Gotta go fast.** Startup and run-time performance are high priorities.
Expensive functionality (built-in or in plugins) is modified and optimized
toward this end, otherwise, they must be opt-in.
- **Close to metal.** There's less between you and vanilla Emacs, by design.
There's less to grok. Modules should be syntactically sweet and backend logic
explicit and abstraction-light. The code itself ought to be designed as if
grokking it were part of the user experience; and it is!
- **Opinionated, but not stubborn.** Doom is a bundle of reasonable defaults
and curated opinions, but you aren't stuck with it. Use as little or as much
of it as you like. Use it as-is as a complete Emacs distribution; disable
everything and use it as a baseline for your own; or anywhere in between.
- **Your system, your rules.** There are more ways to set up your programming
environment than there are dislikes on Youtube Rewind '18, so Doom and its
plugins promise not to *automatically* (and definitely not *silently*) install
system dependencies. This means fonts, packages and programs. `doom doctor`
will tell you what's missing though!
- **Gotta go fast.** Startup and run-time performance are priorities. Doom goes
beyond lazy loading packages by modifying them to be snappier and load lazier!
- **Close to metal.** There's less between you and vanilla Emacs by design.
There's less to grok, on top of Emacs.
- **Readability counts.** Internals ought to be written as if reading them were
part of the user experience, and it is! Modules should be syntactically sweet.
Backend logic should be functional (as much as elisp permits), abstraction
light and (hopefully) documented.
- **Opinionated, but not stubborn.** Doom is a bundle of reasonable defaults and
curated opinions, but all of it should be optional. Use as little or as much
of it as you like.
- **Your system, your rules.** There are more ways to set up your development
environment than there are dislikes on Youtube Rewind '18, so Doom leaves it
to you. Doom will not *automatically* install system dependencies (and will
coerce its plugins not to do so either). Use `doom doctor` to figure out
what's missing.
## Features
- Minimalistic good looks inspired by modern editors.
- A modular architecture for a more organized Emacs configuration.
- A custom elisp library to help simplify your config.
- (Optional) Vim-emulation powered by [evil-mode][url:evil-mode], including
ports of popular vim plugins and functionality.
- A declarative [package management system][doom:packages] (powered by
[straight.el][url:straight]) with a command line interface. Install packages
from anywhere, not just (M)ELPA.
- A curated set of sane defaults for all packages, all (major) OSes, and Emacs
itself.
- Support for *many* programming languages. Too many to list. Includes syntax
highlighting, linters/checker integration, inline code evaluation, code
completion (where possible), REPLs, documentation lookups, snippets, and more!
- Support for *many* tools, like docker, pass, ansible, terraform, and more.
- Minimalistic good looks inspired by modern editors.
- A modular architecture for a more organized Emacs configuration.
- A custom elisp library to help you simplify your config.
- A declarative [package management system][doom:packages] (powered by
[straight.el][url:straight]) with a command line interface. Install packages
from anywhere, not just (M)ELPA.
- Vim-emulation powered by [evil-mode][url:evil-mode], including ports of
popular vim plugins and functionality.
- A Spacemacs-esque [keybinding scheme][doom:bindings], centered around leader
and localleader prefix keys (<kbd>SPC</kbd> and <kbd>SPC</kbd><kbd>m</kbd>, by
default).
@ -104,12 +108,11 @@ to learn more about our favorite OS.
integration. Let someone else argue about tabs vs **\_\***spaces**\*\_**.
- Project-management tools and framework-specific minor modes with their own
snippets libraries.
- Project search (and replace) utilities, powered by
[the_silver_searcher][url:the_silver_searcher] or [ripgrep][url:ripgrep].
- Project search (and replace) utilities, powered by [ripgrep][url:ripgrep].
- Isolated and persistent workspaces (also substitutes for vim tabs).
- An environment variables file generator and loader, so that Emacs can
perfectly inherit your shell configuration.
- Everything is optional!
- An envvar file generator that captures a snapshot of your shell environment
for Doom to load at startup. No more struggling to get Emacs to inherit your
`PATH`, among other things.
# Getting Help
@ -122,7 +125,7 @@ We have [a Discord server][url:discord]! Hop on and say hi!
Encountered strange behavior or an error? Here are some things to try before you
shoot off that bug report:
- Run `bin/doom refresh`. This ensures Doom is properly set up and its autoloads
- Run `bin/doom sync`. This ensures Doom is properly set up and its autoloads
files are up-to-date.
- If you have byte-compiled your config (with `bin/doom compile`), see if
`bin/doom clean` makes the issue go away. Never debug issues with a
@ -168,11 +171,10 @@ you can do to help; I welcome any contribution!
[doom:bindings]: modules/config/default/+evil-bindings.el
[doom:packages]: core/autoload/packages.el
[doom:popups]: modules/ui/popup/README.org
[url:discord]: https://discord.gg/bcZ6P3y
[url:discord]: https://discord.gg/qvGgnVx
[url:liberapay]: https://liberapay.com/hlissner/donate
[url:paypal]: https://paypal.me/henriklissner/10
[url:editorconfig]: http://editorconfig.org/
[url:evil-mode]: https://github.com/emacs-evil/evil
[url:ripgrep]: https://github.com/BurntSushi/ripgrep
[url:the_silver_searcher]: https://github.com/ggreer/the_silver_searcher
[url:straight]: https://github.com/raxod502/straight.el

View file

@ -9,10 +9,11 @@
:; exec $EMACS --script "$0" -- "$@"
:; exit 0
(let* ((loaddir (file-name-directory (file-truename load-file-name)))
(let* ((load-prefer-newer t)
(loaddir (file-name-directory (file-truename load-file-name)))
(emacsdir (getenv "EMACSDIR"))
(user-emacs-directory (or emacsdir (expand-file-name "../" loaddir)))
(load-prefer-newer t))
(user-emacs-directory
(abbreviate-file-name (or emacsdir (expand-file-name "../" loaddir)))))
(push (expand-file-name "core" user-emacs-directory) load-path)
(require 'core)
@ -51,9 +52,18 @@ with a different private module."
(setq doom-auto-accept t)
(print! (info "Auto-yes on")))
(when help-p
(push command args)
(when command
(push command args))
(setq command "help"))
(when (equal (user-real-uid) 0)
(print!
(concat "WARNING: This script is running as root. This likely wasn't intentional, and\n"
"is unnecessary to use this script. This will cause file permissions errors\n"
"later if you use this Doom installation on a non-root account.\n"))
(unless (or doom-auto-accept (y-or-n-p "Continue anyway?"))
(user-error "Aborted")))
;; Reload core in case any of the directories were changed.
(when (or emacsdir doomdir localdir)
(load! "core/core.el" user-emacs-directory))
@ -69,29 +79,43 @@ with a different private module."
((condition-case e
(let ((start-time (current-time)))
(and (doom-cli-execute command args)
(terpri)
(print! (success "Finished! (%.4fs)")
(float-time
(time-subtract (current-time)
start-time)))))
(user-error
(print! (error "%s\n") (error-message-string e))
(print! (yellow "See 'doom help %s' for documentation on this command.") (car args)))
(print! (yellow "See 'doom help %s' for documentation on this command.") (car args))
(error "")) ; Ensure non-zero exit code
((debug error)
(message "--------------------------------------------------\n")
(message "There was an unexpected error:")
(message " %s (%s)" (get (car e) 'error-message) (car e))
(dolist (item (cdr e))
(message " %s" item))
(print! (error "There was an unexpected error:"))
(print-group!
(print! "%s %s" (bold "Type:") (car e))
(print! (bold "Message:"))
(print-group!
(print! "%s" (get (car e) 'error-message)))
(print! (bold "Data:"))
(print-group!
(if (cdr e)
(dolist (item (cdr e))
(print! "%S" item))
(print! "n/a")))
(when (featurep 'straight)
(when (string-match-p (regexp-quote straight-process-buffer)
(error-message-string e))
(print! (bold "Straight output:"))
(print-group! (print! "%s" (straight--process-get-output))))))
(unless debug-on-error
(message
(concat "\nRun the command again with the -d (or --debug) option to enable debug\n"
"mode and, hopefully, generate a stack trace. If you decide to file a bug\n"
"report, please include it!\n\n"
"Emacs outputs to standard error, so you'll need to redirect stderr to\n"
"stdout to pipe this to a file or clipboard!\n\n"
" e.g. doom -d install 2>&1 | clipboard-program\n"))
(signal 'doom-error e)))))))
(terpri)
(print!
(concat "Run the command again with the -d (or --debug) switch to enable debug\n"
"mode and (hopefully) generate a backtrace from this error:\n"
"\n %s\n\n"
"If you file a bug report, please include it!")
(string-join (append (list (file-name-nondirectory load-file-name) "-d" command)
args)
" "))
(error ""))))))) ; Ensure non-zero exit code
(doom-cli-execute :main (cdr (member "--" argv)))
(setq argv nil))

View file

@ -22,8 +22,8 @@ fi
# org-capture key mapped to argument flags
# keys=$(emacsclient -e "(+org-capture-available-keys)" | cut -d '"' -f2)
while getopts hk opt; do
key="\"$opt\""
while getopts "hk:" opt; do
key="\"$OPTARG\""
break
done
shift $((OPTIND-1))

View file

@ -195,7 +195,9 @@ If DERIVED-P, test with `derived-mode-p', otherwise use `eq'."
;;;###autoload
(defun doom-set-buffer-real (buffer flag)
"Forcibly mark BUFFER as FLAG (non-nil = real)."
"Forcibly mark BUFFER as FLAG (non-nil = real).
See `doom-real-buffer-p' for an explanation for real buffers."
(with-current-buffer buffer
(setq doom-real-buffer-p flag)))
@ -251,7 +253,9 @@ regex PATTERN. Returns the number of killed buffers."
;;;###autoload
(defun doom-mark-buffer-as-real-h ()
"Hook function that marks the current buffer as real."
"Hook function that marks the current buffer as real.
See `doom-real-buffer-p' for an explanation for real buffers."
(doom-set-buffer-real (current-buffer) t))
@ -272,6 +276,12 @@ If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
(set-buffer-modified-p nil)))
(doom-kill-buffer-fixup-windows buffer))
(defun doom--message-or-count (interactive message count)
(if interactive
(message message count)
count))
;;;###autoload
(defun doom/kill-all-buffers (&optional buffer-list interactive)
"Kill all buffers and closes their windows.
@ -286,14 +296,14 @@ belong to the current project."
(if (null buffer-list)
(message "No buffers to kill")
(save-some-buffers)
(delete-other-windows)
(when (memq (current-buffer) buffer-list)
(switch-to-buffer (doom-fallback-buffer)))
(mapc #'doom-kill-buffer-and-windows buffer-list)
(delete-other-windows)
(when interactive
(message "Killed %s buffers"
(- (length buffer-list)
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))))
(mapc #'kill-buffer buffer-list)
(doom--message-or-count
interactive "Killed %d buffers"
(- (length buffer-list)
(length (cl-remove-if-not #'buffer-live-p buffer-list))))))
;;;###autoload
(defun doom/kill-other-buffers (&optional buffer-list interactive)
@ -308,10 +318,10 @@ project."
(doom-buffer-list)))
t))
(mapc #'doom-kill-buffer-and-windows buffer-list)
(when interactive
(message "Killed %s buffers"
(- (length buffer-list)
(length (cl-remove-if-not #'buffer-live-p buffer-list))))))
(doom--message-or-count
interactive "Killed %d other buffers"
(- (length buffer-list)
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))
;;;###autoload
(defun doom/kill-matching-buffers (pattern &optional buffer-list interactive)
@ -340,7 +350,11 @@ current project."
(list (doom-buried-buffers
(if current-prefix-arg (doom-project-buffer-list)))
t))
(doom/kill-all-buffers buffer-list interactive))
(mapc #'kill-buffer buffer-list)
(doom--message-or-count
interactive "Killed %d buried buffers"
(- (length buffer-list)
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))
;;;###autoload
(defun doom/kill-project-buffers (project &optional interactive)
@ -358,9 +372,9 @@ current project."
nil)
t))
(when project
(let ((buffers (doom-project-buffer-list project)))
(doom-kill-buffers-fixup-windows buffers)
(when interactive
(message "Killed %d buffer(s)"
(- (length buffers)
(length (cl-remove-if-not #'buffer-live-p buffers))))))))
(let ((buffer-list (doom-project-buffer-list project)))
(doom-kill-buffers-fixup-windows buffer-list)
(doom--message-or-count
interactive "Killed %d project buffers"
(- (length buffer-list)
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))))

View file

@ -1,86 +1,5 @@
;;; core/autoload/cli.el -*- lexical-binding: t; -*-
;; Externs
(defvar evil-collection-mode-list)
;;;###autoload
(defun doom--cli-run (command &rest _args)
(when (featurep 'general)
(general-auto-unbind-keys))
(let* ((evil-collection-mode-list nil)
(default-directory doom-emacs-dir)
(buf (get-buffer-create " *bin/doom*"))
(doom-format-backend 'ansi)
(ignore-window-parameters t)
(noninteractive t)
(standard-output
(lambda (char)
(with-current-buffer buf
(insert char)
(when (memq char '(?\n ?\r))
(ansi-color-apply-on-region (line-beginning-position -1) (line-end-position))
(redisplay))))))
(doom-initialize t)
(setq doom-modules (doom-modules))
(doom-initialize-modules t)
(doom-initialize-packages t)
(with-current-buffer (switch-to-buffer buf)
(erase-buffer)
(require 'package)
(redisplay)
(doom-dispatch command nil)
(print! (green "\nDone!"))))
(when (featurep 'general)
(general-auto-unbind-keys 'undo))
(message (format! (green "Done!"))))
;;;###autoload
(defun doom//autoloads (&optional yes)
"TODO"
(interactive "P")
(let ((doom-auto-accept yes))
(doom--cli-run "autoloads")))
;;;###autoload
(defun doom//update (&optional yes)
"TODO"
(interactive "P")
(let ((doom-auto-accept yes))
(doom--cli-run "update")))
;;;###autoload
(defun doom//upgrade (&optional yes)
"TODO"
(interactive "P")
(let ((doom-auto-accept yes))
(doom--cli-run "upgrade"))
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect. Restart?")
(doom/restart-and-restore)))
;;;###autoload
(defun doom//install (&optional yes)
"TODO"
(interactive "P")
(let ((doom-auto-accept yes))
(doom--cli-run "install")))
;;;###autoload
(defun doom//autoremove (&optional yes)
"TODO"
(interactive "P")
(let ((doom-auto-accept yes))
(doom--cli-run "autoremove")))
;;;###autoload
(defun doom//refresh (&optional yes)
"TODO"
(interactive "P")
(let ((doom-auto-accept yes))
(doom--cli-run "refresh")))
;;
;;; Library
@ -113,7 +32,7 @@ Warning: freezes indefinitely on any stdin prompt."
:connection-type 'pipe))
done-p)
(set-process-filter
process (lambda (process output)
process (lambda (_process output)
(princ output (current-buffer))
(princ output)))
(set-process-sentinel

View file

@ -1,5 +1,8 @@
;;; core/autoload/config.el -*- lexical-binding: t; -*-
(defvar doom-bin-dir (concat doom-emacs-dir "bin/"))
(defvar doom-bin (concat doom-bin-dir "doom"))
;;;###autoload
(defvar doom-reload-hook nil
"A list of hooks to run when `doom/reload' is called.")
@ -23,8 +26,9 @@
(doom-project-find-file doom-private-dir))
;;;###autoload
(defun doom/goto-doomblock ()
"Open your private init.el and go to your `doom!' block."
(defun doom/goto-private-init-file ()
"Open your private init.el file.
And jumps to your `doom!' block."
(interactive)
(find-file (expand-file-name "init.el" doom-private-dir))
(goto-char
@ -34,46 +38,58 @@
(point))))
;;;###autoload
(defun doom/goto-config-file ()
(defun doom/goto-private-config-file ()
"Open your private config.el file."
(interactive)
(find-file (expand-file-name "config.el" doom-private-dir)))
;;;###autoload
(defun doom/goto-packages-file ()
(defun doom/goto-private-packages-file ()
"Open your private packages.el file."
(interactive)
(find-file (expand-file-name "packages.el" doom-private-dir)))
;;
;;; Managements
(cl-defmacro doom--compile (command &key on-success on-failure)
(declare (indent defun))
`(with-current-buffer (compile ,command)
(add-hook
'compilation-finish-functions
(lambda (_buf status)
(if (equal status "finished\n")
,on-success
,on-failure))
nil 'local)))
;;;###autoload
(defun doom/reload ()
"Reloads your private config.
This is experimental! It will try to do as `bin/doom refresh' does, but from
within this Emacs session. i.e. it reload autoloads files (if necessary),
reloads your package list, and lastly, reloads your private config.el.
This is experimental! It will try to do as `bin/doom sync' does, but from within
this Emacs session. i.e. it reload autoloads files (if necessary), reloads your
package list, and lastly, reloads your private config.el.
Runs `doom-reload-hook' afterwards."
(interactive)
(or (y-or-n-p
(concat "You are about to reload your Doom config from within Emacs. This "
"is highly experimental and may cause issues. It is recommended you "
"use 'bin/doom refresh' on the command line instead.\n\n"
"Reload anyway?"))
(user-error "Aborted"))
(require 'core-cli)
(let ((doom-reloading-p t))
(compile (format "%s/bin/doom refresh -f" doom-emacs-dir))
(while compilation-in-progress
(sit-for 1))
(doom-initialize 'force)
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
(general-auto-unbind-keys)
(unwind-protect
(doom-initialize-modules 'force)
(general-auto-unbind-keys t)))
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook))
(message "Finished!"))
(when (and IS-WINDOWS (file-exists-p doom-env-file))
(warn "Can't regenerate envvar file from within Emacs. Run 'doom env' from the console"))
(doom--compile (format "%s sync -e" doom-bin)
:on-success
(let ((doom-reloading-p t))
(doom-initialize 'force)
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
(general-auto-unbind-keys)
(unwind-protect
(doom-initialize-modules 'force)
(general-auto-unbind-keys t)))
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook)
(print! (success "Config successfully reloaded!")))
:on-failure
(user-error "Failed to reload your config")))
;;;###autoload
(defun doom/reload-autoloads ()
@ -83,23 +99,45 @@ This is much faster and safer than `doom/reload', but not as comprehensive. This
reloads your package and module visibility, but does not install new packages or
remove orphaned ones. It also doesn't reload your private config.
It is useful to only pull in changes performed by 'doom refresh' on the command
It is useful to only pull in changes performed by 'doom sync' on the command
line."
(interactive)
(require 'core-cli)
(require 'core-packages)
(doom-initialize-packages)
(doom-reload-autoloads nil 'force))
(doom-cli-reload-autoloads))
;;;###autoload
(defun doom/reload-env ()
"Regenerates and reloads your shell environment.
(defun doom/reload-env (&optional arg)
"Regenerates and/or reloads your envvar file.
Uses the same mechanism as 'bin/doom env reload'."
If passed the prefix ARG, clear the envvar file. Uses the same mechanism as
'bin/doom env'.
An envvar file contains a snapshot of your shell environment, which can be
imported into Emacs."
(interactive "P")
(when IS-WINDOWS
(user-error "Cannot reload envvar file from within Emacs on Windows, run it from cmd.exe"))
(doom--compile
(format "%s -ic '%s env%s'"
(string-trim
(shell-command-to-string
(format "getent passwd %S | cut -d: -f7"
(user-login-name))))
doom-bin (if arg " -c" ""))
:on-success
(let ((doom-reloading-p t))
(unless arg
(doom-load-envvars-file doom-env-file)))
:on-failure
(error "Failed to generate env file")))
;;;###autoload
(defun doom/upgrade ()
"Run 'doom upgrade' then prompt to restart Emacs."
(interactive)
(compile (format "%s env" (expand-file-name "bin/doom" doom-emacs-dir)))
(while compilation-in-progress
(sit-for 1))
(unless (file-readable-p doom-env-file)
(error "Failed to generate env file"))
(doom-load-envvars-file doom-env-file))
(doom--compile (format "%s upgrade" doom-bin)
:on-success
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect.\n\nRestart Emacs?")
(doom/restart-and-restore))))

View file

@ -23,11 +23,25 @@
(when (file-exists-p file)
(insert-file-contents file))))
(defun doom--collect-forms-in (file form)
(when (file-readable-p file)
(let (forms)
(with-temp-buffer
(insert-file-contents file)
(delay-mode-hooks (emacs-lisp-mode))
(while (re-search-forward (format "(%s " (regexp-quote form)) nil t)
(unless (doom-point-in-string-or-comment-p)
(save-excursion
(goto-char (match-beginning 0))
(push (sexp-at-point) forms))))
(nreverse forms)))))
;;;###autoload
(defun doom-info ()
"Returns diagnostic information about the current Emacs session in markdown,
ready to be pasted in a bug report on github."
(require 'vc-git)
(require 'core-packages)
(let ((default-directory doom-emacs-dir)
(doom-modules (doom-modules)))
(cl-letf
@ -46,7 +60,8 @@ ready to be pasted in a bug report on github."
'server-running))))
(doom
(version . ,doom-version)
(build . ,(sh "git" "log" "-1" "--format=%D %h %ci")))
(build . ,(sh "git" "log" "-1" "--format=%D %h %ci"))
(dir . ,(abbreviate-file-name (file-truename doom-private-dir))))
(system
(type . ,system-type)
(config . ,system-configuration)
@ -78,24 +93,29 @@ ready to be pasted in a bug report on github."
(cdr key))))
'("n/a")))
(packages
,@(or (ignore-errors
(let ((doom-interactive-mode t)
doom-packages
doom-disabled-packages)
(doom--read-module-packages-file
(doom-path doom-private-dir "packages.el")
nil t)
(cl-loop for (name . plist) in (nreverse doom-packages)
collect
(if-let (splist (doom-plist-delete (copy-sequence plist)
:modules))
(prin1-to-string (cons name splist))
name))))
,@(or (condition-case e
(mapcar
#'cdr (doom--collect-forms-in
(doom-path doom-private-dir "packages.el")
"package!"))
(error (format "<%S>" e)))
'("n/a")))
(unpin
,@(or (condition-case e
(mapcan #'identity
(mapcar
#'cdr (doom--collect-forms-in
(doom-path doom-private-dir "packages.el")
"unpin!")))
(error (format "<%S>" e)))
'("n/a")))
(elpa
,@(or (ignore-errors
(cl-loop for (name . _) in package-alist
collect (format "%s" name)))
,@(or (condition-case e
(progn
(package-initialize)
(cl-loop for (name . _) in package-alist
collect (format "%s" name)))
(error (format "<%S>" e)))
'("n/a"))))))))
@ -197,7 +217,7 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
(prin1-to-string
(macroexp-progn
(append `((setq noninteractive nil
doom-debug-mode t
init-file-debug t
load-path ',load-path
package--init-file-ensured t
package-user-dir ,package-user-dir
@ -209,8 +229,10 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
(setq-default buffer-undo-tree (make-undo-tree))))
(pcase mode
(`vanilla-doom+ ; Doom core + modules - private config
`((setq doom-init-modules-p t)
(load-file ,user-init-file)
`((load-file ,(expand-file-name "core.el" doom-core-dir))
(doom-initialize)
(doom-initialize-core)
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
(setq doom-modules ',doom-modules)
(maphash (lambda (key plist)
(let ((doom--current-module key)
@ -225,8 +247,9 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
(doom-run-all-startup-hooks-h)))
(`vanilla-doom ; only Doom core
`((setq doom-init-modules-p t)
(load-file ,user-init-file)
`((load-file ,(expand-file-name "core.el" doom-core-dir))
(doom-initialize)
(doom-initialize-core)
(doom-run-all-startup-hooks-h)))
(`vanilla ; nothing loaded
`((package-initialize)))))))
@ -335,6 +358,10 @@ will be automatically appended to the result."
((> (prefix-numeric-value arg) 0)))))
(setq doom-debug-mode value
debug-on-error value
garbage-collection-messages value
use-package-verbose value
jka-compr-verbose value
lsp-log-io value)
lsp-log-io value
gcmh-verbose value
magit-refresh-verbose value)
(message "Debug mode %s" (if value "on" "off"))))

View file

@ -108,26 +108,26 @@ be relative to it.
The search recurses up to DEPTH and no further. DEPTH is an integer.
MATCH is a string regexp. Only entries that match it will be included."
(let (file-name-handler-alist
result)
(let (result file-name-handler-alist)
(dolist (file (mapcan (doom-rpartial #'doom-glob "*") (doom-enlist paths)))
(cond ((file-directory-p file)
(nconcq! result
(and (memq type '(t dirs))
(string-match-p match file)
(not (and filter (funcall filter file)))
(not (and (file-symlink-p file)
(not follow-symlinks)))
(<= mindepth 0)
(list (cond (map (funcall map file))
(relative-to (file-relative-name file relative-to))
(file))))
(and (>= depth 1)
(apply #'doom-files-in file
(append (list :mindepth (1- mindepth)
:depth (1- depth)
:relative-to relative-to)
rest)))))
(appendq!
result
(and (memq type '(t dirs))
(string-match-p match file)
(not (and filter (funcall filter file)))
(not (and (file-symlink-p file)
(not follow-symlinks)))
(<= mindepth 0)
(list (cond (map (funcall map file))
(relative-to (file-relative-name file relative-to))
(file))))
(and (>= depth 1)
(apply #'doom-files-in file
(append (list :mindepth (1- mindepth)
:depth (1- depth)
:relative-to relative-to)
rest)))))
((and (memq type '(t files))
(string-match-p match file)
(not (and filter (funcall filter file)))
@ -178,6 +178,7 @@ single file or nested compound statement of `and' and `or' statements."
file))
(nth 7 (file-attributes file))))
(defvar w32-get-true-file-attributes)
;;;###autoload
(defun doom-directory-size (dir)
"Returns the size of FILE (in DIR) in kilobytes."
@ -202,16 +203,14 @@ single file or nested compound statement of `and' and `or' statements."
;;
;;; Helpers
(defun doom--forget-file (old-path &optional new-path)
(defun doom--forget-file (path)
"Ensure `recentf', `projectile' and `save-place' forget OLD-PATH."
(when (bound-and-true-p recentf-mode)
(when new-path
(recentf-add-file new-path))
(recentf-remove-if-non-kept old-path))
(recentf-remove-if-non-kept path))
(when (and (bound-and-true-p projectile-mode)
(doom-project-p)
(projectile-file-cached-p old-path (doom-project-root)))
(projectile-purge-file-from-cache old-path))
(projectile-file-cached-p path (doom-project-root)))
(projectile-purge-file-from-cache path))
(when (bound-and-true-p save-place-mode)
(save-place-forget-unreadable-files)))
@ -220,7 +219,8 @@ single file or nested compound statement of `and' and `or' statements."
(vc-file-clearprops path)
(vc-resynch-buffer path nil t))
(when (featurep 'magit)
(magit-refresh)))
(when-let (default-directory (magit-toplevel (file-name-directory path)))
(magit-refresh))))
(defun doom--copy-file (old-path new-path &optional force-p)
(let* ((new-path (expand-file-name new-path))
@ -306,11 +306,18 @@ file if it exists, without confirmation."
(let ((old-path (buffer-file-name))
(new-path (expand-file-name new-path)))
(when-let (dest (doom--copy-file old-path new-path force-p))
(doom--forget-file old-path)
(when (file-exists-p old-path)
(delete-file old-path))
(mapc #'doom--update-file
(delq
nil (list (if (ignore-errors
(file-equal-p (doom-project-root old-path)
(doom-project-root new-path)))
nil
old-path)
new-path)))
(kill-current-buffer)
(doom--forget-file old-path new-path)
(doom--update-file new-path)
(find-file new-path)
(message "File successfully moved to %s" dest))))
(`overwrite-self (error "Cannot overwrite self"))
@ -339,4 +346,21 @@ file if it exists, without confirmation."
(defun doom/sudo-this-file ()
"Open the current file as root."
(interactive)
(find-alternate-file (doom--sudo-file buffer-file-name)))
(find-alternate-file (doom--sudo-file (or buffer-file-name
(when (or (derived-mode-p 'dired-mode)
(derived-mode-p 'wdired-mode))
default-directory)))))
;;;###autoload
(defun doom/sudo-save-buffer ()
"Save this file as root."
(interactive)
(let ((file (doom--sudo-file buffer-file-name)))
(if-let (buffer (find-file-noselect file))
(let ((origin (current-buffer)))
(unwind-protect
(with-current-buffer buffer
(save-buffer))
(unless (eq origin buffer)
(kill-buffer buffer))))
(user-error "Unable to open %S" file))))

View file

@ -16,49 +16,51 @@ acceptable values for this variable.")
"How many steps to increase the font size (with `doom-font' as the base) when
`doom-big-font-mode' is enabled and `doom-big-font' is nil.")
;;;###autoload
(defvar doom-change-font-size-hook nil
"A hook run after adjusting the font size with `doom/increase-font-size',
`doom/decrease-font-size', or `doom/reset-font-size'.")
;;
;;; Library
(defun doom--font-name (fontname frame)
(defun doom--font-name (fontname)
(when (query-fontset fontname)
(when-let (ascii (assq 'ascii (aref (fontset-info fontname frame) 2)))
(when-let (ascii (assq 'ascii (aref (fontset-info fontname) 2)))
(setq fontname (nth 2 ascii))))
(or (x-decompose-font-name fontname)
(error "Cannot decompose font name")))
(defun doom--frame-list (&optional frame)
"Return a list consisting of FRAME and all of FRAME's child frames."
(let ((frame (or frame (selected-frame))))
(cons (selected-frame)
(cl-loop for fr in (frame-list)
if (eq (frame-parameter fr 'parent-frame) frame)
collect fr))))
(defvar doom--font-scale nil)
;;;###autoload
(defun doom-adjust-font-size (increment &optional frame)
(defun doom-adjust-font-size (increment)
"Increase size of font in FRAME by INCREMENT.
FRAME parameter defaults to current frame."
(let* ((frame (or frame (selected-frame)))
(font (frame-parameter frame 'font))
(font (doom--font-name font frame)))
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
increment)))
(unless (> new-size 0)
(error "Font is too small at %d" new-size))
(aset font xlfd-regexp-pixelsize-subnum (number-to-string new-size)))
;; Set point size & width to "*", so frame width will adjust to new font size
(aset font xlfd-regexp-pointsize-subnum "*")
(aset font xlfd-regexp-avgwidth-subnum "*")
(setq font (x-compose-font-name font))
(unless (x-list-fonts font)
(error "Cannot change font size"))
(set-frame-parameter frame 'font font)))
(if (null increment)
(progn
(set-frame-font doom-font 'keep-size t)
(setf (alist-get 'font default-frame-alist)
(cond ((stringp doom-font) doom-font)
((fontp doom-font) (font-xlfd-name doom-font))
((signal 'wrong-type-argument (list '(fontp stringp)
doom-font)))))
t)
(let* ((font (frame-parameter nil 'font))
(font (doom--font-name font))
(increment (* increment doom-font-increment))
(zoom-factor (or doom--font-scale 0)))
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
increment)))
(unless (> new-size 0)
(error "Font is too small at %d" new-size))
(aset font xlfd-regexp-pixelsize-subnum (number-to-string new-size)))
;; Set point size & width to "*", so frame width will adjust to new font size
(aset font xlfd-regexp-pointsize-subnum "*")
(aset font xlfd-regexp-avgwidth-subnum "*")
(setq font (x-compose-font-name font))
(unless (x-list-fonts font)
(error "Cannot change font size"))
(set-frame-font font 'keep-size t)
(setf (alist-get 'font default-frame-alist) font)
(setq doom--font-scale (+ zoom-factor increment))
;; Unlike `set-frame-font', `set-frame-parameter' won't trigger this
(run-hooks 'after-setting-font-hook))))
;;
@ -76,20 +78,15 @@ See `doom-init-fonts-h'."
;;;###autoload
(defun doom/increase-font-size (count)
"Enlargens the font size across the current frame."
"Enlargens the font size across the current and child frames."
(interactive "p")
(let ((zoom-factor (or (frame-parameter nil 'font-scale) 0))
(increment (* count doom-font-increment)))
(setq zoom-factor (+ zoom-factor increment))
(doom-adjust-font-size increment)
(set-frame-parameter nil 'font-scale zoom-factor)
(run-hooks 'doom-change-font-size-hook)))
(doom-adjust-font-size count))
;;;###autoload
(defun doom/decrease-font-size (count)
"Shrinks the font size across the current frame."
"Shrinks the font size across the current and child frames."
(interactive "p")
(doom/increase-font-size (- count)))
(doom-adjust-font-size (- count)))
;;;###autoload
(defun doom/reset-font-size ()
@ -103,13 +100,10 @@ Assuming it has been adjusted via `doom/increase-font-size' and
(/= text-scale-mode-amount 0))
(text-scale-set 0)
(setq success t))
(when-let (factor (frame-parameter nil 'font-scale))
(set-frame-font doom-font t)
(set-frame-parameter nil 'font-scale nil)
(when (doom-adjust-font-size nil)
(setq success t))
(unless success
(user-error "The font hasn't been resized"))
(run-hooks 'doom-change-font-size-hook)))
(user-error "The font hasn't been resized"))))
;;;###autoload
(define-minor-mode doom-big-font-mode
@ -123,12 +117,16 @@ This uses `doom/increase-font-size' under the hood, and enlargens the font by
:global t
(unless doom-font
(user-error "`doom-font' must be set to a valid font"))
(let ((frame (selected-frame)))
(if doom-big-font
(progn
(set-frame-font (if doom-big-font-mode doom-big-font doom-font)
t (doom--frame-list frame))
(run-hooks 'doom-change-font-size-hook))
(set-frame-font doom-font t (doom--frame-list frame))
(when doom-big-font-mode
(doom-adjust-font-size doom-big-font-increment frame)))))
(if doom-big-font
(let ((font (if doom-big-font-mode doom-big-font doom-font)))
(set-frame-font font 'keep-size t)
(setf (alist-get 'font default-frame-alist)
(cond ((stringp doom-font) font)
((fontp font) (font-xlfd-name font))
((signal 'wrong-type-argument (list '(fontp stringp)
font))))))
(doom-adjust-font-size
(and doom-big-font-mode
(integerp doom-big-font-increment)
(/= doom-big-font-increment 0)
doom-big-font-increment))))

View file

@ -106,9 +106,8 @@ Accepts 'ansi and 'text-properties. nil means don't render colors.")
;;;###autoload
(defun doom--format-print (output)
(unless (string-empty-p output)
(if (not noninteractive)
(message "%s" output)
(princ output)
(princ output)
(when (or noninteractive (not (eq standard-output t)))
(terpri)) ; newline
t))
@ -213,8 +212,9 @@ into faces or ANSI codes depending on the type of sesssion we're in."
;;;###autoload
(defmacro print! (message &rest args)
"Uses `message' in interactive sessions and `princ' otherwise (prints to
standard out).
"Prints MESSAGE, formatted with ARGS, to stdout.
Returns non-nil if the message is a non-empty string.
Can be colored using (color ...) blocks:

View file

@ -13,6 +13,7 @@
(lisp-mode :lang common-lisp)
(csharp-mode :lang csharp)
(clojure-mode :lang clojure)
(clojurescript-mode :lang clojure)
(graphql-mode :lang data)
(toml-mode :lang data)
(json-mode :lang data)
@ -95,7 +96,7 @@ the current major-modea.")
"Get information on an active minor mode. Use `describe-minor-mode' for a
selection of all minor-modes, active or not."
(interactive
(list (completing-read "Minor mode: " (doom-active-minor-modes))))
(list (completing-read "Describe active mode: " (doom-active-minor-modes))))
(let ((symbol
(cond ((stringp mode) (intern mode))
((symbolp mode) mode)
@ -104,21 +105,6 @@ selection of all minor-modes, active or not."
(helpful-function symbol)
(helpful-variable symbol))))
;;;###autoload
(defun doom/describe-symbol (symbol)
"Show help for SYMBOL, a variable, function or macro."
(interactive
(list (helpful--read-symbol "Symbol: " #'helpful--bound-p)))
(let* ((sym (intern-soft symbol))
(bound (boundp sym))
(fbound (fboundp sym)))
(cond ((and sym bound (not fbound))
(helpful-variable sym))
((and sym fbound (not bound))
(helpful-callable sym))
((apropos (format "^%s\$" symbol)))
((apropos (format "%s" symbol))))))
;;
;;; Documentation commands
@ -132,30 +118,30 @@ selection of all minor-modes, active or not."
(depth (if (integerp depth) depth)))
(message "Loading search results...")
(unwind-protect
(delq nil
(org-map-entries
(lambda ()
(cl-destructuring-bind (level _reduced-level _todo _priority text tags)
(org-heading-components)
(let ((path (org-get-outline-path)))
(when (and (or (null depth)
(<= level depth))
(or (null tags)
(not (string-match-p ":TOC" tags))))
(propertize
(mapconcat
'identity
(list (mapconcat #'identity
(append (when include-files
(list (or (+org-get-global-property "TITLE")
(file-relative-name buffer-file-name))))
path
(list (replace-regexp-in-string org-link-any-re "\\4" text)))
" > ")
(delq
nil
(org-map-entries
(lambda ()
(cl-destructuring-bind (level _reduced-level _todo _priority text tags)
(org-heading-components)
(when (and (or (null depth)
(<= level depth))
(or (null tags)
(not (string-match-p ":TOC" tags))))
(let ((path (org-get-outline-path)))
(list (string-join
(list (string-join
(append (when include-files
(list (or (+org-get-global-property "TITLE")
(file-relative-name (buffer-file-name)))))
path
(list (replace-regexp-in-string org-link-any-re "\\4" text)))
" > ")
tags)
" ")
'location (cons buffer-file-name (point)))))))
t 'agenda))
(buffer-file-name)
(point))))))
t 'agenda))
(mapc #'kill-buffer org-agenda-new-buffers)
(setq org-agenda-new-buffers nil))))
@ -163,17 +149,23 @@ selection of all minor-modes, active or not."
;;;###autoload
(defun doom-completing-read-org-headings (prompt files &optional depth include-files initial-input extra-candidates)
"TODO"
(let (ivy-sort-functions-alist)
(if-let* ((result (completing-read
prompt
(append (doom--org-headings files depth include-files)
extra-candidates)
nil nil initial-input)))
(cl-destructuring-bind (file . location)
(get-text-property 0 'location result)
(let ((alist
(append (doom--org-headings files depth include-files)
extra-candidates))
ivy-sort-functions-alist)
(if-let (result (completing-read prompt alist nil nil initial-input))
(cl-destructuring-bind (file &optional location)
(cdr (assoc result alist))
(find-file file)
(when location
(goto-char location)))
(cond ((functionp location)
(funcall location))
(location
(goto-char location)))
(ignore-errors
(when (outline-invisible-p)
(save-excursion
(outline-previous-visible-heading 1)
(org-show-subtree)))))
(user-error "Aborted"))))
;;;###autoload
@ -189,7 +181,7 @@ selection of all minor-modes, active or not."
(find-file (expand-file-name "index.org" doom-docs-dir)))
;;;###autoload
(defun doom/help-search (&optional initial-input)
(defun doom/help-search-headings (&optional initial-input)
"Search Doom's documentation and jump to a headline."
(interactive)
(doom-completing-read-org-headings
@ -201,11 +193,29 @@ selection of all minor-modes, active or not."
"faq.org")
2 t initial-input
(mapcar (lambda (x)
(propertize (concat "Doom Modules > " x)
'location
(get-text-property (1- (length x)) 'location x)))
(setcar x (concat "Doom Modules > " (car x)))
x)
(doom--help-modules-list))))
;;;###autoload
(defun doom/help-search (&optional initial-input)
"Preform a text search on all of Doom's documentation."
(interactive)
(funcall (cond ((fboundp '+ivy-file-search)
#'+ivy-file-search)
((fboundp '+helm-file-search)
#'+helm-file-search)
((rgrep
(read-regexp
"Search for" (or initial-input 'grep-tag-default)
'grep-regexp-history)
"*.org" doom-emacs-dir)
#'ignore))
:query initial-input
:args '("-g" "*.org")
:in doom-emacs-dir
:prompt "Search documentation for: "))
;;;###autoload
(defun doom/help-news-search (&optional initial-input)
"Search headlines in Doom's newsletters."
@ -298,30 +308,19 @@ without needing to check if they are available."
(describe-function fn))))
(defun doom--help-modules-list ()
(cl-loop for path in (doom-module-load-path 'all)
(cl-loop for path in (cdr (doom-module-load-path 'all))
for (cat . mod) = (doom-module-from-path path)
for location = (cons (or (doom-module-locate-path cat mod "README.org")
(doom-module-locate-path cat mod))
nil)
for format = (propertize (format "%s %s" cat mod)
'location location)
for readme-path = (or (doom-module-locate-path cat mod "README.org")
(doom-module-locate-path cat mod))
for format = (format "%s %s" cat mod)
if (doom-module-p cat mod)
collect format
collect (list format readme-path)
else if (and cat mod)
collect
(propertize
format
'face 'font-lock-comment-face
'location location)))
collect (list (propertize format 'face 'font-lock-comment-face)
readme-path)))
(defun doom--help-current-module-str ()
(cond ((and buffer-file-name
(eq major-mode 'emacs-lisp-mode)
(file-in-directory-p buffer-file-name doom-private-dir)
(save-excursion (goto-char (point-min))
(re-search-forward "^\\s-*(doom! " nil t))
(thing-at-point 'sexp t)))
((save-excursion
(cond ((save-excursion
(require 'smartparens)
(ignore-errors
(sp-beginning-of-sexp)
@ -330,45 +329,54 @@ without needing to check if they are available."
(let ((sexp (sexp-at-point)))
(when (memq (car-safe sexp) '(featurep! require!))
(format "%s %s" (nth 1 sexp) (nth 2 sexp)))))))
((and buffer-file-name
(when-let (mod (doom-module-from-path buffer-file-name))
(format "%s %s" (car mod) (cdr mod)))))
((when buffer-file-name
(when-let (mod (doom-module-from-path buffer-file-name))
(unless (memq (car mod) '(:core :private))
(format "%s %s" (car mod) (cdr mod))))))
((when-let (mod (cdr (assq major-mode doom--help-major-mode-module-alist)))
(format "%s %s"
(symbol-name (car mod))
(symbol-name (cadr mod)))))))
;;;###autoload
(defun doom/help-modules (category module)
(defun doom/help-modules (category module &optional visit-dir)
"Open the documentation for a Doom module.
CATEGORY is a keyword and MODULE is a symbol. e.g. :editor and 'evil.
If VISIT-DIR is non-nil, visit the module's directory rather than its
documentation.
Automatically selects a) the module at point (in private init files), b) the
module derived from a `featurep!' or `require!' call, c) the module that the
current file is in, or d) the module associated with the current major mode (see
`doom--help-major-mode-module-alist')."
(interactive
(let* ((module-string
(completing-read "Describe module: "
(doom--help-modules-list)
nil t nil nil
(doom--help-current-module-str)))
(key (doom-module-from-path
(car (get-text-property 0 'location module-string)))))
(list (car key)
(cdr key))))
(mapcar #'intern
(split-string
(completing-read "Describe module: "
(doom--help-modules-list)
nil t nil nil
(doom--help-current-module-str))
" " t)))
(cl-check-type category symbol)
(cl-check-type module symbol)
(let ((path (doom-module-locate-path category module)))
(cl-destructuring-bind (module-string path)
(or (assoc (format "%s %s" category module) (doom--help-modules-list))
(user-error "'%s %s' is not a valid module" category module))
(setq module-string (substring-no-properties module-string))
(unless (file-readable-p path)
(error "'%s %s' isn't a valid module; it doesn't exist" category module))
(if-let* ((readme-path (doom-module-locate-path category module "README.org")))
(find-file readme-path)
(if (y-or-n-p (format "The '%s %s' module has no README file. Explore its directory?"
category module))
(doom-project-browse path)
(user-error "Aborted module lookup")))))
(error "Can't find or read %S module at %S" module-string path))
(cond ((not (file-directory-p path))
(if visit-dir
(doom-project-browse (file-name-directory path))
(find-file path)))
(visit-dir
(doom-project-browse path))
((y-or-n-p (format "The %S module has no README file. Explore its directory?"
module-string))
(doom-project-browse (file-name-directory path)))
((user-error "Aborted module lookup")))))
;;
@ -431,9 +439,9 @@ If prefix arg is present, refresh the cache."
(list
(intern
(completing-read (if guess
(format "Select package to search for (default %s): "
(format "Select Doom package to search for (default %s): "
guess)
"Describe package: ")
"Describe Doom package: ")
packages nil t nil nil
(if guess (symbol-name guess))))))))
(require 'core-packages)
@ -511,7 +519,7 @@ If prefix arg is present, refresh the cache."
(insert "\n\n")))))
(defvar doom--package-cache nil)
(defun doom--package-list ()
(defun doom--package-list (&optional prompt)
(let* ((guess (or (function-called-at-point)
(symbol-at-point))))
(require 'finder-inf nil t)
@ -527,10 +535,11 @@ If prefix arg is present, refresh the cache."
(setq doom--package-cache packages)
(unless (memq guess packages)
(setq guess nil))
(intern (completing-read (if guess
(format "Select package to search for (default %s): "
guess)
"Describe package: ")
(intern (completing-read (or prompt
(if guess
(format "Select package to search for (default %s): "
guess)
"Describe package: "))
packages nil t nil nil
(if guess (symbol-name guess)))))))
@ -577,7 +586,7 @@ If prefix arg is present, refresh the cache."
This only searches `doom-emacs-dir' (typically ~/.emacs.d) and does not include
config blocks in your private config."
(interactive (list (doom--package-list)))
(interactive (list (doom--package-list "Find package config: ")))
(cl-destructuring-bind (file line _match)
(split-string
(completing-read
@ -591,55 +600,49 @@ config blocks in your private config."
(recenter)))
;;;###autoload
(defun doom/help-package-homepage (package)
"Open PACKAGE's repo or homepage in your browser."
(interactive (list (doom--package-list)))
(browse-url (doom--package-url package)))
(defalias 'doom/help-package-homepage #'straight-visit-package-website)
(defun doom--help-search-prompt (prompt)
(let ((query (doom-thing-at-point-or-region)))
(if (featurep 'counsel)
query
(read-string prompt query 'git-grep query))))
(defvar counsel-rg-base-command)
(defun doom--help-search (dirs query prompt)
;; REVIEW Replace with deadgrep
(unless (executable-find "rg")
(user-error "Can't find ripgrep on your system"))
(if (fboundp 'counsel-rg)
(let ((counsel-rg-base-command
(concat counsel-rg-base-command " "
(mapconcat #'shell-quote-argument dirs " "))))
(counsel-rg query nil "-Lz" prompt))
;; TODO Add helm support?
(grep-find
(string-join
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never"
(shell-quote-argument query))
(mapcar #'shell-quote-argument dirs))
" "))))
;;;###autoload
(defun doom/help-search-load-path (query)
"Perform a text search on your `load-path'.
Uses the symbol at point or the current selection, if available."
(interactive
(let ((query
;; TODO Generalize this later; into something the lookup module and
;; project search commands could as well
(if (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(or (symbol-name (symbol-at-point)) ""))))
(list (read-string
(format "Search load-path (default: %s): " query)
nil 'git-grep query))))
;; REVIEW Replace with deadgrep
(grep-find
(mapconcat
#'shell-quote-argument
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never" query)
(cl-remove-if-not #'file-directory-p load-path))
" ")))
(list (doom--help-search-prompt "Search load-path: ")))
(doom--help-search (cl-remove-if-not #'file-directory-p load-path)
query "Search load-path: "))
;; TODO factor our the duplicate code between this and the above
;;;###autoload
(defun doom/help-search-loaded-files (query)
"Perform a text search on your `load-path'.
Uses the symbol at point or the current selection, if available."
(interactive
(let ((query
;; TODO Generalize this later; into something the lookup module and
;; project search commands could as well.
(if (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))
(or (symbol-name (symbol-at-point)) ""))))
(list (read-string
(format "Search load-path (default: %s): " query)
nil 'git-grep query))))
(unless (executable-find "rg")
(user-error "Can't find ripgrep on your system"))
(require 'elisp-refs)
;; REVIEW Replace with deadgrep
(grep-find
(mapconcat
#'shell-quote-argument
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never" query)
(cl-remove-if-not #'file-directory-p (elisp-refs--loaded-paths)))
" ")))
(list (doom--help-search-prompt "Search loaded files: ")))
(let ((paths (cl-loop for (file . _) in load-history
for filebase = (file-name-sans-extension file)
if (file-exists-p! (format "%s.el" filebase))
collect it)))
(doom--help-search paths query "Search loaded files: ")))

View file

@ -13,6 +13,13 @@
nil-value)
plist)))
;;;###autoload
(defun doom-package-set (package prop value)
"Set PROPERTY in PACKAGE's recipe to VALUE."
(setf (alist-get package doom-packages)
(plist-put (alist-get package doom-packages)
prop value)))
;;;###autoload
(defun doom-package-recipe (package &optional prop nil-value)
"Returns the `straight' recipe PACKAGE was registered with."
@ -23,6 +30,14 @@
nil-value)
plist)))
;;;###autoload
(defun doom-package-recipe-repo (package)
"Resolve and return PACKAGE's (symbol) local-repo property."
(if-let* ((recipe (cdr (straight-recipes-retrieve package)))
(repo (straight-vc-local-repo-name recipe)))
repo
(symbol-name package)))
;;;###autoload
(defun doom-package-build-recipe (package &optional prop nil-value)
"Returns the `straight' recipe PACKAGE was installed with."
@ -39,7 +54,7 @@
(car (gethash (symbol-name package) straight--build-cache)))
;;;###autoload
(defun doom-package-dependencies (package &optional recursive noerror)
(defun doom-package-dependencies (package &optional recursive _noerror)
"Return a list of dependencies for a package."
(let ((deps (nth 1 (gethash (symbol-name package) straight--build-cache))))
(if recursive
@ -47,6 +62,7 @@
deps))
deps)))
;;;###autoload
(defun doom-package-depending-on (package &optional noerror)
"Return a list of packages that depend on the package named NAME."
(cl-check-type name symbol)
@ -155,6 +171,7 @@ was installed with."
((debug error)
(signal 'doom-package-error
(list (doom-module-from-path file)
file
e))))))
;;;###autoload
@ -167,8 +184,7 @@ If ALL-P, gather packages unconditionally across all modules, including disabled
ones."
(let ((doom-interactive-mode t)
(doom-modules (doom-modules))
doom-packages
doom-disabled-packages)
doom-packages)
(doom--read-module-packages-file
(doom-path doom-core-dir "packages.el") all-p t)
(let ((private-packages (doom-path doom-private-dir "packages.el")))
@ -189,6 +205,67 @@ ones."
(doom--read-module-packages-file private-packages all-p t))
(nreverse doom-packages)))
;;;###autoload
(defun doom-package-pinned-list ()
"Return an alist mapping package names (strings) to pinned commits (strings)."
(let (alist)
(dolist (package doom-packages alist)
(cl-destructuring-bind (name &key disable ignore pin unpin &allow-other-keys)
package
(when (and (not ignore)
(not disable)
(or pin unpin))
(setf (alist-get (doom-package-recipe-repo name) alist
nil 'remove #'equal)
(unless unpin pin)))))))
;;;###autoload
(defun doom-package-unpinned-list ()
"Return an alist mapping package names (strings) to pinned commits (strings)."
(let (alist)
(dolist (package doom-packages alist)
(cl-destructuring-bind
(_ &key recipe disable ignore pin unpin &allow-other-keys)
package
(when (and (not ignore)
(not disable)
(or unpin
(and (plist-member recipe :pin)
(null pin))))
(cl-pushnew (doom-package-recipe-repo (car package)) alist
:test #'equal))))))
;;;###autoload
(defun doom-package-recipe-list ()
"Return straight recipes for non-builtin packages with a local-repo."
(let (recipes)
(dolist (recipe (hash-table-values straight--recipe-cache))
(cl-destructuring-bind (&key local-repo type no-build &allow-other-keys)
recipe
(unless (or (null local-repo)
(eq type 'built-in)
no-build)
(push recipe recipes))))
(nreverse recipes)))
;;;###autoload
(defmacro doom-with-package-recipes (recipes binds &rest body)
"TODO"
(declare (indent 2))
(let ((recipe-var (make-symbol "recipe"))
(recipes-var (make-symbol "recipes")))
`(let* ((,recipes-var ,recipes)
(built ())
(straight-use-package-pre-build-functions
(cons (lambda (pkg) (cl-pushnew pkg built :test #'equal))
straight-use-package-pre-build-functions)))
(dolist (,recipe-var ,recipes-var)
(cl-block nil
(straight--with-plist (append (list :recipe ,recipe-var) ,recipe-var)
,(doom-enlist binds)
,@body)))
(nreverse built))))
;;
;;; Main functions
@ -201,3 +278,48 @@ ones."
(message "Reloading packages")
(doom-initialize-packages t)
(message "Reloading packages...DONE"))
;;;###autoload
(defun doom/update-pinned-package-form (&optional select)
"Inserts or updates a `:pin' for the `package!' statement at point.
Grabs the latest commit id of the package using 'git'."
(interactive "P")
;; REVIEW Better error handling
;; TODO Insert a new `package!' if no `package!' at poin
(require 'straight)
(ignore-errors
(while (and (atom (sexp-at-point))
(not (bolp)))
(forward-sexp -1)))
(save-excursion
(if (not (eq (sexp-at-point) 'package!))
(user-error "Not on a `package!' call")
(backward-char)
(let* ((recipe (cdr (sexp-at-point)))
(package (car recipe))
(oldid (doom-package-get package :pin))
(id
(cdr (doom-call-process
"git" "ls-remote"
(straight-vc-git--destructure
(doom-plist-merge
(plist-get (cdr recipe) :recipe)
(or (cdr (straight-recipes-retrieve package))
(plist-get (cdr (assq package doom-packages)) :recipe)))
(upstream-repo upstream-host)
(straight-vc-git--encode-url upstream-repo upstream-host))))))
(unless id
(user-error "No id for %S package" package))
(let* ((id (if select
(car (split-string (completing-read "Commit: " (split-string id "\n" t))))
(car (split-string id))))
(id (substring id 0 10)))
(if (and oldid (string-match-p (concat "^" oldid) id))
(user-error "No update necessary")
(if (re-search-forward ":pin +\"\\([^\"]+\\)\"" (cdr (bounds-of-thing-at-point 'sexp)) t)
(replace-match id t t nil 1)
(thing-at-point--end-of-sexp)
(backward-char)
(insert " :pin " (prin1-to-string id)))
(message "Updated %S: %s -> %s" package oldid id)))))))

View file

@ -66,7 +66,7 @@ BODY."
;;;###autoload
(defun doom-plist-merge (from-plist to-plist)
"Destructively merge FROM-PLIST onto TO-PLIST"
"Non-destructively merge FROM-PLIST onto TO-PLIST"
(let ((plist (copy-sequence from-plist)))
(while plist
(plist-put! to-plist (pop plist) (pop plist)))
@ -83,11 +83,11 @@ BODY."
p))
;;;###autoload
(defun doom-plist-delete (plist prop)
"Delete PROP from a copy of PLIST."
(defun doom-plist-delete (plist &rest props)
"Delete PROPS from a copy of PLIST."
(let (p)
(while plist
(if (not (eq prop (car plist)))
(if (not (memq (car plist) props))
(plist-put! p (car plist) (nth 1 plist)))
(setq plist (cddr plist)))
p))

View file

@ -1,6 +1,8 @@
;;; core/autoload/projects.el -*- lexical-binding: t; -*-
(defvar projectile-project-root nil)
(defvar projectile-enable-caching)
(defvar projectile-require-project-root)
;;;###autoload (autoload 'projectile-relevant-known-projects "projectile")

View file

@ -96,9 +96,10 @@ following:
;;
;;; Commands
(defvar projectile-enable-caching)
;;;###autoload
(defun doom/open-scratch-buffer (&optional arg project-p)
"Opens the (persistent) scratch buffer in a popup.
"Pop up a persistent scratch buffer.
If passed the prefix ARG, switch to it in the current window.
If PROJECT-P is non-nil, open a persistent scratch buffer associated with the

View file

@ -47,10 +47,16 @@
"TODO"
(setq file (expand-file-name (or file (doom-session-file))))
(message "Attempting to load %s" file)
(cond ((require 'persp-mode nil t)
(cond ((not (file-readable-p file))
(message "No session file at %S to read from" file))
((require 'persp-mode nil t)
(unless persp-mode
(persp-mode +1))
(persp-load-state-from-file file))
(let ((allowed (persp-list-persp-names-in-file file)))
(cl-loop for name being the hash-keys of *persp-hash*
unless (member name allowed)
do (persp-kill name))
(persp-load-state-from-file file)))
((and (require 'frameset nil t)
(require 'restart-emacs nil t))
(restart-emacs--restore-frames-using-desktop file))
@ -125,4 +131,7 @@
(setq doom-autosave-session nil)
(doom/quicksave-session)
(restart-emacs
(delq nil (list (if debug "--debug-init") "--restore"))))
(append (if debug (list "--debug-init"))
(when (boundp 'chemacs-current-emacs-profile)
(list "--with-profile" chemacs-current-emacs-profile))
(list "--restore"))))

View file

@ -1,5 +1,17 @@
;;; core/autoload/text.el -*- lexical-binding: t; -*-
(defvar doom-point-in-comment-functions ()
"List of functions to run to determine if point is in a comment.
Each function takes one argument: the position of the point. Stops on the first
function to return non-nil. Used by `doom-point-in-comment-p'.")
(defvar doom-point-in-string-functions ()
"List of functions to run to determine if point is in a string.
Each function takes one argument: the position of the point. Stops on the first
function to return non-nil. Used by `doom-point-in-string-p'.")
;;;###autoload
(defun doom-surrounded-p (pair &optional inline balanced)
"Returns t if point is surrounded by a brace delimiter: {[(
@ -28,31 +40,18 @@ lines, above and below, with only whitespace in between."
;;;###autoload
(defun doom-point-in-comment-p (&optional pos)
"Return non-nil if POS is in a comment.
POS defaults to the current position."
;; REVIEW Should we cache `syntax-ppss'?
(let* ((pos (or pos (point)))
(ppss (syntax-ppss pos)))
(or (nth 4 ppss)
(nth 8 ppss)
(and (< pos (point-max))
(memq (char-syntax (char-after pos)) '(?< ?>))
(not (eq (char-after pos) ?\n)))
(when-let (s (car (syntax-after pos)))
(or (and (/= 0 (logand (lsh 1 16) s))
(nth 4 (doom-syntax-ppss (+ pos 2))))
(and (/= 0 (logand (lsh 1 17) s))
(nth 4 (doom-syntax-ppss (+ pos 1))))
(and (/= 0 (logand (lsh 1 18) s))
(nth 4 (doom-syntax-ppss (- pos 1))))
(and (/= 0 (logand (lsh 1 19) s))
(nth 4 (doom-syntax-ppss (- pos 2)))))))))
(let ((pos (or pos (point))))
(or (run-hook-with-args-until-success 'doom-point-in-comment-functions pos)
(sp-point-in-comment pos))))
;;;###autoload
(defun doom-point-in-string-p (&optional pos)
"Return non-nil if POS is in a string."
;; REVIEW Should we cache `syntax-ppss'?
(nth 3 (syntax-ppss pos)))
(let ((pos (or pos (point))))
(or (run-hook-with-args-until-success 'doom-point-in-string-functions pos)
(sp-point-in-string pos))))
;;;###autoload
(defun doom-point-in-string-or-comment-p (&optional pos)
@ -60,74 +59,157 @@ POS defaults to the current position."
(or (doom-point-in-string-p pos)
(doom-point-in-comment-p pos)))
;;;###autoload
(defun doom-region-active-p ()
"Return non-nil if selection is active.
Detects evil visual mode as well."
(declare (side-effect-free t))
(or (use-region-p)
(and (bound-and-true-p evil-local-mode)
(evil-visual-state-p))))
;;;###autoload
(defun doom-region-beginning ()
"Return beginning position of selection.
Uses `evil-visual-beginning' if available."
(declare (side-effect-free t))
(if (bound-and-true-p evil-local-mode)
evil-visual-beginning
(region-beginning)))
;;;###autoload
(defun doom-region-end ()
"Return end position of selection.
Uses `evil-visual-end' if available."
(declare (side-effect-free t))
(if (bound-and-true-p evil-local-mode)
evil-visual-end
(region-end)))
;;;###autoload
(defun doom-thing-at-point-or-region (&optional thing prompt)
"Grab the current selection, THING at point, or xref identifier at point.
Returns THING if it is a string. Otherwise, if nothing is found at point and
PROMPT is non-nil, prompt for a string (if PROMPT is a string it'll be used as
the prompting string). Returns nil if all else fails.
NOTE: Don't use THING for grabbing symbol-at-point. The xref fallback is smarter
in some cases."
(declare (side-effect-free t))
(cond ((stringp thing)
thing)
((doom-region-active-p)
(buffer-substring-no-properties
(doom-region-beginning)
(doom-region-end)))
(thing
(thing-at-point thing t))
((require 'xref nil t)
;; A little smarter than using `symbol-at-point', though in most cases,
;; xref ends up using `symbol-at-point' anyway.
(xref-backend-identifier-at-point (xref-find-backend)))
(prompt
(read-string (if (stringp prompt) prompt "")))))
;;
;;; Commands
(defvar doom--last-backward-pt most-positive-fixnum)
(defun doom--bol-bot-eot-eol (&optional pos)
(save-excursion
(when pos
(goto-char pos))
(let* ((bol (if visual-line-mode
(save-excursion
(beginning-of-visual-line)
(point))
(line-beginning-position)))
(bot (save-excursion
(goto-char bol)
(skip-chars-forward " \t\r")
(point)))
(eol (if visual-line-mode
(save-excursion (end-of-visual-line) (point))
(line-end-position)))
(eot (or (save-excursion
(if (not comment-use-syntax)
(progn
(goto-char bol)
(when (re-search-forward comment-start-skip eol t)
(or (match-end 1) (match-beginning 0))))
(goto-char eol)
(while (and (doom-point-in-comment-p)
(> (point) bol))
(backward-char))
(skip-chars-backward " " bol)
(unless (or (eq (char-after) 32) (eolp))
(forward-char))
(point)))
eol)))
(list bol bot eot eol))))
(defvar doom--last-backward-pt nil)
;;;###autoload
(defun doom/backward-to-bol-or-indent ()
(defun doom/backward-to-bol-or-indent (&optional point)
"Jump between the indentation column (first non-whitespace character) and the
beginning of the line. The opposite of
`doom/forward-to-last-non-comment-or-eol'."
(interactive)
(let ((pt (point)))
(cl-destructuring-bind (bol . bot)
(save-excursion
(beginning-of-visual-line)
(cons (point)
(progn (skip-chars-forward " \t\r")
(point))))
(interactive "d")
(let ((pt (or point (point))))
(cl-destructuring-bind (bol bot _eot _eol)
(doom--bol-bot-eot-eol pt)
(cond ((> pt bot)
(goto-char bot))
((= pt bol)
(goto-char (min doom--last-backward-pt bot))
(setq doom--last-backward-pt most-positive-fixnum))
(or (and doom--last-backward-pt
(= (line-number-at-pos doom--last-backward-pt)
(line-number-at-pos pt)))
(setq doom--last-backward-pt nil))
(goto-char (or doom--last-backward-pt bot))
(setq doom--last-backward-pt nil))
((<= pt bot)
(setq doom--last-backward-pt pt)
(goto-char bol))))))
(defvar doom--last-forward-pt -1)
(defvar doom--last-forward-pt nil)
;;;###autoload
(defun doom/forward-to-last-non-comment-or-eol ()
(defun doom/forward-to-last-non-comment-or-eol (&optional point)
"Jumps between the last non-blank, non-comment character in the line and the
true end of the line. The opposite of `doom/backward-to-bol-or-indent'."
(interactive "d")
(let ((pt (or point (point))))
(cl-destructuring-bind (_bol _bot eot eol)
(doom--bol-bot-eot-eol pt)
(cond ((< pt eot)
(goto-char eot))
((= pt eol)
(goto-char (or doom--last-forward-pt eot))
(setq doom--last-forward-pt nil))
((>= pt eot)
(setq doom--last-backward-pt pt)
(goto-char eol))))))
;;;###autoload
(defun doom/backward-kill-to-bol-and-indent ()
"Kill line to the first non-blank character. If invoked again afterwards, kill
line to beginning of line. Same as `evil-delete-back-to-indentation'."
(interactive)
(let ((eol (if (not visual-line-mode)
(line-end-position)
(save-excursion (end-of-visual-line) (point)))))
(if (or (and (< (point) eol)
(sp-point-in-comment))
(not (sp-point-in-comment eol)))
(if (= (point) eol)
(progn
(goto-char doom--last-forward-pt)
(setq doom--last-forward-pt -1))
(setq doom--last-forward-pt (point))
(goto-char eol))
(let* ((bol (save-excursion (beginning-of-visual-line) (point)))
(boc (or (save-excursion
(if (not comment-use-syntax)
(progn
(goto-char bol)
(when (re-search-forward comment-start-skip eol t)
(or (match-end 1) (match-beginning 0))))
(goto-char eol)
(while (and (sp-point-in-comment)
(> (point) bol))
(backward-char))
(skip-chars-backward " " bol)
(point)))
eol)))
(when (> doom--last-forward-pt boc)
(setq boc doom--last-forward-pt))
(if (or (= eol (point))
(> boc (point)))
(progn
(goto-char boc)
(setq doom--last-forward-pt -1))
(setq doom--last-forward-pt (point))
(goto-char eol))))))
(let ((empty-line-p (save-excursion (beginning-of-line)
(looking-at-p "[ \t]*$"))))
(funcall (if (fboundp 'evil-delete)
#'evil-delete
#'delete-region)
(point-at-bol) (point))
(unless empty-line-p
(indent-according-to-mode))))
;;;###autoload
(defun doom/delete-backward-word (arg)
"Like `backward-kill-word', but doesn't affect the kill-ring."
(interactive "p")
(let (kill-ring)
(backward-kill-word arg)))
;;;###autoload
(defun doom/dumb-indent ()
@ -155,20 +237,6 @@ true end of the line. The opposite of `doom/backward-to-bol-or-indent'."
tab-width
(- tab-width movement)))))))))
;;;###autoload
(defun doom/backward-kill-to-bol-and-indent ()
"Kill line to the first non-blank character. If invoked again
afterwards, kill line to beginning of line."
(interactive)
(let ((empty-line-p (save-excursion (beginning-of-line)
(looking-at-p "[ \t]*$"))))
(funcall (if (fboundp 'evil-delete)
#'evil-delete
#'delete-region)
(point-at-bol) (point))
(unless empty-line-p
(indent-according-to-mode))))
;;;###autoload
(defun doom/retab (arg &optional beg end)
"Converts tabs-to-spaces or spaces-to-tabs within BEG and END (defaults to

View file

@ -19,12 +19,13 @@ all themes. It will apply to all themes once they are loaded."
`(let ((fn (gensym "doom--customize-themes-h-")))
(fset
fn (lambda ()
(dolist (theme (doom-enlist (or ,theme 'user)))
(when (or (eq theme 'user)
(custom-theme-enabled-p theme))
(apply #'custom-theme-set-faces 'user
(mapcan #'doom--custom-theme-set-face
(list ,@specs)))))))
(let (custom--inhibit-theme-enable)
(dolist (theme (doom-enlist (or ,theme 'user)))
(when (or (eq theme 'user)
(custom-theme-enabled-p theme))
(apply #'custom-theme-set-faces theme
(mapcan #'doom--custom-theme-set-face
(list ,@specs))))))))
(when (or doom-init-theme-p (null doom-theme))
(funcall fn))
(add-hook 'doom-load-theme-hook fn 'append)))

View file

@ -1,7 +1,7 @@
;;; core/autoload/ui.el -*- lexical-binding: t; -*-
;;
;; Public library
;;; Public library
;;;###autoload
(defun doom-resize-window (window new-size &optional horizontal force-p)
@ -24,7 +24,7 @@ are open."
;;
;; Advice
;;; Advice
;;;###autoload
(defun doom-recenter-a (&rest _)
@ -43,7 +43,7 @@ In tty Emacs, messages suppressed completely."
;;
;; Hooks
;;; Hooks
;;;###autoload
(defun doom-apply-ansi-color-to-compilation-buffer-h ()
@ -57,9 +57,17 @@ In tty Emacs, messages suppressed completely."
"Turn off `show-paren-mode' buffer-locally."
(setq-local show-paren-mode nil))
;;;###autoload
(defun doom-enable-line-numbers-h ()
(display-line-numbers-mode +1))
;;;###autoload
(defun doom-disable-line-numbers-h ()
(display-line-numbers-mode -1))
;;
;; Commands
;;; Commands
;;;###autoload
(defun doom/toggle-line-numbers ()
@ -95,6 +103,7 @@ See `display-line-numbers' for what these values mean."
(delete-frame))
(save-buffers-kill-emacs)))
(defvar doom--maximize-last-wconf nil)
;;;###autoload
(defun doom/window-maximize-buffer ()
"Close other windows to focus on this one. Activate again to undo this. If the
@ -102,41 +111,40 @@ window changes before then, the undo expires.
Alternatively, use `doom/window-enlargen'."
(interactive)
(if (and (one-window-p)
(assq ?_ register-alist))
(jump-to-register ?_)
(when (and (bound-and-true-p +popup-mode)
(+popup-window-p))
(user-error "Cannot maximize a popup, use `+popup/raise' first or use `doom/window-enlargen' instead"))
(window-configuration-to-register ?_)
(delete-other-windows)))
(setq doom--maximize-last-wconf
(if (and (null (cdr (cl-remove-if #'window-dedicated-p (window-list))))
doom--maximize-last-wconf)
(ignore (set-window-configuration doom--maximize-last-wconf))
(when (and (bound-and-true-p +popup-mode)
(+popup-window-p))
(user-error "Cannot maximize a popup, use `+popup/raise' first or use `doom/window-enlargen' instead"))
(prog1 (current-window-configuration)
(delete-other-windows)))))
(defvar doom--window-enlargened nil)
(defvar doom--enlargen-last-wconf nil)
;;;###autoload
(defun doom/window-enlargen ()
"Enlargen the current window to focus on this one. Does not close other
windows (unlike `doom/window-maximize-buffer') Activate again to undo."
windows (unlike `doom/window-maximize-buffer'). Activate again to undo."
(interactive)
(setq doom--window-enlargened
(if (and doom--window-enlargened
(assq ?_ register-alist))
(ignore (ignore-errors (jump-to-register ?_)))
(window-configuration-to-register ?_)
(let* ((window (selected-window))
(dedicated-p (window-dedicated-p window))
(preserved-p (window-parameter window 'window-preserved-size))
(ignore-window-parameters t))
(unwind-protect
(progn
(when dedicated-p
(set-window-dedicated-p window nil))
(when preserved-p
(set-window-parameter window 'window-preserved-size nil))
(maximize-window window))
(set-window-dedicated-p window dedicated-p)
(when preserved-p
(set-window-parameter window 'window-preserved-size preserved-p)))
t))))
(setq doom--enlargen-last-wconf
(if doom--enlargen-last-wconf
(ignore (set-window-configuration doom--enlargen-last-wconf))
(prog1 (current-window-configuration)
(let* ((window (selected-window))
(dedicated-p (window-dedicated-p window))
(preserved-p (window-parameter window 'window-preserved-size))
(ignore-window-parameters t))
(unwind-protect
(progn
(when dedicated-p
(set-window-dedicated-p window nil))
(when preserved-p
(set-window-parameter window 'window-preserved-size nil))
(maximize-window window))
(set-window-dedicated-p window dedicated-p)
(when preserved-p
(set-window-parameter window 'window-preserved-size preserved-p))))))))
;;;###autoload
(defun doom/window-maximize-horizontally ()
@ -179,8 +187,7 @@ narrowing doesn't affect other windows displaying the same buffer. Call
Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(interactive
(list (or (bound-and-true-p evil-visual-beginning) (region-beginning))
(or (bound-and-true-p evil-visual-end) (region-end))
current-prefix-arg))
(or (bound-and-true-p evil-visual-end) (region-end))))
(unless (region-active-p)
(setq beg (line-beginning-position)
end (line-end-position)))

View file

@ -1,418 +1,244 @@
;;; core/cli/autoloads.el -*- lexical-binding: t; -*-
(defvar doom-autoload-excluded-packages '("gh")
"Packages that have silly or destructive autoload files that try to load
"What packages whose autoloads file we won't index.
These packages have silly or destructive autoload files that try to load
everyone in the universe and their dog, causing errors that make babies cry. No
one wants that.")
(defvar doom-autoload-cached-vars
'(load-path
auto-mode-alist
interpreter-mode-alist
Info-directory-list
doom-disabled-packages)
"A list of variables to be cached in `doom-package-autoload-file'.")
;; externs
(defvar autoload-timestamps)
(defvar generated-autoload-load-name)
(defvar generated-autoload-file)
(defun doom-cli-reload-autoloads ()
"Reloads `doom-autoload-file' and `doom-package-autoload-file' files."
(doom-cli-reload-core-autoloads)
(doom-cli-reload-package-autoloads))
;;
;;; Commands
(defun doom-cli-reload-core-autoloads (&optional file)
(print! (start "(Re)generating core autoloads..."))
(print-group!
(let ((file (or file doom-autoload-file))
doom-autoload-cached-vars)
(cl-check-type file string)
(and (print! (start "Generating core autoloads..."))
(doom-cli--write-autoloads
file (doom-cli--generate-autoloads
(cl-loop for dir
in (append (list doom-core-dir)
(cdr (doom-module-load-path 'all-p))
(list doom-private-dir))
if (doom-glob dir "autoload.el") collect it
if (doom-glob dir "autoload/*.el") append it)
'scan))
(print! (start "Byte-compiling core autoloads file..."))
(doom-cli--byte-compile-file file)
(print! (success "Generated %s")
(relpath (byte-compile-dest-file file)
doom-emacs-dir))))))
(defcli! (autoloads a) ()
"Regenerates Doom's autoloads files.
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
modules/*/*/autoload.el and modules/*/*/autoload/*.el, and generates and
byte-compiles `doom-autoload-file', as well as `doom-package-autoload-file'
(created from the concatenated autoloads files of all installed packages).
It also caches `load-path', `Info-directory-list', `doom-disabled-packages',
`package-activated-list' and `auto-mode-alist'."
(straight-check-all)
(doom-cli-reload-autoloads nil 'force))
(defun doom-cli-reload-package-autoloads (&optional file)
(print! (start "(Re)generating package autoloads..."))
(print-group!
(doom-initialize-packages)
(let ((file (or file doom-package-autoload-file)))
(cl-check-type file string)
(and (print! (start "Generating package autoloads..."))
(doom-cli--write-autoloads
file
(doom-cli--generate-var-cache doom-autoload-cached-vars)
(doom-cli--generate-autoloads
(mapcar #'straight--autoloads-file
(cl-set-difference (hash-table-keys straight--build-cache)
doom-autoload-excluded-packages
:test #'string=))))
(print! (start "Byte-compiling package autoloads file..."))
(doom-cli--byte-compile-file file)
(print! (success "Generated %s")
(relpath (byte-compile-dest-file file)
doom-emacs-dir))))))
;;
;;; Helpers
(defun doom--cli-delete-autoloads-file (file)
"Delete FILE (an autoloads file) and accompanying *.elc file, if any."
(cl-check-type file string)
(when (file-exists-p file)
(when-let (buf (find-buffer-visiting file))
(with-current-buffer buf
(set-buffer-modified-p nil))
(kill-buffer buf))
(delete-file file)
(ignore-errors (delete-file (byte-compile-dest-file file)))
t))
(defun doom-cli--write-autoloads (file &rest forms)
(make-directory (file-name-directory file) 'parents)
(condition-case-unless-debug e
(with-temp-file file
(let ((standard-output (current-buffer))
(print-quoted t)
(print-level nil)
(print-length nil))
(insert ";; -*- lexical-binding: t; -*-\n"
";; This file is autogenerated by Doom, DO NOT EDIT IT!!\n")
(dolist (form (delq nil forms))
(mapc #'print form))
t))
(error (delete-file file)
(signal 'doom-autoload-error (list file e)))))
(defun doom--cli-warn-refresh-session-h ()
(message "Restart or reload Doom Emacs for changes to take effect:\n")
(message " M-x doom/restart-and-restore")
(message " M-x doom/restart")
(message " M-x doom/reload"))
(defun doom--cli-byte-compile-file (file)
(let ((byte-compile-warnings (if doom-debug-mode byte-compile-warnings))
(byte-compile-dynamic t)
(byte-compile-dynamic-docstrings t))
(condition-case-unless-debug e
(defun doom-cli--byte-compile-file (file)
(condition-case-unless-debug e
(let ((byte-compile-warnings (if doom-debug-mode byte-compile-warnings))
(byte-compile-dynamic t)
(byte-compile-dynamic-docstrings t))
(when (byte-compile-file file)
(prog1 (load file 'noerror 'nomessage 'nosuffix)
(when noninteractive
(add-hook 'doom-cli-post-success-execute-hook #'doom--cli-warn-refresh-session-h))))
((debug error)
(let ((backup-file (concat file ".bk")))
(print! (warn "Copied backup to %s") (relpath backup-file))
(copy-file file backup-file 'overwrite))
(doom--cli-delete-autoloads-file file)
(signal 'doom-autoload-error (list file e))))))
(unless doom-interactive-mode
(add-hook 'doom-cli-post-success-execute-hook #'doom-cli--warn-refresh-session-h))
(load (byte-compile-dest-file file) nil t)))
(error
(delete-file (byte-compile-dest-file file))
(signal 'doom-autoload-error (list file e)))))
(defun doom-cli-reload-autoloads (&optional file force-p)
"Reloads FILE (an autoload file), if it needs reloading.
(defun doom-cli--warn-refresh-session-h ()
(print! "Restart or reload Doom Emacs for changes to take effect:")
(print-group! (print! "M-x doom/restart-and-restore")
(print! "M-x doom/restart")
(print! "M-x doom/reload")))
FILE should be one of `doom-autoload-file' or `doom-package-autoload-file'. If
it is nil, it will try to reload both. If FORCE-P (universal argument) do it
even if it doesn't need reloading!"
(or (null file)
(stringp file)
(signal 'wrong-type-argument (list 'stringp file)))
(if (stringp file)
(cond ((file-equal-p file doom-autoload-file)
(doom-cli-reload-core-autoloads force-p))
((file-equal-p file doom-package-autoload-file)
(doom-cli-reload-package-autoloads force-p))
((error "Invalid autoloads file: %s" file)))
(doom-cli-reload-core-autoloads force-p)
(doom-cli-reload-package-autoloads force-p)))
(defun doom-cli--generate-var-cache (vars)
`((setq ,@(cl-loop for var in vars
append `(,var ',(symbol-value var))))))
(defun doom-cli--filter-form (form &optional expand)
(let ((func (car-safe form)))
(cond ((memq func '(provide custom-autoload))
nil)
((and (eq func 'add-to-list)
(memq (doom-unquote (cadr form))
doom-autoload-cached-vars))
nil)
((not (eq func 'autoload))
form)
((and expand (not (file-name-absolute-p (nth 2 form))))
(defvar doom--autoloads-path-cache nil)
(setf (nth 2 form)
(let ((path (nth 2 form)))
(or (cdr (assoc path doom--autoloads-path-cache))
(when-let* ((libpath (locate-library path))
(libpath (file-name-sans-extension libpath))
(libpath (abbreviate-file-name libpath)))
(push (cons path libpath) doom--autoloads-path-cache)
libpath)
path)))
form)
(form))))
;;
;;; Doom autoloads
(defun doom--cli-generate-header (func)
(goto-char (point-min))
(insert ";; -*- lexical-binding:t; -*-\n"
";; This file is autogenerated by `" (symbol-name func) "', DO NOT EDIT !!\n\n"))
(defun doom--cli-generate-autoloads (targets)
(let ((n 0))
(dolist (file targets)
(insert
(with-temp-buffer
(cond ((not (doom-file-cookie-p file "if" t))
(print! (debug "Ignoring %s") (relpath file)))
((let ((generated-autoload-load-name (file-name-sans-extension file)))
(autoload-generate-file-autoloads file (current-buffer)))
(print! (debug "Nothing in %s") (relpath file)))
((cl-incf n)
(print! (debug "Scanning %s...") (relpath file))))
(buffer-string))))
(print! (class (if (> n 0) 'success 'info)
"Scanned %d file(s)")
n)))
(defun doom--cli-expand-autoload-paths (&optional allow-internal-paths)
(let ((load-path
;; NOTE With `doom-private-dir' in `load-path', Doom autoloads files
;; will be unable to declare autoloads for the built-in autoload.el
;; Emacs package, should $DOOMDIR/autoload.el exist. Not sure why
;; they'd want to though, so it's an acceptable compromise.
(append (list doom-private-dir)
doom-modules-dirs
(straight--directory-files (straight--build-dir) nil t)
load-path)))
(defvar doom--autoloads-path-cache nil)
(while (re-search-forward "^\\s-*(\\(?:custom-\\)?autoload\\s-+'[^ ]+\\s-+\"\\([^\"]*\\)\"" nil t)
(let ((path (match-string 1)))
(replace-match
(or (cdr (assoc path doom--autoloads-path-cache))
(when-let* ((libpath (or (and allow-internal-paths
(locate-library path nil (cons doom-emacs-dir doom-modules-dirs)))
(locate-library path)))
(libpath (file-name-sans-extension libpath))
(libpath (abbreviate-file-name libpath)))
(push (cons path libpath) doom--autoloads-path-cache)
libpath)
path)
t t nil 1)))))
(defun doom--cli-generate-autodefs-1 (path &optional member-p)
(let (forms)
(defun doom-cli--generate-autoloads-autodefs (file buffer module &optional module-enabled-p)
(with-temp-buffer
(insert-file-contents file)
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
(let* ((sexp (sexp-at-point))
(alt-sexp (match-string 1))
(type (car sexp))
(name (doom-unquote (cadr sexp)))
(origin (doom-module-from-path path)))
(cond
((and (not member-p)
alt-sexp)
(push (read alt-sexp) forms))
((memq type '(defun defmacro cl-defun cl-defmacro))
(cl-destructuring-bind (_ _name arglist &rest body) sexp
(appendq!
forms
(list (if member-p
(make-autoload sexp path)
(let ((docstring
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
origin
(if (stringp (car body))
(pop body)
"No documentation."))))
(condition-case-unless-debug e
(if alt-sexp
(read alt-sexp)
(append
(list (pcase type
(`defun 'defmacro)
(`cl-defun `cl-defmacro)
(_ type))
name arglist docstring)
(cl-loop for arg in arglist
if (and (symbolp arg)
(not (keywordp arg))
(not (memq arg cl--lambda-list-keywords)))
collect arg into syms
else if (listp arg)
collect (car arg) into syms
finally return (if syms `((ignore ,@syms))))))
('error
(print! "- Ignoring autodef %s (%s)" name e)
nil))))
`(put ',name 'doom-module ',origin)))))
((eq type 'defalias)
(cl-destructuring-bind (_type name target &optional docstring) sexp
(let ((name (doom-unquote name))
(target (doom-unquote target)))
(unless member-p
(setq target #'ignore
docstring
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
origin docstring)))
(appendq! forms `((put ',name 'doom-module ',origin)
(defalias ',name #',target ,docstring))))))
(member-p (push sexp forms)))))
forms))
(defun doom--cli-generate-autodefs (targets enabled-targets)
(goto-char (point-max))
(search-backward ";;;***" nil t)
(save-excursion (insert "\n"))
(dolist (path targets)
(insert
(with-temp-buffer
(insert-file-contents path)
(if-let (forms (doom--cli-generate-autodefs-1 path (member path enabled-targets)))
(concat (mapconcat #'prin1-to-string (nreverse forms) "\n")
"\n")
"")))))
(defun doom--cli-cleanup-autoloads ()
(goto-char (point-min))
(when (re-search-forward "^;;\\(;[^\n]*\\| no-byte-compile: t\\)\n" nil t)
(replace-match "" t t)))
(defun doom-cli-reload-core-autoloads (&optional force-p)
"Refreshes `doom-autoload-file', if necessary (or if FORCE-P is non-nil).
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
modules/*/*/autoload.el and modules/*/*/autoload/*.el, and generates
`doom-autoload-file'.
Run this whenever your `doom!' block, or a module autoload file, is modified."
(require 'autoload)
(let* ((default-directory doom-emacs-dir)
(doom-modules (doom-modules))
(let* ((standard-output buffer)
(form (read (current-buffer)))
(altform (match-string 1))
(definer (car-safe form))
(symbol (doom-unquote (cadr form))))
(cond ((and (not module-enabled-p) altform)
(print (read altform)))
((memq definer '(defun defmacro cl-defun cl-defmacro))
(if module-enabled-p
(print (make-autoload form file))
(cl-destructuring-bind (_ _ arglist &rest body) form
(print
(if altform
(read altform)
(append
(list (pcase definer
(`defun 'defmacro)
(`cl-defun `cl-defmacro)
(_ type))
symbol arglist
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
module
(if (stringp (car body))
(pop body)
"No documentation.")))
(cl-loop for arg in arglist
if (and (symbolp arg)
(not (keywordp arg))
(not (memq arg cl--lambda-list-keywords)))
collect arg into syms
else if (listp arg)
collect (car arg) into syms
finally return (if syms `((ignore ,@syms)))))))))
(print `(put ',symbol 'doom-module ',module)))
((eq definer 'defalias)
(cl-destructuring-bind (_ _ target &optional docstring) form
(unless module-enabled-p
(setq target #'ignore
docstring
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
module docstring)))
(print `(put ',symbol 'doom-module ',module))
(print `(defalias ',symbol #',(doom-unquote target) ,docstring))))
(module-enabled-p (print form)))))))
(defun doom-cli--generate-autoloads-buffer (file)
(let* (;; Prevent `autoload-find-file' from firing file hooks, e.g. adding
;; to recentf.
find-file-hook
write-file-functions
;; Prevent a possible source of crashes when there's a syntax error
;; in the autoloads file
debug-on-error
;; The following bindings are in `package-generate-autoloads'.
;; Presumably for a good reason, so I just copied them
(noninteractive t)
(backup-inhibited t)
(version-control 'never)
(case-fold-search nil) ; reduce magic
(autoload-timestamps nil)
case-fold-search ; reduce magic
autoload-timestamps ; reduce noise in generated files
;; Needed for `autoload-generate-file-autoloads'
(generated-autoload-load-name (file-name-sans-extension file))
(target-buffer (current-buffer))
(module (doom-module-from-path file))
(module-enabled-p (and (or (memq (car module) '(:core :private))
(doom-module-p (car module) (cdr module)))
(doom-file-cookie-p file "if" t))))
(save-excursion
(when module-enabled-p
(quiet! (autoload-generate-file-autoloads file target-buffer)))
(doom-cli--generate-autoloads-autodefs
file target-buffer module module-enabled-p))))
;; Where we'll store the files we'll scan for autoloads. This should
;; contain *all* autoload files, even in disabled modules, so we can
;; scan those for autodefs. We start with the core libraries.
(targets (doom-glob doom-core-dir "autoload/*.el"))
;; A subset of `targets' in enabled modules
(active-targets (copy-sequence targets)))
(dolist (path (doom-module-load-path 'all-p))
(when-let* ((files (cons (doom-glob path "autoload.el")
(doom-files-in (doom-path path "autoload")
:match "\\.el$")))
(files (delq nil files)))
(appendq! targets files)
(when (or (doom-module-from-path path 'enabled-only)
(file-equal-p path doom-private-dir))
(appendq! active-targets files))))
(print! (start "Checking core autoloads file"))
(print-group!
(if (and (not force-p)
(file-exists-p doom-autoload-file)
(not (file-newer-than-file-p doom-emacs-dir doom-autoload-file))
(not (cl-loop for dir
in (append (doom-glob doom-private-dir "init.el*")
targets)
if (file-newer-than-file-p dir doom-autoload-file)
return t)))
(ignore
(print! (success "Skipping core autoloads, they are up-to-date"))
(doom-load-autoloads-file doom-autoload-file))
(if (doom--cli-delete-autoloads-file doom-autoload-file)
(print! (success "Deleted old %s") (filename doom-autoload-file))
(make-directory (file-name-directory doom-autoload-file) t))
(print! (start "Regenerating core autoloads file"))
(print-group!
(with-temp-file doom-autoload-file
(doom--cli-generate-header 'doom-cli-reload-core-autoloads)
(save-excursion
(doom--cli-generate-autoloads active-targets)
(print! (success "Generated new autoloads.el")))
;; Replace autoload paths (only for module autoloads) with absolute
;; paths for faster resolution during load and simpler `load-path'
(save-excursion
(doom--cli-expand-autoload-paths 'allow-internal-paths)
(print! (success "Expanded module autoload paths")))
;; Generates stub definitions for functions/macros defined in disabled
;; modules, so that you will never get a void-function when you use
;; them.
(save-excursion
(doom--cli-generate-autodefs targets (reverse active-targets))
(print! (success "Generated autodefs")))
;; Remove byte-compile-inhibiting file variables so we can byte-compile
;; the file, and autoload comments.
(doom--cli-cleanup-autoloads)
(print! (success "Cleaned up autoloads"))))
;; Byte compile it to give the file a chance to reveal errors (and buy us a
;; few marginal performance boosts)
(print! "> Byte-compiling %s..." (relpath doom-autoload-file))
(when (doom--cli-byte-compile-file doom-autoload-file)
(print-group!
(print! (success "Compiled %s") (relpath doom-autoload-file)))))
t)))
;;
;;; Package autoloads
(defun doom--generate-package-autoloads ()
"Concatenates package autoload files, let-binds `load-file-name' around
them,and remove unnecessary `provide' statements or blank links."
(dolist (pkg (hash-table-keys straight--build-cache))
(unless (member pkg doom-autoload-excluded-packages)
(let ((file (straight--autoloads-file pkg)))
(when (file-exists-p file)
(insert-file-contents file)
(save-excursion
(while (re-search-forward "\\(?:\\_<load-file-name\\|#\\$\\)\\_>" nil t)
;; `load-file-name' is meaningless in a concatenated
;; mega-autoloads file, so we replace references to it and #$ with
;; the file they came from.
(unless (doom-point-in-string-or-comment-p)
(replace-match (prin1-to-string (abbreviate-file-name file))
t t))))
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
(unless (doom-point-in-string-p)
(replace-match "" t t)))
(unless (bolp) (insert "\n")))))))
(defun doom--generate-var-cache ()
"Print a `setq' form for expensive-to-initialize variables, so we can cache
them in Doom's autoloads file."
(doom-initialize-packages)
(prin1 `(setq load-path ',load-path
auto-mode-alist ',auto-mode-alist
Info-directory-list ',Info-directory-list
doom-disabled-packages ',doom-disabled-packages)
(current-buffer)))
(defun doom--cleanup-package-autoloads ()
"Remove (some) forms that modify `load-path' or `auto-mode-alist'.
These variables are cached all at once and at later, so these removed statements
served no purpose but to waste cycles."
(while (re-search-forward "^\\s-*\\((\\(?:add-to-list\\|\\(?:when\\|if\\) (boundp\\)\\s-+'\\(?:load-path\\|auto-mode-alist\\)\\)" nil t)
(goto-char (match-beginning 1))
(kill-sexp)))
(defun doom-cli-reload-package-autoloads (&optional force-p)
"Compiles `doom-package-autoload-file' from the autoloads files of all
installed packages. It also caches `load-path', `Info-directory-list',
`doom-disabled-packages', `package-activated-list' and `auto-mode-alist'.
Will do nothing if none of your installed packages have been modified. If
FORCE-P (universal argument) is non-nil, regenerate it anyway.
This should be run whenever your `doom!' block or update your packages."
(defun doom-cli--generate-autoloads (files &optional scan)
(require 'autoload)
(print! (start "Checking package autoloads file"))
(print-group!
(if (and (not force-p)
(file-exists-p doom-package-autoload-file)
(not (file-newer-than-file-p package-user-dir doom-package-autoload-file))
(not (cl-loop for dir in (straight--directory-files (straight--build-dir))
if (cl-find-if
(lambda (dir)
(file-newer-than-file-p dir doom-package-autoload-file))
(doom-glob (straight--build-dir dir) "*.el"))
return t))
(not (cl-loop with doom-modules = (doom-modules)
for key being the hash-keys of doom-modules
for path = (doom-module-path (car key) (cdr key) "packages.el")
if (file-newer-than-file-p path doom-package-autoload-file)
return t)))
(ignore
(print! (success "Skipping package autoloads, they are up-to-date"))
(doom-load-autoloads-file doom-package-autoload-file))
(let (;; The following bindings are in `package-generate-autoloads'.
;; Presumably for a good reason, so I just copied them
(noninteractive t)
(backup-inhibited t)
(version-control 'never)
(case-fold-search nil) ; reduce magic
(autoload-timestamps nil))
(if (doom--cli-delete-autoloads-file doom-package-autoload-file)
(print! (success "Deleted old %s") (filename doom-package-autoload-file))
(make-directory (file-name-directory doom-autoload-file) t))
(print! (start "Regenerating package autoloads file"))
(print-group!
(with-temp-file doom-package-autoload-file
(doom--cli-generate-header 'doom-cli-reload-package-autoloads)
(save-excursion
;; Cache important and expensive-to-initialize state here.
(doom--generate-var-cache)
(print! (success "Cached package state"))
;; Concatenate the autoloads of all installed packages.
(doom--generate-package-autoloads)
(print! (success "Package autoloads included")))
;; Replace autoload paths (only for module autoloads) with absolute
;; paths for faster resolution during load and simpler `load-path'
(save-excursion
(doom--cli-expand-autoload-paths)
(print! (success "Expanded module autoload paths")))
;; Remove `load-path' and `auto-mode-alist' modifications (most of them,
;; at least); they are cached later, so all those membership checks are
;; unnecessary overhead.
(doom--cleanup-package-autoloads)
(print! (success "Removed load-path/auto-mode-alist entries"))))
;; Byte compile it to give the file a chance to reveal errors (and buy us a
;; few marginal performance boosts)
(print! (start "Byte-compiling %s...") (relpath doom-package-autoload-file))
(when (doom--cli-byte-compile-file doom-package-autoload-file)
(print-group!
(print! (success "Compiled %s") (relpath doom-package-autoload-file))))))
t))
(let (autoloads)
(dolist (file
(cl-remove-if-not #'file-readable-p files)
(nreverse (delq nil autoloads)))
(with-temp-buffer
(print! (debug "- Scanning %s") (relpath file doom-emacs-dir))
(if scan
(doom-cli--generate-autoloads-buffer file)
(insert-file-contents file))
(save-excursion
(let ((filestr (prin1-to-string file)))
(while (re-search-forward "\\_<load-file-name\\_>" nil t)
;; `load-file-name' is meaningless in a concatenated
;; mega-autoloads file, so we replace references to it with the
;; file they came from.
(let ((ppss (save-excursion (syntax-ppss))))
(or (nth 3 ppss)
(nth 4 ppss)
(replace-match filestr t t))))))
(let ((load-file-name file)
(load-path
(append (list doom-private-dir)
doom-modules-dirs
load-path)))
(condition-case _
(while t
(push (doom-cli--filter-form (read (current-buffer))
scan)
autoloads))
(end-of-file)))))))

View file

@ -27,6 +27,7 @@ and your private config files, respectively. To recompile your packages, use
(let ((filename (file-name-nondirectory path)))
(or (string-prefix-p "." filename)
(string-prefix-p "test-" filename)
(string-suffix-p ".example.el" filename)
(not (equal (file-name-extension path) "el"))
(member filename (list "packages.el" "doctor.el")))))
@ -92,7 +93,8 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
;; But first we must be sure that Doom and your private config have been
;; fully loaded. Which usually aren't so in an noninteractive session.
(let ((doom-interactive-mode 'byte-compile))
(doom-initialize 'force)
(doom-initialize)
(doom-initialize-packages)
(doom-initialize-core))
;;
@ -122,9 +124,9 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
(cl-return nil))
(print!
(info (if recompile-p
"Recompiling stale elc files..."
"Byte-compiling your config (may take a while)...")))
(start (if recompile-p
"Recompiling stale elc files..."
"Byte-compiling your config (may take a while)...")))
(print-group!
(require 'use-package)
(condition-case e
@ -199,4 +201,5 @@ module. This does not include your byte-compiled, third party packages.'"
finally do
(print! (if success
(success "All elc files deleted")
(info "No elc files to clean"))))))
(info "No elc files to clean"))))
t))

View file

@ -136,7 +136,7 @@ in."
(`darwin "~/Library/Fonts/"))
(require 'all-the-icons nil t))
(with-temp-buffer
(insert (cdr (doom-call-process "fc-list")))
(insert (cdr (doom-call-process "fc-list" "" "file")))
(dolist (font all-the-icons-font-names)
(if (save-excursion (re-search-backward font nil t))
(success! "Found font %s" font)

View file

@ -3,9 +3,9 @@
(defcli! env
((clear-p ["-c" "--clear"] "Clear and delete your envvar file")
(outputfile ["-o" PATH]
"Generate the envvar file at PATH. Note that envvar files that aren't in
`doom-env-file' won't be loaded automatically at startup. You will need to
load them manually from your private config with the `doom-load-envvars-file'
"Generate the envvar file at PATH. Envvar files that aren't in
`doom-env-file' won't be loaded automatically at startup. You will need to load
them manually from your private config with the `doom-load-envvars-file'
function."))
"Creates or regenerates your envvars file.
@ -19,8 +19,8 @@ This is useful in cases where you cannot guarantee that Emacs (or the daemon)
will be launched from the correct environment (e.g. on MacOS or through certain
app launchers on Linux).
This file is automatically regenerated when you run this command or 'doom
refresh'. However, 'doom refresh' will only regenerate this file if it exists.
This file is automatically regenerated when you run this command or 'doom sync'.
However, 'doom sync' will only regenerate this file if it exists.
Why this over exec-path-from-shell?
@ -36,7 +36,7 @@ Why this over exec-path-from-shell?
I'd rather it inherit your shell environment /correctly/ (and /completely/)
or not at all. It frontloads the debugging process rather than hiding it
until it you least want to deal with it."
until you least want to deal with it."
(let ((env-file (expand-file-name (or outputfile doom-env-file))))
(cond (clear-p
(unless (file-exists-p env-file)
@ -57,18 +57,20 @@ Why this over exec-path-from-shell?
;; Helpers
(defvar doom-env-ignored-vars
'("^PWD$"
"^PS1$"
"^R?PROMPT$"
"^DBUS_SESSION_BUS_ADDRESS$"
'("^DBUS_SESSION_BUS_ADDRESS$"
"^GPG_AGENT_INFO$"
"^GPG_TTY$"
"^HOME$"
"^PS1$"
"^PWD$"
"^R?PROMPT$"
"^SSH_AGENT_PID$"
"^SSH_AUTH_SOCK$"
;; Doom envvars
"^INSECURE$"
"^DEBUG$"
"^YES$"
"^TERM$"
;; Doom envvars
"^DEBUG$"
"^INSECURE$"
"^YES$"
"^__")
"Environment variables to not save in `doom-env-file'.
@ -100,7 +102,7 @@ default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
(goto-char (point-min))
(insert
(concat
"# -*- mode: dotenv -*-\n"
"# -*- mode: sh -*-\n"
(format "# Generated from a %s shell environent\n" shell-file-name)
"# ---------------------------------------------------------------------------\n"
"# This file was auto-generated by `doom env'. It contains a list of environment\n"
@ -109,7 +111,7 @@ default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
"#\n"
(if (file-equal-p env-file doom-env-file)
(concat "# It is NOT safe to edit this file. Changes will be overwritten next time you\n"
"# run 'doom refresh'. To create a safe-to-edit envvar file use:\n#\n"
"# run 'doom sync'. To create a safe-to-edit envvar file use:\n#\n"
"# doom env -o ~/.doom.d/myenv\n#\n"
"# And load it with (doom-load-envvars-file \"~/.doom.d/myenv\").\n")
(concat "# This file is safe to edit by hand, but needs to be loaded manually with:\n#\n"
@ -120,7 +122,7 @@ default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
;; user's interactive shell, therefore we just dump
;; `process-environment' to a file.
(dolist (env process-environment)
(if (cl-find-if (doom-rpartial #'string-match-p env)
(if (cl-find-if (doom-rpartial #'string-match-p (car (split-string env "=")))
doom-env-ignored-vars)
(print! (info "Ignoring %s") env)
(insert env "\n")))

View file

@ -27,7 +27,9 @@
until (memq arg cl--lambda-list-keywords)
collect (format "[%s]" (upcase (symbol-name arg)))))
" ")
"")))
""))
(when-let (aliases (doom-cli-aliases cli))
(print! "Aliases: %s" (string-join aliases ", "))))
(defun doom--cli-print-desc (cli &optional short)
(print! "%s"
@ -43,7 +45,6 @@
(print! (bold "Options:"))
(print-group!
(cl-loop for opt in optlist
for flags = (doom-cli-option-flags opt)
for desc = (doom-cli-option-desc opt)
for args = (doom-cli-option-args opt)
for flagstr = (string-join (doom-cli-option-flags opt) ", ")

View file

@ -5,7 +5,7 @@
(noenv-p ["--no-env"] "Don't generate an envvars file (see 'doom help env')")
(noinstall-p ["--no-install"] "Don't auto-install packages")
(nofonts-p ["--no-fonts"] "Don't install (or prompt to install) all-the-icons fonts")
&rest args)
&rest _args)
"Installs and sets up Doom Emacs for the first time.
This command does the following:
@ -46,24 +46,20 @@ DOOMDIR environment variable. e.g.
(print! (success "Done!")))))
'(("init.el" .
(lambda ()
(insert-file-contents (doom-path doom-emacs-dir "init.example.el"))))
(insert-file-contents
(doom-path doom-emacs-dir "init.example.el"))))
("config.el" .
(lambda ()
(insert! ";;; %sconfig.el -*- lexical-binding: t; -*-\n\n"
";; Place your private configuration here\n"
((relpath doom-private-dir)))))
(insert-file-contents
(doom-path doom-core-dir "templates/config.example.el"))))
("packages.el" .
(lambda ()
(insert! ";; -*- no-byte-compile: t; -*-\n;;; %spackages.el\n\n"
";;; Examples:\n"
";; (package! some-package)\n"
";; (package! another-package :recipe (:host github :repo \"username/repo\"))\n"
";; (package! builtin-package :disable t)\n"
((relpath doom-private-dir))))))))
(insert-file-contents
(doom-path doom-core-dir "templates/packages.example.el")))))))
;; In case no init.el was present the first time `doom-initialize-modules' was
;; called in core.el (e.g. on first install)
(doom-initialize 'force)
(doom-initialize 'force 'noerror)
(doom-initialize-modules)
;; Ask if user would like an envvar file generated
@ -72,7 +68,7 @@ DOOMDIR environment variable. e.g.
(if (file-exists-p doom-env-file)
(print! (info "Envvar file already exists, skipping"))
(when (or doom-auto-accept
(y-or-n-p "Generate an env file? (see `doom help env` for details)"))
(y-or-n-p "Generate an envvar file? (see `doom help env` for details)"))
(doom-cli-reload-env-file 'force-p))))
;; Install Doom packages
@ -82,16 +78,24 @@ DOOMDIR environment variable. e.g.
(doom-cli-packages-install))
(print! "Regenerating autoloads files")
(doom-cli-reload-autoloads nil 'force-p)
(if nofonts-p
(print! (warn "Not installing fonts, as requested"))
(when (or doom-auto-accept
(y-or-n-p "Download and install all-the-icon's fonts?"))
(require 'all-the-icons)
(let ((window-system (cond (IS-MAC 'ns)
(IS-LINUX 'x))))
(all-the-icons-install-fonts 'yes))))
(doom-cli-reload-autoloads)
(cond (nofonts-p)
(IS-WINDOWS
(print! (warn "Doom cannot install all-the-icons' fonts on Windows!\n"))
(print-group!
(print!
(concat "You'll have to do so manually:\n\n"
" 1. Launch Doom Emacs\n"
" 2. Execute 'M-x all-the-icons-install-fonts' to download the fonts\n"
" 3. Open the download location in windows explorer\n"
" 4. Open each font file to install them"))))
((or doom-auto-accept
(y-or-n-p "Download and install all-the-icon's fonts?"))
(require 'all-the-icons)
(let ((window-system (cond (IS-MAC 'ns)
(IS-LINUX 'x))))
(all-the-icons-install-fonts 'yes))))
(when (file-exists-p "~/.emacs")
(print! (warn "A ~/.emacs file was detected. This conflicts with Doom and should be deleted!")))

View file

@ -1,7 +1,8 @@
;; -*- no-byte-compile: t; -*-
;;; core/cli/packages.el
(defcli! (update u) ()
(defcli! (update u)
((discard-p ["--discard"] "All local changes to packages are discarded"))
"Updates packages.
This works by fetching all installed package repos and checking the distance
@ -10,10 +11,11 @@ between HEAD and FETCH_HEAD. This can take a while.
This excludes packages whose `package!' declaration contains a non-nil :freeze
or :ignore property."
(straight-check-all)
(doom-cli-reload-core-autoloads)
(when (doom-cli-packages-update)
(doom-cli-reload-package-autoloads 'force-p))
t)
(let ((doom-auto-discard discard-p))
(doom-cli-reload-core-autoloads)
(when (doom-cli-packages-update)
(doom-cli-reload-package-autoloads))
t))
(defcli! (build b)
((rebuild-p ["-r"] "Only rebuild packages that need rebuilding"))
@ -23,7 +25,7 @@ This ensures that all needed files are symlinked from their package repo and
their elisp files are byte-compiled. This is especially necessary if you upgrade
Emacs (as byte-code is generally not forward-compatible)."
(when (doom-cli-packages-build (not rebuild-p))
(doom-cli-reload-package-autoloads 'force-p))
(doom-cli-reload-package-autoloads))
t)
(defcli! (purge p)
@ -46,7 +48,7 @@ list remains lean."
(not norepos-p)
(not nobuilds-p)
regraft-p)
(doom-cli-reload-package-autoloads 'force-p))
(doom-cli-reload-package-autoloads))
t)
;; (defcli! rollback () ; TODO doom rollback
@ -57,138 +59,186 @@ list remains lean."
;;
;;; Library
(defun doom--same-commit-p (abbrev-ref ref)
(and (stringp abbrev-ref)
(stringp ref)
(string-match-p (concat "^" (regexp-quote abbrev-ref))
ref)))
(defun doom--abbrev-commit (commit &optional full)
(if full commit (substring commit 0 7)))
(defun doom--commit-log-between (start-ref end-ref)
(and (straight--call
"git" "log" "--oneline" "--no-merges"
"-n" "25" end-ref (concat "^" (regexp-quote start-ref)))
(straight--process-get-output)))
(defun doom-cli-packages-install ()
"Installs missing packages.
This function will install any primary package (i.e. a package with a `package!'
declaration) or dependency thereof that hasn't already been."
(print! (start "Installing & building packages..."))
(print-group!
(let ((n 0))
(dolist (package (hash-table-keys straight--recipe-cache))
(straight--with-plist (gethash package straight--recipe-cache)
(local-repo)
(let ((existed-p (file-directory-p (straight--repos-dir package))))
(condition-case-unless-debug e
(and (straight-use-package (intern package) nil nil (make-string (1- (or doom-format-indent 1)) 32))
(not existed-p)
(file-directory-p (straight--repos-dir package))
(cl-incf n))
(error
(signal 'doom-package-error
(list e (straight--process-get-output))))))))
(if (= n 0)
(ignore (print! (success "No packages need to be installed")))
(print! (success "Installed & built %d packages") n)
t))))
(straight--transaction-finalize)
(print! (start "Installing packages..."))
(let ((pinned (doom-package-pinned-list)))
(print-group!
(if-let (built
(doom-with-package-recipes (doom-package-recipe-list)
(recipe package type local-repo)
(condition-case-unless-debug e
(straight-use-package (intern package))
(error
(signal 'doom-package-error
(list package e (straight--process-get-output)))))))
(print! (success "Installed %d packages")
(length built))
(print! (info "No packages need to be installed"))
nil))))
(defun doom-cli-packages-build (&optional force-p)
"(Re)build all packages."
(straight--transaction-finalize)
(print! (start "(Re)building %spackages...") (if force-p "all " ""))
(print-group!
(let ((n 0))
(if force-p
(let ((straight--packages-to-rebuild :all)
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
(dolist (package (hash-table-keys straight--recipe-cache))
(straight-use-package
(intern package) nil (lambda (_) (cl-incf n) nil)
(make-string (1- (or doom-format-indent 1)) 32))))
(dolist (recipe (hash-table-values straight--recipe-cache))
(straight--with-plist recipe (package local-repo no-build)
(unless (or no-build (null local-repo))
;; REVIEW We do these modification checks manually because
;; Straight's checks seem to miss stale elc files. Need
;; more tests to confirm this.
(when (or (ignore-errors
(gethash package straight--packages-to-rebuild))
(gethash package straight--cached-package-modifications)
(not (file-directory-p (straight--build-dir package)))
(cl-loop for file
in (doom-files-in (straight--build-dir package)
:match "\\.el$"
:full t)
for elc-file = (byte-compile-dest-file file)
if (and (file-exists-p elc-file)
(file-newer-than-file-p file elc-file))
return t))
(let ((straight-use-package-pre-build-functions
straight-use-package-pre-build-functions))
(add-hook 'straight-use-package-pre-build-functions
(lambda (&rest _) (cl-incf n)))
(let ((straight--packages-to-rebuild :all)
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
(straight-use-package
(intern package) nil nil
(make-string (or doom-format-indent 0) 32)))
(straight--byte-compile-package recipe)
(dolist (dep (straight--get-dependencies package))
(when-let (recipe (gethash dep straight--recipe-cache))
(straight--byte-compile-package recipe)))))))))
(if (= n 0)
(ignore (print! (success "No packages need rebuilding")))
(doom--finalize-straight)
(print! (success "Rebuilt %d package(s)" n))
t))))
(let ((straight-check-for-modifications
(when (file-directory-p (straight--modified-dir))
'(find-when-checking)))
(straight--allow-find
(and straight-check-for-modifications
(executable-find straight-find-executable)
t))
(straight--packages-not-to-rebuild
(or straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
(straight--packages-to-rebuild
(or (if force-p :all straight--packages-to-rebuild)
(make-hash-table :test #'equal)))
(recipes (doom-package-recipe-list)))
(unless force-p
(straight--make-build-cache-available))
(if-let (built
(doom-with-package-recipes recipes (package local-repo)
(unless force-p
;; Ensure packages with outdated files/bytecode are rebuilt
(let ((build-dir (straight--build-dir package))
(repo-dir (straight--repos-dir local-repo)))
(and (or (file-newer-than-file-p repo-dir build-dir)
(file-exists-p (straight--modified-dir (or local-repo package)))
;; Doesn't make sense to compare el and elc files
;; when the former isn't a symlink to their source.
(when straight-use-symlinks
(cl-loop for file
in (doom-files-in build-dir :match "\\.el$" :full t)
for elc-file = (byte-compile-dest-file file)
if (and (file-exists-p elc-file)
(file-newer-than-file-p file elc-file))
return t)))
(puthash package t straight--packages-to-rebuild))))
(straight-use-package (intern package))))
(print! (success "Rebuilt %d package(s)") (length built))
(print! (success "No packages need rebuilding"))
nil))))
(defun doom-cli-packages-update ()
"Updates packages."
(straight--transaction-finalize)
(print! (start "Updating packages (this may take a while)..."))
(let ((straight--packages-to-rebuild (make-hash-table :test #'equal))
(total (hash-table-count straight--repo-cache))
(i 1)
errors)
(print-group!
(dolist (recipe (hash-table-values straight--repo-cache))
(straight--with-plist recipe (package type local-repo)
(let* ((repo-dir (straight--repos-dir))
(pinned (doom-package-pinned-list))
(packages-to-rebuild (make-hash-table :test 'equal))
(repos-to-rebuild (make-hash-table :test 'equal))
(recipes (doom-package-recipe-list))
(total (length recipes))
(esc (unless doom-debug-mode "\033[1A"))
(i 0)
errors)
(doom-with-package-recipes recipes (recipe package type local-repo)
(cl-incf i)
(print-group!
(unless (straight--repository-is-available-p recipe)
(print! (error "(%d/%d) Couldn't find local repo for %s") i total package)
(cl-return))
(when (gethash local-repo repos-to-rebuild)
(puthash package t packages-to-rebuild)
(print! (success "(%d/%d) %s was updated indirectly (with %s)") i total package local-repo)
(cl-return))
(let ((default-directory (straight--repos-dir local-repo)))
(unless (file-in-directory-p default-directory repo-dir)
(print! (warn "(%d/%d) Skipping %s because it is local") i total package)
(cl-return))
(condition-case-unless-debug e
(let* ((default-directory (straight--repos-dir local-repo))
(commit (straight-vc-get-commit type local-repo)))
(if (not (straight-vc-fetch-from-remote recipe))
(print! (warn "(%d/%d) Failed to fetch %s" i total package))
(let ((output (straight--process-get-output)))
(straight-merge-package package)
(let ((newcommit (straight-vc-get-commit type local-repo)))
(if (string= commit newcommit)
(print! (info "(%d/%d) %s is up-to-date") i total package)
(let ((ref (straight-vc-get-commit type local-repo))
(target-ref (cdr (assoc local-repo pinned)))
output)
(or (cond
((not (stringp target-ref))
(print! (start "\033[K(%d/%d) Fetching %s...%s") i total package esc)
(when (straight-vc-fetch-from-remote recipe)
(setq output (straight--process-get-output))
(straight-merge-package package)
(setq target-ref (straight-vc-get-commit type local-repo))
(or (not (doom--same-commit-p target-ref ref))
(cl-return))))
((doom--same-commit-p target-ref ref)
(print! (info "\033[K(%d/%d) %s is up-to-date...%s") i total package esc)
(cl-return))
((straight-vc-commit-present-p recipe target-ref)
(print! (start "\033[K(%d/%d) Checking out %s (%s)...%s")
i total package (doom--abbrev-commit target-ref) esc)
(straight-vc-check-out-commit recipe target-ref)
(or (not (eq type 'git))
(setq output (doom--commit-log-between ref target-ref)))
(doom--same-commit-p target-ref (straight-vc-get-commit type local-repo)))
((print! (start "\033[K(%d/%d) Re-cloning %s...") i total local-repo esc)
(let ((repo (straight--repos-dir local-repo)))
(ignore-errors
(delete-directory (straight--build-dir package) 'recursive))
(puthash package t straight--packages-to-rebuild)
(print! (success "(%d/%d) %s updated (%s -> %s)") i total package
(substring commit 0 7)
(substring newcommit 0 7))
(unless (string-empty-p output)
(print-group!
(print! (info "%s") output)
(when (eq type 'git)
(straight--call "git" "log" "--oneline" newcommit (concat "^" commit))
(print-group!
(print! "%s" (straight--process-get-output))))))))))
(cl-incf i))
(delete-directory repo 'recursive))
(print-group!
(straight-use-package (intern package) nil 'no-build))
(prog1 (file-directory-p repo)
(or (not (eq type 'git))
(setq output (doom--commit-log-between ref target-ref)))))))
(progn
(print! (warn "\033[K(%d/%d) Failed to fetch %s")
i total local-repo)
(unless (string-empty-p output)
(print-group! (print! (info "%s" output))))
(cl-return)))
(puthash local-repo t repos-to-rebuild)
(puthash package t packages-to-rebuild)
(unless (string-empty-p output)
(print! (start "\033[K(%d/%d) Updating %s...") i total local-repo)
(print-group! (print! (indent 2 output))))
(print! (success "\033[K(%d/%d) %s updated (%s -> %s)")
i total local-repo
(doom--abbrev-commit ref)
(doom--abbrev-commit target-ref)))
(user-error
(signal 'user-error (error-message-string e)))
(error
(print! (warn "(%d/%d) Encountered error with %s" i total package))
(print! (warn "\033[K(%d/%d) Encountered error with %s" i total package))
(print-group!
(print! (error "%s" e))
(print! (error "%s") e)
(print-group! (print! (info "%s" (straight--process-get-output)))))
(push package errors)))))
(when errors
(print! (error "There were %d errors, the offending packages are: %s")
(length errors) (string-join errors ", ")))
(if (hash-table-empty-p straight--packages-to-rebuild)
(ignore
(print! (success "All %d packages are up-to-date")
(hash-table-count straight--repo-cache)))
(let ((count (hash-table-count straight--packages-to-rebuild))
(packages (hash-table-keys straight--packages-to-rebuild)))
(sort packages #'string-lessp)
(doom--finalize-straight)
(doom-cli-packages-build)
(print! (success "Updated %d package(s)") count))
t))))
(push package errors))))))
(princ "\033[K")
(when errors
(print! (error "Encountered %d error(s), the offending packages: %s")
(length errors) (string-join errors ", ")))
(if (hash-table-empty-p packages-to-rebuild)
(ignore (print! (success "All %d packages are up-to-date") total))
(let ((default-directory (straight--build-dir)))
(mapc (doom-rpartial #'delete-directory 'recursive)
(hash-table-keys packages-to-rebuild)))
(print! (success "Updated %d package(s)")
(hash-table-count packages-to-rebuild))
(doom-cli-packages-build)
t)))
;;; PURGE (for the emperor)
@ -204,34 +254,44 @@ declaration) or dependency thereof that hasn't already been."
(if (not builds)
(progn (print! (info "No builds to purge"))
0)
(length
(delq nil (mapcar #'doom--cli-packages-purge-build builds)))))
(print! (start "Purging straight builds..." (length builds)))
(print-group!
(length
(delq nil (mapcar #'doom--cli-packages-purge-build builds))))))
(defun doom--cli-packages-regraft-repo (repo)
(cl-defun doom--cli-packages-regraft-repo (repo)
(let ((default-directory (straight--repos-dir repo)))
(if (not (file-directory-p ".git"))
(ignore (print! (warn "repos/%s is not a git repo, skipping" repo)))
(let ((before-size (doom-directory-size default-directory)))
(straight--call "git" "reset" "--hard")
(straight--call "git" "clean" "-ffd")
(if (not (car (straight--call "git" "replace" "--graft" "HEAD")))
(print! (info "repos/%s is already compact" repo))
(straight--call "git" "gc")
(print! (success "Regrafted repos/%s (from %0.1fKB to %0.1fKB)")
repo before-size (doom-directory-size default-directory))
(print-group! (print! "%s" (straight--process-get-output)))))
(unless (file-directory-p ".git")
(print! (warn "\033[Krepos/%s is not a git repo, skipping" repo))
(cl-return))
(unless (file-in-directory-p default-directory straight-base-dir)
(print! (warn "\033[KSkipping repos/%s because it is local" repo))
(cl-return))
(let ((before-size (doom-directory-size default-directory)))
(straight--call "git" "reset" "--hard")
(straight--call "git" "clean" "-ffd")
(if (not (car (straight--call "git" "replace" "--graft" "HEAD")))
(print! (info "\033[Krepos/%s is already compact\033[1A" repo))
(straight--call "git" "reflog" "expire" "--expire=all" "--all")
(straight--call "git" "gc" "--prune=now")
(print! (success "\033[KRegrafted repos/%s (from %0.1fKB to %0.1fKB)")
repo before-size (doom-directory-size default-directory))
(print-group! (print! "%s" (straight--process-get-output))))
t)))
(defun doom--cli-packages-regraft-repos (repos)
(if (not repos)
(progn (print! (info "No repos to regraft"))
0)
(print! (start "Regrafting %d repos..." (length repos)))
(let ((before-size (doom-directory-size (straight--repos-dir))))
(prog1 (print-group! (delq nil (mapcar #'doom--cli-packages-regraft-repo repos)))
(let ((after-size (doom-directory-size (straight--repos-dir))))
(print! (success "Finished regrafting. Size before: %0.1fKB and after: %0.1fKB (%0.1fKB)")
before-size after-size
(- after-size before-size)))))))
(print-group!
(prog1 (delq nil (mapcar #'doom--cli-packages-regraft-repo repos))
(princ "\033[K")
(let ((after-size (doom-directory-size (straight--repos-dir))))
(print! (success "Finished regrafting. Size before: %0.1fKB and after: %0.1fKB (%0.1fKB)")
before-size after-size
(- after-size before-size))))))))
(defun doom--cli-packages-purge-repo (repo)
(let ((repo-dir (straight--repos-dir repo)))
@ -247,22 +307,29 @@ declaration) or dependency thereof that hasn't already been."
(if (not repos)
(progn (print! (info "No repos to purge"))
0)
(length
(delq nil (mapcar #'doom--cli-packages-purge-repo repos)))))
(print! (start "Purging straight repositories..."))
(print-group!
(length
(delq nil (mapcar #'doom--cli-packages-purge-repo repos))))))
(defun doom--cli-packages-purge-elpa ()
(unless (bound-and-true-p package--initialized)
(package-initialize))
(let ((packages (cl-loop for (package desc) in package-alist
for dir = (package-desc-dir desc)
if (file-in-directory-p dir package-user-dir)
collect (cons package dir))))
(if (not package-alist)
(require 'core-packages)
(let ((dirs (doom-files-in package-user-dir :type t :depth 0)))
(if (not dirs)
(progn (print! (info "No ELPA packages to purge"))
0)
(mapc (doom-rpartial #'delete-directory 'recursive)
(mapcar #'cdr packages))
(length packages))))
(print! (start "Purging ELPA packages..."))
(dolist (path dirs (length dirs))
(condition-case e
(print-group!
(if (file-directory-p path)
(delete-directory path 'recursive)
(delete-file path))
(print! (success "Deleted %s") (filename path)))
(error
(print! (error "Failed to delete %s because: %s")
(filename path)
e)))))))
(defun doom-cli-packages-purge (&optional elpa-p builds-p repos-p regraft-repos-p)
"Auto-removes orphaned packages and repos.
@ -273,7 +340,7 @@ a `package!' declaration) or isn't depended on by another primary package.
If BUILDS-P, include straight package builds.
If REPOS-P, include straight repos.
If ELPA-P, include packages installed with package.el (M-x package-install)."
(print! (start "Searching for orphaned packages to purge (for the emperor)..."))
(print! (start "Purging orphaned packages (for the emperor)..."))
(cl-destructuring-bind (&optional builds-to-purge repos-to-purge repos-to-regraft)
(let ((rdirs (straight--directory-files (straight--repos-dir) nil nil 'sort))
(bdirs (straight--directory-files (straight--build-dir) nil nil 'sort)))
@ -302,6 +369,4 @@ If ELPA-P, include packages installed with package.el (M-x package-install)."
(print! (info "Skipping regrafting"))
(and (doom--cli-packages-regraft-repos repos-to-regraft)
(setq success t)))
(when success
(doom--finalize-straight)
t)))))
success))))

View file

@ -11,9 +11,9 @@
(defcli! test (&rest targets)
"Run Doom unit tests."
:bare t
(doom-initialize 'force)
(doom-initialize 'force 'noerror)
(require 'ansi-color)
(let (files error read-files)
(let (files read-files)
(unless targets
(setq targets
(cons doom-core-dir
@ -48,11 +48,11 @@
doom-auto-accept t)
(require 'core ,(locate-library "core"))
(require 'core-cli)
(doom-initialize 'force)
(doom-initialize 'force 'noerror)
(doom-initialize-modules)
(doom-cli-reload-core-autoloads 'force)
(doom-cli-reload-core-autoloads)
(when (doom-cli-packages-install)
(doom-cli-reload-package-autoloads 'force)))))
(doom-cli-reload-package-autoloads)))))
(unless (zerop status)
(error "Failed to bootstrap unit tests"))))
(with-temp-buffer

View file

@ -1,7 +1,8 @@
;;; core/cli/upgrade.el -*- lexical-binding: t; -*-
(defcli! (upgrade up)
((force-p ["-f" "--force"]))
((force-p ["-f" "--force"] "Discard local changes to Doom and packages, and upgrade anyway")
(packages-only-p ["-p" "--packages"] "Only upgrade packages, not Doom"))
"Updates Doom and packages.
This requires that ~/.emacs.d is a git repo, and is the equivalent of the
@ -10,15 +11,20 @@ following shell commands:
cd ~/.emacs.d
git pull --rebase
bin/doom clean
bin/doom refresh
bin/doom sync
bin/doom update"
:bare t
(when (doom-cli-upgrade doom-auto-accept force-p)
(require 'core-packages)
(doom-initialize)
(doom-initialize-packages)
(when (doom-cli-packages-update)
(doom-cli-reload-package-autoloads 'force))))
(let ((doom-auto-discard force-p))
(if (delq
nil (list
(unless packages-only-p
(doom-cli-upgrade doom-auto-accept doom-auto-discard))
(doom-cli-execute "refresh")
(when (doom-cli-packages-update)
(doom-cli-reload-package-autoloads)
t)))
(print! (success "Done! Restart Emacs for changes to take effect."))
(print! "Nothing to do. Doom is up-to-date!"))))
;;
@ -33,7 +39,7 @@ following shell commands:
(cl-destructuring-bind (success . stdout)
(doom-call-process "git" "status" "--porcelain" "-uno")
(if (= 0 success)
(string-match-p "[^ \t\n]" (buffer-string))
(split-string stdout "\n" t)
(error "Failed to check working tree in %s" dir))))
@ -52,21 +58,22 @@ following shell commands:
"Couldn't detect what branch you're on. Is Doom detached?")))
;; We assume that a dirty .emacs.d is intentional and abort
(when (doom--working-tree-dirty-p default-directory)
(when-let (dirty (doom--working-tree-dirty-p default-directory))
(if (not force-p)
(user-error! "%s\n\n%s"
(user-error! "%s\n\n%s\n\n %s"
(format "Refusing to upgrade because %S has been modified." (path doom-emacs-dir))
"Either stash/undo your changes or run 'doom upgrade -f' to discard local changes.")
"Either stash/undo your changes or run 'doom upgrade -f' to discard local changes."
(string-join dirty "\n"))
(print! (info "You have local modifications in Doom's source. Discarding them..."))
(doom-call-process "git" "reset" "--hard" (format "origin/%s" branch))
(doom-call-process "git" "clean" "-ffd")))
(doom-call-process "git" "remote" "remove" doom-repo-remote)
(unwind-protect
(progn
(let (result)
(or (zerop (car (doom-call-process "git" "remote" "add" doom-repo-remote doom-repo-url)))
(error "Failed to add %s to remotes" doom-repo-remote))
(or (zerop (car (doom-call-process "git" "fetch" "--tags" doom-repo-remote branch)))
(or (zerop (car (setq result (doom-call-process "git" "fetch" "--tags" doom-repo-remote branch))))
(error "Failed to fetch from upstream"))
(let ((this-rev (vc-git--rev-parse "HEAD"))
@ -99,13 +106,11 @@ following shell commands:
(print! (start "Upgrading Doom Emacs..."))
(print-group!
(doom-clean-byte-compiled-files)
(unless (and (zerop (car (doom-call-process "git" "reset" "--hard" target-remote)))
(equal (vc-git--rev-parse "HEAD") new-rev))
(if (and (zerop (car (doom-call-process "git" "reset" "--hard" target-remote)))
(equal (vc-git--rev-parse "HEAD") new-rev))
(print! (info "%s") (cdr result))
(error "Failed to check out %s" (substring new-rev 0 10)))
(print! (success "Finished upgrading Doom Emacs")))
(doom-cli-execute "refresh" (if auto-accept-p '("-y")))
t)
(print! (success "Done! Restart Emacs for changes to take effect."))))))
t)))))
(ignore-errors
(doom-call-process "git" "remote" "remove" doom-repo-remote))))))

View file

@ -1,14 +1,5 @@
;;; -*- lexical-binding: t; no-byte-compile: t; -*-
(require 'seq)
;; Eagerly load these libraries because we may be in a session that hasn't been
;; fully initialized (e.g. where autoloads files haven't been generated or
;; `load-path' populated).
(mapc (doom-rpartial #'load nil (not doom-debug-mode) 'nosuffix)
(file-expand-wildcards (concat doom-core-dir "autoload/*.el")))
;;
;;; Variables
@ -17,6 +8,9 @@
commands like `doom-cli-packages-install', `doom-cli-packages-update' and
`doom-packages-autoremove'.")
(defvar doom-auto-discard (getenv "FORCE")
"If non-nil, discard all local changes while updating.")
(defvar doom--cli-p nil)
(defvar doom--cli-commands (make-hash-table :test 'equal))
(defvar doom--cli-groups (make-hash-table :test 'equal))
@ -187,13 +181,14 @@ BODY will be run when this dispatcher is called."
:plist plist
:fn
(lambda (--alist--)
(ignore --alist--)
(let ,(cl-loop for opt in speclist
for optsym = (if (listp opt) (car opt) opt)
unless (memq optsym cl--lambda-list-keywords)
collect (list optsym `(cdr (assq ',optsym --alist--))))
,@(unless (plist-get plist :bare)
'((unless doom-init-p
(doom-initialize 'force)
(doom-initialize 'force 'noerror)
(doom-initialize-modules))))
,@body)))
doom--cli-commands)
@ -209,15 +204,127 @@ BODY will be run when this dispatcher is called."
,@body))
;;
;;; Straight hacks
(defvar doom--cli-straight-discard-options
'("^Delete remote \"[^\"]+\", re-create it with correct "
"^Reset branch "
"^Abort merge$"
"^Discard changes$"))
;; HACK Remove dired & magit options from prompt, since they're inaccessible in
;; noninteractive sessions.
(advice-add #'straight-vc-git--popup-raw :override #'straight--popup-raw)
;; HACK Replace GUI popup prompts (which hang indefinitely in tty Emacs) with
;; simple prompts.
(defadvice! doom--straight-fallback-to-y-or-n-prompt-a (orig-fn &optional prompt)
:around #'straight-are-you-sure
(or doom-auto-accept
(if noninteractive
(y-or-n-p (format! "%s" (or prompt "")))
(funcall orig-fn prompt))))
(defadvice! doom--straight-fallback-to-tty-prompt-a (orig-fn prompt actions)
"Modifies straight to prompt on the terminal when in noninteractive sessions."
:around #'straight--popup-raw
(if (not noninteractive)
(funcall orig-fn prompt actions)
;; We can't intercept C-g, so no point displaying any options for this key
;; when C-c is the proper way to abort batch Emacs.
(delq! "C-g" actions 'assoc)
;; HACK These are associated with opening dired or magit, which isn't
;; possible in tty Emacs, so...
(delq! "e" actions 'assoc)
(delq! "g" actions 'assoc)
(if doom-auto-discard
(cl-loop with doom-auto-accept = t
for (_key desc func) in actions
when desc
when (cl-find-if (doom-rpartial #'string-match-p desc)
doom--cli-straight-discard-options)
return (funcall func))
(print! (start "%s") (red prompt))
(print-group!
(terpri)
(let (options)
(print-group!
(print! " 1) Abort")
(cl-loop for (_key desc func) in actions
when desc
do (push func options)
and do
(print! "%2s) %s" (1+ (length options))
(if (cl-find-if (doom-rpartial #'string-match-p desc)
doom--cli-straight-discard-options)
(concat desc " (Recommended)")
desc))))
(terpri)
(let* ((options
(cons (lambda ()
(let ((doom-format-indent 0))
(terpri)
(print! (warn "Aborted")))
(kill-emacs 1))
(nreverse options)))
(prompt
(format! "How to proceed? (%s) "
(mapconcat #'number-to-string
(number-sequence 1 (length options))
", ")))
answer fn)
(while (null (nth (setq answer (1- (read-number prompt)))
options))
(print! (warn "%s is not a valid answer, try again.")
answer))
(funcall (nth answer options))))))))
(defadvice! doom--straight-respect-print-indent-a (args)
"Indent straight progress messages to respect `doom-format-indent', so we
don't have to pass whitespace to `straight-use-package's fourth argument
everywhere we use it (and internally)."
:filter-args #'straight-use-package
(cl-destructuring-bind
(melpa-style-recipe &optional no-clone no-build cause interactive)
args
(list melpa-style-recipe no-clone no-build
(if (and (not cause)
(boundp 'doom-format-indent)
(> doom-format-indent 0))
(make-string (1- (or doom-format-indent 1)) 32)
cause)
interactive)))
;;
;;; Dependencies
(require 'seq)
;; Eagerly load these libraries because we may be in a session that hasn't been
;; fully initialized (e.g. where autoloads files haven't been generated or
;; `load-path' populated).
(load! "autoload/cli")
(load! "autoload/debug")
(load! "autoload/files")
(load! "autoload/format")
(load! "autoload/plist")
;;
;;; CLI Commands
(load! "cli/help")
(load! "cli/install")
(defcli! (refresh re)
((if-necessary-p ["-n" "--if-necessary"] "Only regenerate autoloads files if necessary"))
"Ensure Doom is properly set up.
(defcligroup! "Maintenance"
"For managing your config and packages"
(defcli! (sync s refresh re)
((if-necessary-p ["-n" "--if-necessary"] "Only regenerate autoloads files if necessary")
(inhibit-envvar-p ["-e"] "Don't regenerate the envvar file")
(prune-p ["-p" "--prune"] "Purge orphaned packages & regraft repos"))
"Synchronize your config with Doom Emacs.
This is the equivalent of running autoremove, install, autoloads, then
recompile. Run this whenever you:
@ -230,22 +337,34 @@ recompile. Run this whenever you:
It will ensure that unneeded packages are removed, all needed packages are
installed, autoloads files are up-to-date and no byte-compiled files have gone
stale."
(print! (green "Initiating a refresh of Doom Emacs...\n"))
(let (success)
(when (file-exists-p doom-env-file)
(doom-cli-reload-env-file 'force))
(doom-cli-reload-core-autoloads (not if-necessary-p))
(unwind-protect
(progn
(and (doom-cli-packages-install)
(setq success t))
(and (doom-cli-packages-build)
(setq success t))
(and (doom-cli-packages-purge nil 'builds-p nil)
(setq success t)))
(doom-cli-reload-package-autoloads (or success (not if-necessary-p)))
(doom-cli-byte-compile nil 'recompile))
t))
:bare t
(let (success)
;; Ensures that no pre-existing state pollutes the generation of the new
;; autoloads files.
(dolist (file (list doom-autoload-file doom-package-autoload-file))
(delete-file file)
(delete-file (byte-compile-dest-file file)))
(doom-initialize 'force 'noerror)
(doom-initialize-modules)
(print! (start "Synchronizing your config with Doom Emacs..."))
(print-group!
(when (and (not inhibit-envvar-p)
(file-exists-p doom-env-file))
(doom-cli-reload-env-file 'force))
(doom-cli-reload-core-autoloads)
(doom-cli-packages-install)
(doom-cli-packages-build)
(doom-cli-packages-purge prune-p 'builds-p prune-p prune-p)
(doom-cli-reload-package-autoloads)
t)))
(load! "cli/env")
(load! "cli/upgrade")
(load! "cli/packages")
(load! "cli/autoloads"))
(defcligroup! "Diagnostics"
"For troubleshooting and diagnostics"
@ -253,13 +372,6 @@ stale."
(load! "cli/debug")
(load! "cli/test"))
(defcligroup! "Maintenance"
"For managing your config and packages"
(load! "cli/env")
(load! "cli/upgrade")
(load! "cli/packages")
(load! "cli/autoloads"))
(defcligroup! "Compilation"
"For compiling Doom and your config"
(load! "cli/byte-compile"))

View file

@ -12,11 +12,14 @@ successfully sets indent_style/indent_size.")
(defvar-local doom-large-file-p nil)
(put 'doom-large-file-p 'permanent-local t)
(defvar doom-large-file-size 1
"The threshold above which Doom enables emergency optimizations.
(defvar doom-large-file-size-alist '(("." . 1.0))
"An alist mapping regexps (like `auto-mode-alist') to filesize thresholds.
This threshold is in MB. See `doom--optimize-for-large-files-a' for
implementation details.")
If a file is opened and discovered to be larger than the threshold, Doom
performs emergency optimizations to prevent Emacs from hanging, crashing or
becoming unusably slow.
These thresholds are in MB, and is used by `doom--optimize-for-large-files-a'.")
(defvar doom-large-file-excluded-modes
'(so-long-mode special-mode archive-mode tar-mode jka-compr
@ -31,7 +34,7 @@ implementation details.")
(defadvice! doom--optimize-for-large-files-a (orig-fn &rest args)
"Set `doom-large-file-p' if the file is too large.
Uses `doom-large-file-size' to determine when a file is too large. When
Uses `doom-large-file-size-alist' to determine when a file is too large. When
`doom-large-file-p' is set, other plugins can detect this and reduce their
runtime costs (or disable themselves) to ensure the buffer is as fast as
possible."
@ -39,19 +42,24 @@ possible."
(if (setq doom-large-file-p
(and buffer-file-name
(not doom-large-file-p)
(file-readable-p buffer-file-name)
(> (nth 7 (file-attributes buffer-file-name))
(* 1024 1024 doom-large-file-size))))
(file-exists-p buffer-file-name)
(ignore-errors
(> (nth 7 (file-attributes buffer-file-name))
(* 1024 1024
(assoc-default buffer-file-name doom-large-file-size-alist
#'string-match-p))))))
(prog1 (apply orig-fn args)
(if (memq major-mode doom-large-file-excluded-modes)
(setq doom-large-file-p nil)
(so-long-minor-mode +1)
(when (fboundp 'so-long-minor-mode) ; in case the user disabled it
(so-long-minor-mode +1))
(message "Large file detected! Cutting a few corners to improve performance...")))
(apply orig-fn args)))
;; Resolve symlinks when opening files, so that any operations are conducted
;; from the file's true directory (like `find-file').
(setq find-file-visit-truename t)
(setq find-file-visit-truename t
vc-follow-symlinks t)
;; Disable the warning "X and Y are the same file". It's fine to ignore this
;; warning as it will redirect you to the existing buffer anyway.
@ -123,16 +131,14 @@ possible."
;;
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
;; Save clipboard contents into kill-ring before replacing them
(setq save-interprogram-paste-before-kill t)
;; Fixes the clipboard in tty Emacs by piping clipboard I/O through xclip, xsel,
;; pb{copy,paste}, wl-copy, termux-clipboard-get, or getclip (cygwin).
(add-hook! 'tty-setup-hook
(defun doom-init-clipboard-in-tty-emacs-h ()
(and (not (getenv "SSH_CONNECTION"))
(require 'xclip nil t)
(xclip-mode +1))))
(unless IS-WINDOWS
(add-hook! 'tty-setup-hook
(defun doom-init-clipboard-in-tty-emacs-h ()
(and (not (getenv "SSH_CONNECTION"))
(require 'xclip nil t)
(xclip-mode +1)))))
;;
@ -140,6 +146,7 @@ possible."
(push '("/LICENSE\\'" . text-mode) auto-mode-alist)
(push '("\\.log\\'" . text-mode) auto-mode-alist)
(push '("\\.env\\'" . sh-mode) auto-mode-alist)
;;
@ -188,17 +195,14 @@ possible."
(not (file-remote-p file)))
(file-truename file)
file))
(setq recentf-filename-handlers '(doom--recent-file-truename abbreviate-file-name))
(setq recentf-save-file (concat doom-cache-dir "recentf")
(setq recentf-filename-handlers
'(substring-no-properties
doom--recent-file-truename
abbreviate-file-name)
recentf-save-file (concat doom-cache-dir "recentf")
recentf-auto-cleanup 'never
recentf-max-menu-items 0
recentf-max-saved-items 200
recentf-exclude
(list "\\.\\(?:gz\\|gif\\|svg\\|png\\|jpe?g\\)$" "^/tmp/" "^/ssh:"
"\\.?ido\\.last$" "\\.revive$" "/TAGS$" "^/var/folders/.+$"
;; ignore private DOOM temp files
(concat "^" (recentf-apply-filename-handlers doom-local-dir))))
recentf-max-saved-items 200)
(add-hook! '(doom-switch-window-hook write-file-functions)
(defun doom--recentf-touch-buffer-h ()
@ -250,6 +254,11 @@ possible."
:after-while #'save-place-find-file-hook
(if buffer-file-name (ignore-errors (recenter))))
(defadvice! doom--inhibit-saveplace-in-long-files-a (orig-fn &rest args)
:around #'save-place-to-alist
(unless doom-large-file-p
(apply orig-fn args)))
(defadvice! doom--dont-prettify-saveplace-cache-a (orig-fn)
"`save-place-alist-to-file' uses `pp' to prettify the contents of its cache.
`pp' can be expensive for longer lists, and there's no reason to prettify cache
@ -265,6 +274,7 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(use-package! server
:when (display-graphic-p)
:after-call pre-command-hook after-find-file focus-out-hook
:defer 1
:init
(when-let (name (getenv "EMACS_SERVER_NAME"))
(setq server-name name))
@ -358,6 +368,10 @@ files, so we replace calls to `pp' with the much faster `prin1'."
:around #'dtrt-indent-mode
(let ((dtrt-indent-run-after-smie dtrt-indent-run-after-smie))
(cl-letf* ((old-smie-config-guess (symbol-function 'smie-config-guess))
(old-smie-config--guess (symbol-function 'symbol-config--guess))
((symbol-function 'symbol-config--guess)
(lambda (beg end)
(funcall old-smie-config--guess beg (min end 10000))))
((symbol-function 'smie-config-guess)
(lambda ()
(condition-case e (funcall old-smie-config-guess)
@ -372,12 +386,11 @@ files, so we replace calls to `pp' with the much faster `prin1'."
;; a better *help* buffer
:commands helpful--read-symbol
:init
(define-key!
[remap describe-function] #'helpful-callable
[remap describe-command] #'helpful-command
[remap describe-variable] #'helpful-variable
[remap describe-key] #'helpful-key
[remap describe-symbol] #'doom/describe-symbol)
(global-set-key [remap describe-function] #'helpful-callable)
(global-set-key [remap describe-command] #'helpful-command)
(global-set-key [remap describe-variable] #'helpful-variable)
(global-set-key [remap describe-key] #'helpful-key)
(global-set-key [remap describe-symbol] #'helpful-symbol)
(defun doom-use-helpful-a (orig-fn &rest args)
"Force ORIG-FN to use helpful instead of the old describe-* commands."
@ -413,23 +426,25 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(require 'smartparens-config)
;; Overlays are too distracting and not terribly helpful. show-parens does
;; this for us already, so...
;; this for us already (and is faster), so...
(setq sp-highlight-pair-overlay nil
sp-highlight-wrap-overlay nil
sp-highlight-wrap-tag-overlay nil)
;; But if someone does want overlays enabled, evil users will be stricken with
;; an off-by-one issue where smartparens assumes you're outside the pair when
;; you're really at the last character in insert mode. We must correct this
;; vile injustice.
(setq sp-show-pair-from-inside t)
;; ...and stay highlighted until we've truly escaped the pair!
(setq sp-cancel-autoskip-on-backward-movement nil)
(with-eval-after-load 'evil
;; But if someone does want overlays enabled, evil users will be stricken
;; with an off-by-one issue where smartparens assumes you're outside the
;; pair when you're really at the last character in insert mode. We must
;; correct this vile injustice.
(setq sp-show-pair-from-inside t)
;; ...and stay highlighted until we've truly escaped the pair!
(setq sp-cancel-autoskip-on-backward-movement nil))
;; The default is 100, because smartparen's scans are relatively expensive
;; (especially with large pair lists for somoe modes), we halve it, as a
;; (especially with large pair lists for some modes), we reduce it, as a
;; better compromise between performance and accuracy.
(setq sp-max-prefix-length 50)
;; This speeds up smartparens. No pair has any business being longer than 4
;; characters; if they must, the modes that need it set it buffer-locally.
(setq sp-max-prefix-length 25)
;; No pair has any business being longer than 4 characters; if they must, set
;; it buffer-locally. It's less work for smartparens.
(setq sp-max-pair-length 4)
;; This isn't always smart enough to determine when we're in a string or not.
;; See https://github.com/Fuco1/smartparens/issues/783.
@ -437,13 +452,13 @@ files, so we replace calls to `pp' with the much faster `prin1'."
;; Silence some harmless but annoying echo-area spam
(dolist (key '(:unmatched-expression :no-matching-tag))
(setf (cdr (assq key sp-message-alist)) nil))
(setf (alist-get key sp-message-alist) nil))
(add-hook! 'minibuffer-setup-hook
(defun doom-init-smartparens-in-minibuffer-maybe-h ()
"Enable `smartparens-mode' in the minibuffer, during `eval-expression' or
`evil-ex'."
(when (memq this-command '(eval-expression evil-ex))
"Enable `smartparens-mode' in the minibuffer, during `eval-expression',
`pp-eval-expression' or `evil-ex'."
(when (memq this-command '(eval-expression pp-eval-expression evil-ex))
(smartparens-mode))))
;; You're likely writing lisp in the minibuffer, therefore, disable these
@ -481,6 +496,10 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(delq! 'buffer-read-only so-long-variable-overrides 'assq)
;; ...but at least reduce the level of syntax highlighting
(add-to-list 'so-long-variable-overrides '(font-lock-maximum-decoration . 1))
;; ...and insist that save-place not operate in large/long files
(add-to-list 'so-long-variable-overrides '(save-place-alist . nil))
;; Text files could possibly be too long too
(add-to-list 'so-long-target-modes 'text-mode)
;; But disable everything else that may be unnecessary/expensive for large
;; or wide buffers.
(appendq! so-long-minor-modes
@ -494,14 +513,26 @@ files, so we replace calls to `pp' with the much faster `prin1'."
auto-composition-mode
undo-tree-mode
highlight-indent-guides-mode
hl-fill-column-mode)))
hl-fill-column-mode))
(defun doom-buffer-has-long-lines-p ()
;; HACK Fix #2183: `so-long-detected-long-line-p' tries to parse comment
;; syntax, but in some buffers comment state isn't initialized, leading
;; to a wrong-type-argument: stringp error.
(let ((so-long-skip-leading-comments (bound-and-true-p comment-use-syntax)))
;; HACK If visual-line-mode is on in a text-mode, then long lines are
;; normal and can be ignored.
(unless (and visual-line-mode (derived-mode-p 'text-mode))
(so-long-detected-long-line-p))))
(setq so-long-predicate #'doom-buffer-has-long-lines-p))
(use-package! undo-tree
;; Branching & persistent undo
:after-call doom-switch-buffer-hook after-find-file
:config
(setq undo-tree-auto-save-history t
(setq undo-tree-visualizer-diff t
undo-tree-auto-save-history t
undo-tree-enable-undo-in-region t
;; Increase undo-limits by a factor of ten to avoid emacs prematurely
;; truncating the undo history and corrupting the tree. See
;; https://github.com/syl20bnr/spacemacs/issues/12110
@ -532,16 +563,18 @@ files, so we replace calls to `pp' with the much faster `prin1'."
(stringp (car item))
(setcar item (substring-no-properties (car item))))))
;; Undo-tree is too chatty about saving its history files. This doesn't
;; totally suppress it logging to *Messages*, it only stops it from appearing
;; in the echo-area.
(advice-add #'undo-tree-save-history :around #'doom-shut-up-a)
(global-undo-tree-mode +1))
(use-package! ws-butler
;; a less intrusive `delete-trailing-whitespaces' on save
:after-call after-find-file
:config
(appendq! ws-butler-global-exempt-modes
'(special-mode comint-mode term-mode eshell-mode))
(ws-butler-global-mode))
:config (ws-butler-global-mode +1))
(provide 'core-editor)
;;; core-editor.el ends here

View file

@ -93,6 +93,7 @@ Accepts the same arguments as `message'."
ARGS is a list of the last N arguments to pass to FUN. The result is a new
function which does the same as FUN, except that the last N arguments are fixed
at the values with which this function was called."
(declare (pure t) (side-effect-free t))
(lambda (&rest pre-args)
(apply fn (append pre-args args))))
@ -101,14 +102,18 @@ at the values with which this function was called."
;;; Sugars
(defmacro λ! (&rest body)
"Expands to (lambda () (interactive) ,@body)."
(declare (doc-string 1))
"Expands to (lambda () (interactive) ,@body).
A factory for quickly producing interaction commands, particularly for keybinds
or aliases."
(declare (doc-string 1) (pure t) (side-effect-free t))
`(lambda () (interactive) ,@body))
(defalias 'lambda! 'λ!)
(defun λ!! (command &optional arg)
"Expands to a command that interactively calls COMMAND with prefix ARG."
(declare (doc-string 1))
"Expands to a command that interactively calls COMMAND with prefix ARG.
A factory for quickly producing interactive, prefixed commands for keybinds or
aliases."
(declare (doc-string 1) (pure t) (side-effect-free t))
(lambda () (interactive)
(let ((current-prefix-arg arg))
(call-interactively command))))
@ -128,8 +133,62 @@ at the values with which this function was called."
(when-let (path (file!))
(directory-file-name (file-name-directory path))))
(defmacro after! (package &rest body)
"Evaluate BODY after PACKAGE have loaded.
PACKAGE is a symbol or list of them. These are package names, not modes,
functions or variables. It can be:
- An unquoted package symbol (the name of a package)
(after! helm BODY...)
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
and git-gutter have loaded)
(after! (magit git-gutter) BODY...)
- An unquoted, nested list of compound package lists, using any combination of
:or/:any and :and/:all
(after! (:or package-a package-b ...) BODY...)
(after! (:and package-a package-b ...) BODY...)
(after! (:and package-a (:or package-b package-c) ...) BODY...)
Without :or/:any/:and/:all, :and/:all are implied.
This is a wrapper around `eval-after-load' that:
1. Suppresses warnings for disabled packages at compile-time
2. No-ops for package that are disabled by the user (via `package!')
3. Supports compound package statements (see below)
4. Prevents eager expansion pulling in autoloaded macros all at once"
(declare (indent defun) (debug t))
(if (symbolp package)
(unless (memq package (bound-and-true-p doom-disabled-packages))
(list (if (or (not (bound-and-true-p byte-compile-current-file))
(require package nil 'noerror))
#'progn
#'with-no-warnings)
(let ((body (macroexp-progn body)))
`(if (featurep ',package)
,body
;; We intentionally avoid `with-eval-after-load' to prevent
;; eager macro expansion from pulling (or failing to pull) in
;; autoloaded macros/packages.
(eval-after-load ',package ',body)))))
(let ((p (car package)))
(cond ((not (keywordp p))
`(after! (:and ,@package) ,@body))
((memq p '(:or :any))
(macroexp-progn
(cl-loop for next in (cdr package)
collect `(after! ,next ,@body))))
((memq p '(:and :all))
(dolist (next (cdr package))
(setq body `((after! ,next ,@body))))
(car body))))))
(defmacro setq! (&rest settings)
"A stripped-down `customize-set-variable' with the syntax of `setq'."
"A stripped-down `customize-set-variable' with the syntax of `setq'.
Use this instead of `setq' when you know a variable has a custom setter (a :set
property in its `defcustom' declaration). This trigger setters. `setq' does
not."
(macroexp-progn
(cl-loop for (var val) on settings by 'cddr
collect `(funcall (or (get ',var 'custom-set) #'set)
@ -150,10 +209,6 @@ This is a variadic `cl-pushnew'."
"Append LISTS to SYM in place."
`(setq ,sym (append ,sym ,@lists)))
(defmacro nconcq! (sym &rest lists)
"Append LISTS to SYM by altering them in place."
`(setq ,sym (nconc ,sym ,@lists)))
(defmacro delq! (elt list &optional fetcher)
"`delq' ELT from LIST in-place.
@ -164,6 +219,15 @@ If FETCHER is a function, ELT is used as the key in LIST (an alist)."
elt)
,list)))
(defmacro letenv! (envvars &rest body)
"Lexically bind ENVVARS in BODY, like `let' but for `process-environment'."
(declare (indent 1))
`(let ((process-environment (copy-sequence process-environment)))
(dolist (var (list ,@(cl-loop for (var val) in envvars
collect `(cons ,var ,val))))
(setenv (car var) (cdr var)))
,@body))
(defmacro add-load-path! (&rest dirs)
"Add DIRS to `load-path', relative to the current file.
The current file is the file from which `add-to-load-path!' is used."
@ -203,13 +267,14 @@ If N and M = 1, there's no benefit to using this macro over `add-hook'.
This macro accepts, in order:
1. Optional properties :local and/or :append, which will make the hook
1. The mode(s) or hook(s) to add to. This is either an unquoted mode, an
unquoted list of modes, a quoted hook variable or a quoted list of hook
variables.
2. Optional properties :local and/or :append, which will make the hook
buffer-local or append to the list of hooks (respectively),
2. The hook(s) to be added to: either an unquoted mode, an unquoted list of
modes, a quoted hook variable or a quoted list of hook variables. If
unquoted, '-hook' will be appended to each symbol.
3. The function(s) to be added: this can be one function, a list thereof, a
list of `defun's, or body forms (implicitly wrapped in a closure).
3. The function(s) to be added: this can be one function, a quoted list
thereof, a list of `defun's, or body forms (implicitly wrapped in a
lambda).
\(fn HOOKS [:append :local] FUNCTIONS)"
(declare (indent (lambda (indent-point state)
@ -408,10 +473,27 @@ DOCSTRING and BODY are as in `defun'.
where-alist))
`(progn
(defun ,symbol ,arglist ,docstring ,@body)
,(when where-alist
`(dolist (targets (list ,@(nreverse where-alist)))
(dolist (target (cdr targets))
(advice-add target (car targets) #',symbol)))))))
(dolist (targets (list ,@(nreverse where-alist)))
(dolist (target (cdr targets))
(advice-add target (car targets) #',symbol))))))
(defmacro undefadvice! (symbol _arglist &optional docstring &rest body)
"Undefine an advice called SYMBOL.
This has the same signature as `defadvice!' an exists as an easy undefiner when
testing advice (when combined with `rotate-text').
\(fn SYMBOL ARGLIST &optional DOCSTRING &rest [WHERE PLACES...] BODY\)"
(declare (doc-string 3) (indent defun))
(let (where-alist)
(unless (stringp docstring)
(push docstring body))
(while (keywordp (car body))
(push `(cons ,(pop body) (doom-enlist ,(pop body)))
where-alist))
`(dolist (targets (list ,@(nreverse where-alist)))
(dolist (target (cdr targets))
(advice-remove target #',symbol)))))
(provide 'core-lib)
;;; core-lib.el ends here

View file

@ -13,8 +13,8 @@
(defconst doom-obsolete-modules
'((:feature (version-control (:emacs vc) (:ui vc-gutter))
(spellcheck (:tools flyspell))
(syntax-checker (:tools flycheck))
(spellcheck (:checkers spell))
(syntax-checker (:checkers syntax))
(evil (:editor evil))
(snippets (:editor snippets))
(file-templates (:editor file-templates))
@ -24,7 +24,9 @@
(debugger (:tools debugger)))
(:tools (rotate-text (:editor rotate-text))
(vterm (:term vterm))
(password-store (:tools pass)))
(password-store (:tools pass))
(flycheck (:checkers syntax))
(flyspell (:checkers spell)))
(:emacs (electric-indent (:emacs electric))
(hideshow (:editor fold))
(eshell (:term eshell))
@ -40,7 +42,7 @@
Each entry is a three-level tree. For example:
(:feature (version-control (:emacs vc) (:ui vc-gutter))
(spellcheck (:tools flyspell))
(spellcheck (:checkers spell))
(syntax-checker (:tools flycheck)))
This marks :feature version-control, :feature spellcheck and :feature
@ -76,6 +78,7 @@ non-nil."
(when (or force-p (not doom-init-modules-p))
(setq doom-init-modules-p t
doom-modules nil)
(load custom-file 'noerror 'nomessage)
(when (load! "init" doom-private-dir t)
(when doom-modules
(maphash (lambda (key plist)
@ -101,11 +104,10 @@ non-nil."
(defun doom-module-p (category module &optional flag)
"Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')."
(declare (pure t) (side-effect-free t))
(let ((plist (gethash (cons category module) doom-modules)))
(and plist
(or (null flag)
(memq flag (plist-get plist :flags)))
t)))
(when-let (plist (gethash (cons category module) doom-modules))
(or (null flag)
(and (memq flag (plist-get plist :flags))
t))))
(defun doom-module-get (category module &optional property)
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set."
@ -186,7 +188,8 @@ If ENABLED-ONLY, return nil if the containing module isn't enabled."
(cdr doom--current-module))
doom--current-module)
doom--current-module)
(doom-module-from-path (file!)))
(ignore-errors
(doom-module-from-path (file!))))
(let* ((file-name-handler-alist nil)
(path (file-truename (or path (file!)))))
(save-match-data
@ -332,14 +335,15 @@ This value is cached. If REFRESH-P, then don't use the cached value."
(defmacro doom! (&rest modules)
"Bootstraps DOOM Emacs and its modules.
If the first item in MODULES doesn't satisfy `keywordp', MODULES is evaluated,
otherwise, MODULES is a multiple-property list (a plist where each key can have
multiple, linear values).
The bootstrap process involves making sure the essential directories exist, core
packages are installed, `doom-autoload-file' is loaded, `doom-packages-file'
cache exists (and is loaded) and, finally, loads your private init.el (which
should contain your `doom!' block).
If the cache exists, much of this function isn't run, which substantially
reduces startup time.
The overall load order of Doom is as follows:
~/.emacs.d/init.el
@ -358,9 +362,10 @@ The overall load order of Doom is as follows:
Module load order is determined by your `doom!' block. See `doom-modules-dirs'
for a list of all recognized module trees. Order defines precedence (from most
to least)."
`(let ((modules ',modules))
(unless (keywordp (car modules))
(setq modules (eval modules t)))
`(let ((modules
,@(if (keywordp (car modules))
(list (list 'quote modules))
modules)))
(unless doom-modules
(setq doom-modules
(make-hash-table :test 'equal
@ -524,7 +529,7 @@ Module FLAGs are set in your config's `doom!' block, typically in
:config (default +flag1 -flag2)
CATEGORY and MODULE can be omitted When this macro is used from inside a module
(except your DOOMDIR, which is a special moduel). e.g. (featurep! +flag)"
(except your DOOMDIR, which is a special module). e.g. (featurep! +flag)"
(and (cond (flag (memq flag (doom-module-get category module :flags)))
(module (doom-module-p category module))
(doom--current-flags (memq category doom--current-flags))
@ -535,66 +540,16 @@ CATEGORY and MODULE can be omitted When this macro is used from inside a module
(memq category (doom-module-get (car module) (cdr module) :flags)))))
t))
(defmacro after! (package &rest body)
"Evaluate BODY after PACKAGE have loaded.
PACKAGE is a symbol or list of them. These are package names, not modes,
functions or variables. It can be:
- An unquoted package symbol (the name of a package)
(after! helm BODY...)
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
and git-gutter have loaded)
(after! (magit git-gutter) BODY...)
- An unquoted, nested list of compound package lists, using any combination of
:or/:any and :and/:all
(after! (:or package-a package-b ...) BODY...)
(after! (:and package-a package-b ...) BODY...)
(after! (:and package-a (:or package-b package-c) ...) BODY...)
Without :or/:any/:and/:all, :and/:all are implied.
This is a wrapper around `eval-after-load' that:
1. Suppresses warnings for disabled packages at compile-time
2. No-ops for package that are disabled by the user (via `package!')
3. Supports compound package statements (see below)
4. Prevents eager expansion pulling in autoloaded macros all at once"
(declare (indent defun) (debug t))
(if (symbolp package)
(unless (memq package (bound-and-true-p doom-disabled-packages))
(list (if (or (not (bound-and-true-p byte-compile-current-file))
(require package nil 'noerror))
#'progn
#'with-no-warnings)
(let ((body (macroexp-progn body)))
`(if (featurep ',package)
,body
;; We intentionally avoid `with-eval-after-load' to prevent
;; eager macro expansion from pulling (or failing to pull) in
;; autoloaded macros/packages.
(eval-after-load ',package ',body)))))
(let ((p (car package)))
(cond ((not (keywordp p))
`(after! (:and ,@package) ,@body))
((memq p '(:or :any))
(macroexp-progn
(cl-loop for next in (cdr package)
collect `(after! ,next ,@body))))
((memq p '(:and :all))
(dolist (next (cdr package))
(setq body `((after! ,next ,@body))))
(car body))))))
;; DEPRECATED
(defmacro def-package! (&rest args)
(make-obsolete 'def-package! 'use-package! "2.0.9")
(message "`def-package!' is renamed and is now deprecated; use `use-package!' instead")
(message "`def-package!' was renamed to `use-package!'; use that instead.")
`(use-package! ,@args))
(make-obsolete 'def-package! 'use-package! "2.0.9")
(defmacro def-package-hook! (&rest args)
(make-obsolete 'def-package-hook! 'use-package-hook! "2.0.9")
(message "`def-package-hook!' is renamed and is now deprecated; use `use-package-hook!' instead")
(message "`def-package-hook!' was renamed to `use-package-hook!'; use that instead.")
`(use-package-hook! ,@args))
(make-obsolete 'def-package-hook! 'use-package-hook! "2.0.9")
(provide 'core-modules)
;;; core-modules.el ends here

View file

@ -21,7 +21,7 @@
;;
;; + `bin/doom install`: a wizard that guides you through setting up Doom and
;; your private config for the first time.
;; + `bin/doom refresh`: your go-to command for making sure Doom is in optimal
;; + `bin/doom sync`: your go-to command for making sure Doom is in optimal
;; condition. It ensures all unneeded packages are removed, all needed ones
;; are installed, and all metadata associated with them is generated.
;; + `bin/doom upgrade`: upgrades Doom Emacs and your packages to the latest
@ -43,7 +43,7 @@
package's name as a symbol, and whose CDR is the plist supplied to its
`package!' declaration. Set by `doom-initialize-packages'.")
(defvar doom-core-packages '(straight use-package async)
(defvar doom-core-packages '(straight use-package)
"A list of packages that must be installed (and will be auto-installed if
missing) and shouldn't be deleted.")
@ -72,8 +72,7 @@ missing) and shouldn't be deleted.")
;; Ensure that, if we do need package.el, it is configured correctly. You really
;; shouldn't be using it, but it may be convenient for quick package testing.
(setq package--init-file-ensured t
package-enable-at-startup nil
(setq package-enable-at-startup nil
package-user-dir (concat doom-local-dir "elpa/")
package-gnupghome-dir (expand-file-name "gpg" package-user-dir)
;; I omit Marmalade because its packages are manually submitted rather
@ -84,6 +83,8 @@ missing) and shouldn't be deleted.")
("melpa" . ,(concat proto "://melpa.org/packages/"))
("org" . ,(concat proto "://orgmode.org/elpa/")))))
(advice-add #'package--ensure-init-file :override #'ignore)
;; Don't save `package-selected-packages' to `custom-file'
(defadvice! doom--package-inhibit-custom-file-a (&optional value)
:override #'package--save-selected-packages
@ -109,73 +110,17 @@ missing) and shouldn't be deleted.")
;; certain things to work (like magit and org), but we can deal with that
;; when we cross that bridge.
straight-vc-git-default-clone-depth 1
;; Straight's own emacsmirror mirror is a little smaller and faster.
straight-recipes-emacsmirror-use-mirror t
;; Prefix declarations are unneeded bulk added to our autoloads file. Best
;; we just don't have to deal with them at all.
autoload-compute-prefixes nil)
autoload-compute-prefixes nil
;; We handle it ourselves
straight-fix-org nil)
(defun doom--finalize-straight ()
(mapc #'funcall (delq nil (mapcar #'cdr straight--transaction-alist)))
(setq straight--transaction-alist nil))
;;; Getting straight to behave in batch mode
(when noninteractive
;; HACK Remove dired & magit options from prompt, since they're inaccessible
;; in noninteractive sessions.
(advice-add #'straight-vc-git--popup-raw :override #'straight--popup-raw))
;; HACK Replace GUI popup prompts (which hang indefinitely in tty Emacs) with
;; simple prompts.
(defadvice! doom--straight-fallback-to-y-or-n-prompt-a (orig-fn &optional prompt)
:around #'straight-are-you-sure
(if noninteractive
(y-or-n-p (format! "%s" (or prompt "")))
(funcall orig-fn prompt)))
(defadvice! doom--straight-fallback-to-tty-prompt-a (orig-fn prompt actions)
"Modifies straight to prompt on the terminal when in noninteractive sessions."
:around #'straight--popup-raw
(if (not noninteractive)
(funcall orig-fn prompt actions)
;; We can't intercept C-g, so no point displaying any options for this key
;; Just use C-c
(delq! "C-g" actions 'assoc)
;; HACK These are associated with opening dired or magit, which isn't
;; possible in tty Emacs, so...
(delq! "e" actions 'assoc)
(delq! "g" actions 'assoc)
(let ((options (list (lambda ()
(let ((doom-format-indent 0))
(terpri)
(print! (error "Aborted")))
(kill-emacs)))))
(print! (start "%s") (red prompt))
(terpri)
(print-group!
(print-group!
(print! " 1) Abort")
(dolist (action actions)
(cl-destructuring-bind (_key desc func) action
(when desc
(push func options)
(print! "%2s) %s" (length options) desc)))))
(terpri)
(let ((options (nreverse options))
answer fn)
(while
(not
(setq
fn (ignore-errors
(nth (1- (setq answer
(read-number
(format! "How to proceed? (%s) "
(mapconcat #'number-to-string
(number-sequence 1 (length options))
", ")))))
options))))
(print! (warn "%s is not a valid answer, try again.") answer))
(funcall fn))))))
(defadvice! doom--read-pinned-packages-a (orig-fn &rest args)
"Read from `doom-pinned-packages' on top of straight's lockfiles."
:around #'straight--lockfile-read-all
(append (apply orig-fn args)
(doom-package-pinned-list)))
;;
@ -190,7 +135,7 @@ This ensure `doom-packages' is populated, if isn't aren't already. Use this
before any of straight's or Doom's package management's API to ensure all the
necessary package metadata is initialized and available for them."
(unless doom-init-packages-p
(setq force-p t))
(setq force-p t))
(when (or force-p (not (bound-and-true-p package--initialized)))
(doom-log "Initializing package.el")
(require 'package)
@ -198,63 +143,69 @@ necessary package metadata is initialized and available for them."
(when (or force-p (not doom-packages))
(doom-log "Initializing straight")
(setq doom-init-packages-p t)
(unless (fboundp 'straight--reset-caches)
(doom-ensure-straight)
(require 'straight))
(straight--reset-caches)
(mapc #'straight-use-recipes doom-core-package-sources)
(straight-register-package
`(straight :type git :host github
:repo ,(format "%s/straight.el" straight-repository-user)
:files ("straight*.el")
:branch ,straight-repository-branch
:no-byte-compile t))
(doom-ensure-straight)
(mapc #'straight-use-package doom-core-packages)
(doom-log "Initializing doom-packages")
(setq doom-disabled-packages nil
doom-pinned-packages nil
doom-packages (doom-package-list))
(cl-loop for (pkg . plist) in doom-packages
for ignored = (plist-get plist :ignore)
for disabled = (plist-get plist :disable)
if disabled
do (cl-pushnew pkg doom-disabled-packages)
else if (not ignored)
do (with-demoted-errors "Package error: %s"
(straight-register-package
(if-let (recipe (plist-get plist :recipe))
(let ((plist (straight-recipes-retrieve pkg)))
`(,pkg ,@(doom-plist-merge recipe (cdr plist))))
pkg))))
(unless doom-interactive-mode
(add-hook 'kill-emacs-hook #'doom--finalize-straight))))
(dolist (package doom-packages)
(let ((name (car package)))
(with-plist! (cdr package) (recipe modules disable ignore pin)
(if ignore
(doom-log "Ignoring package %S" name)
(if (not disable)
(with-demoted-errors "Package error: %s"
(when recipe
(straight-override-recipe (cons name recipe)))
(straight-register-package name))
(doom-log "Disabling package %S" name)
(cl-pushnew name doom-disabled-packages)
;; Warn about disabled core packages
(when (cl-find :core modules :key #'car)
(print! (warn "%s\n%s")
(format "You've disabled %S" name)
(indent 2 (concat "This is a core package. Disabling it will cause errors, as Doom assumes\n"
"core packages are always available. Disable their minor-modes or hooks instead.")))))))))))
(defun doom-ensure-straight ()
"Ensure `straight' is installed and was compiled with this version of Emacs."
(defvar bootstrap-version)
(let* (;; Force straight to install into ~/.emacs.d/.local/straight instead of
;; ~/.emacs.d/straight by pretending `doom-local-dir' is our .emacs.d.
(user-emacs-directory straight-base-dir)
(bootstrap-file (doom-path straight-base-dir "straight/repos/straight.el/straight.el"))
(bootstrap-version 5))
(make-directory (doom-path straight-base-dir "straight/build") 'parents)
(unless (featurep 'straight)
(unless (or (require 'straight nil t)
(file-readable-p bootstrap-file))
(with-current-buffer
(url-retrieve-synchronously
(format "https://raw.githubusercontent.com/raxod502/straight.el/%s/install.el"
straight-repository-branch)
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil t))))
(unless (fboundp 'straight--reset-caches)
(defvar bootstrap-version)
(let* (;; Force straight to install into ~/.emacs.d/.local/straight instead of
;; ~/.emacs.d/straight by pretending `doom-local-dir' is our .emacs.d.
(user-emacs-directory straight-base-dir)
(bootstrap-file (doom-path straight-base-dir "straight/repos/straight.el/straight.el"))
(bootstrap-version 5))
(make-directory (doom-path straight-base-dir "straight/build") 'parents)
(or (require 'straight nil t)
(file-readable-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
(format "https://raw.githubusercontent.com/raxod502/straight.el/%s/install.el"
straight-repository-branch)
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil t))
(require 'straight))
(straight--reset-caches)
(setq straight-recipe-repositories nil
straight-recipe-overrides nil)
(mapc #'straight-use-recipes doom-core-package-sources)
(straight-register-package
`(straight :type git :host github
:repo ,(format "%s/straight.el" straight-repository-user)
:files ("straight*.el")
:branch ,straight-repository-branch
:no-byte-compile t)))
;;
;;; Module package macros
(cl-defmacro package!
(name &rest plist &key built-in recipe ignore _disable _freeze)
(name &rest plist &key built-in recipe ignore _pin _disable)
"Declares a package and how to install it (if applicable).
This macro is declarative and does not load nor install packages. It is used to
@ -266,31 +217,38 @@ Only use this macro in a module's packages.el file.
Accepts the following properties:
:recipe RECIPE
Takes a MELPA-style recipe (see `quelpa-recipe' in `quelpa' for an example);
for packages to be installed from external sources.
Specifies a straight.el recipe to allow you to acquire packages from external
sources. See https://github.com/raxod502/straight.el#the-recipe-format for
details on this recipe.
:disable BOOL
Do not install or update this package AND disable all of its `use-package!'
blocks.
and `after!' blocks.
:ignore FORM
Do not install this package.
:freeze FORM
Do not update this package if FORM is non-nil.
:built-in BOOL
Same as :ignore if the package is a built-in Emacs package. If set to
'prefer, will use built-in package if it is present.
:pin STR|nil
Pin this package to commit hash STR. Setting this to nil will unpin this
package if previously pinned.
:built-in BOOL|'prefer
Same as :ignore if the package is a built-in Emacs package. This is more to
inform help commands like `doom/help-packages' that this is a built-in
package. If set to 'prefer, the package will not be installed if it is
already provided by Emacs.
Returns t if package is successfully registered, and nil if it was disabled
elsewhere."
(declare (indent defun))
(when (and recipe (keywordp (car-safe recipe)))
(plist-put! plist :recipe `(quote ,recipe)))
;; :built-in t is basically an alias for :ignore (locate-library NAME)
(when built-in
(when (and (not ignore) (equal built-in '(quote prefer)))
(when (and (not ignore)
(equal built-in '(quote prefer)))
(setq built-in `(locate-library ,(symbol-name name) nil doom--initial-load-path)))
(plist-delete! plist :built-in)
(plist-put! plist :ignore built-in))
`(let* ((name ',name)
(plist (cdr (assq name doom-packages))))
;; Record what module this declaration was found in
(let ((module-list (plist-get plist :modules))
(module ',(doom-module-from-path)))
(unless (member module module-list)
@ -298,27 +256,31 @@ elsewhere."
(append module-list
(list module)
nil))))
;; Merge given plist with pre-existing one
(doplist! ((prop val) (list ,@plist) plist)
(unless (null val)
(plist-put! plist prop val)))
;; Some basic key validation; error if you're not using a valid key
(condition-case e
(cl-destructuring-bind
(&key _local-repo _files _flavor _no-build
_type _repo _host _branch _remote _nonrecursive _fork _depth)
(plist-get plist :recipe))
(when-let (recipe (plist-get plist :recipe))
(cl-destructuring-bind
(&key local-repo _files _flavor
_no-build _no-byte-compile _no-autoloads
_type _repo _host _branch _remote _nonrecursive _fork _depth)
recipe
;; Expand :local-repo from current directory
(when local-repo
(plist-put! plist :recipe
(plist-put recipe :local-repo
(expand-file-name local-repo ,(dir!)))))))
(error
(signal 'doom-package-error
(cons ,(symbol-name name)
(error-message-string e)))))
;; This is the only side-effect of this macro!
(setf (alist-get name doom-packages) plist)
(if (not (plist-get plist :disable)) t
(doom-log "Disabling package %S" name)
(cl-pushnew name doom-disabled-packages)
nil)))
(with-no-warnings
(not (plist-get plist :disable)))))
(defmacro disable-packages! (&rest packages)
"A convenience macro for disabling packages in bulk.
@ -327,5 +289,43 @@ Only use this macro in a module's (or your private) packages.el file."
(cl-loop for p in packages
collect `(package! ,p :disable t))))
(defmacro unpin! (&rest targets)
"Unpin packages in TARGETS.
This unpins packages, so that 'doom upgrade' downloads their latest version. It
can be used one of five ways:
+ To disable pinning wholesale: (unpin! t)
+ To unpin individual packages: (unpin! packageA packageB ...)
+ To unpin all packages in a group of modules: (unpin! :lang :tools ...)
+ To unpin packages in individual modules:
(unpin! (:lang python javascript) (:tools docker))
Or any combination of the above.
This macro should only be used from the user's private packages.el. No module
should use it!"
(if (memq t targets)
`(mapc (doom-rpartial #'doom-package-set :unpin t)
(mapcar #'car doom-packages))
(let (forms)
(dolist (target targets)
(cl-check-type target (or symbol keyword list))
(cond
((symbolp target)
(push `(doom-package-set ',target :unpin t) forms))
((or (keywordp target)
(listp target))
(cl-destructuring-bind (category . modules) (doom-enlist target)
(dolist (pkg doom-packages)
(let ((pkg-modules (plist-get (cdr pkg) :modules)))
(and (assq category pkg-modules)
(or (null modules)
(cl-loop for module in modules
if (member (cons category module) pkg-modules)
return t))
(push `(doom-package-set ',(car pkg) :unpin t) forms))))))))
(macroexp-progn forms))))
(provide 'core-packages)
;;; core-packages.el ends here

View file

@ -31,15 +31,11 @@ Emacs.")
:init
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
projectile-enable-caching doom-interactive-mode
projectile-known-projects-file (concat doom-cache-dir "projectile.projects")
projectile-require-project-root t
projectile-globally-ignored-files '(".DS_Store" "Icon " "TAGS")
projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o")
projectile-ignored-projects '("~/" "/tmp")
projectile-kill-buffers-filter 'kill-only-files
projectile-files-cache-expire 604800 ; expire after a week
projectile-sort-order 'recentf
projectile-use-git-grep t) ; use git-grep for text searches
projectile-known-projects-file (concat doom-cache-dir "projectile.projects")
projectile-ignored-projects '("~/" "/tmp"))
(global-set-key [remap evil-jump-to-tag] #'projectile-find-tag)
(global-set-key [remap find-tag] #'projectile-find-tag)
@ -47,6 +43,21 @@ Emacs.")
:config
(projectile-mode +1)
;; Projectile runs four functions to determine the root (in this order):
;;
;; + `projectile-root-local' -> consults the `projectile-project-root'
;; variable for an explicit path.
;; + `projectile-root-bottom-up' -> consults
;; `projectile-project-root-files-bottom-up'; searches from / to your
;; current directory for certain files (including .project and .git)
;; + `projectile-root-top-down' -> consults `projectile-project-root-files';
;; searches from the current directory down to / for certain project
;; markers, like package.json, setup.py, or Cargo.toml
;; + `projectile-root-top-down-recurring' -> consults
;; `projectile-project-root-files-top-down-recurring'; e.g. searches from
;; the current directory down to / for a directory that has Makefile but
;; doesn't have a parent with one of those files.
;;
;; In the interest of performance, we reduce the number of project root marker
;; files/directories projectile searches for when resolving the project root.
(setq projectile-project-root-files-bottom-up
@ -54,20 +65,14 @@ Emacs.")
".git") ; Git VCS root dir
(when (executable-find "hg")
'(".hg")) ; Mercurial VCS root dir
(when (executable-find "fossil")
'(".fslckout" ; Fossil VCS root dir
"_FOSSIL_")) ; Fossil VCS root DB on Windows
(when (executable-find "bzr")
'(".bzr")) ; Bazaar VCS root dir
(when (executable-find "darcs")
'("_darcs"))) ; Darcs VCS root dir
'(".bzr"))) ; Bazaar VCS root dir
;; This will be filled by other modules. We build this list manually so
;; projectile doesn't perform so many file checks every time it resolves
;; a project's root -- particularly when a file has no project.
projectile-project-root-files '("TAGS")
projectile-project-root-files-top-down-recurring '(".svn" "Makefile"))
projectile-project-root-files '()
projectile-project-root-files-top-down-recurring '("Makefile"))
;; a more generic project root file
(push (abbreviate-file-name doom-local-dir) projectile-globally-ignored-directories)
;; Disable commands that won't work, as is, and that Doom already provides a
@ -125,10 +130,11 @@ c) are not valid projectile projects."
;; that is significantly faster than git ls-files or find, and it respects
;; .gitignore. This is recommended in the projectile docs.
((executable-find doom-projectile-fd-binary)
(setq projectile-git-command (concat
doom-projectile-fd-binary
" . --color=never --type f -0 -H -E .git")
projectile-generic-command projectile-git-command
(setq projectile-generic-command
(format "%s . --color=never --type f -0 -H -E .git"
doom-projectile-fd-binary)
projectile-git-command projectile-generic-command
projectile-git-submodule-command nil
;; ensure Windows users get fd's benefits
projectile-indexing-method 'alien))
@ -138,25 +144,16 @@ c) are not valid projectile projects."
(concat "rg -0 --files --color=never --hidden"
(cl-loop for dir in projectile-globally-ignored-directories
concat (format " --glob '!%s'" dir)))
projectile-git-command projectile-generic-command
projectile-git-submodule-command nil
;; ensure Windows users get rg's benefits
projectile-indexing-method 'alien)
;; fix breakage on windows in git projects
(unless (executable-find "tr")
(setq projectile-git-submodule-command nil)))
projectile-indexing-method 'alien))
((not (executable-find "tr"))
;; Fix breakage on windows in git projects with submodules, since Windows
;; doesn't have tr
(IS-WINDOWS
(setq projectile-git-submodule-command nil)))
(defadvice! doom--projectile-cache-timers-a ()
"Persist `projectile-projects-cache-time' across sessions, so that
`projectile-files-cache-expire' checks won't reset when restarting Emacs."
:before #'projectile-serialize-cache
(projectile-serialize projectile-projects-cache-time doom-projectile-cache-timer-file))
;; Restore it
(when (file-readable-p doom-projectile-cache-timer-file)
(setq projectile-projects-cache-time
(projectile-unserialize doom-projectile-cache-timer-file)))
(defadvice! doom--projectile-default-generic-command-a (orig-fn &rest args)
"If projectile can't tell what kind of project you're in, it issues an error
when using many of projectile's command, e.g. `projectile-compile-command',
@ -171,12 +168,11 @@ the command instead."
;; Projectile root-searching functions can cause an infinite loop on TRAMP
;; connections, so disable them.
;; TODO Is this still necessary?
(defadvice! doom--projectile-locate-dominating-file-a (orig-fn file name)
(defadvice! doom--projectile-locate-dominating-file-a (file _name)
"Don't traverse the file system if on a remote connection."
:around #'projectile-locate-dominating-file
(when (and (stringp file)
(not (file-remote-p file nil t)))
(funcall orig-fn file name))))
:before-while #'projectile-locate-dominating-file
(and (stringp file)
(not (file-remote-p file nil t)))))
;;
@ -195,16 +191,15 @@ state are passed in.")
on-load
on-enter
on-exit)
"Define a project minor-mode named NAME (a symbol) and declare where and how
it is activated. Project modes allow you to configure 'sub-modes' for
major-modes that are specific to a folder, project structure, framework or
whatever arbitrary context you define. These project modes can have their own
settings, keymaps, hooks, snippets, etc.
"Define a project minor mode named NAME and where/how it is activated.
Project modes allow you to configure 'sub-modes' for major-modes that are
specific to a folder, project structure, framework or whatever arbitrary context
you define. These project modes can have their own settings, keymaps, hooks,
snippets, etc.
This creates NAME-hook and NAME-map as well.
A project can be enabled through .dir-locals.el too, by setting `doom-project'.
PLIST may contain any of these properties, which are all checked to see if NAME
should be activated. If they are *all* true, NAME is activated.

View file

@ -173,7 +173,12 @@ read-only or not file-visiting."
(setq hscroll-margin 2
hscroll-step 1
scroll-conservatively 10
;; Emacs spends too much effort recentering the screen if you scroll the
;; cursor more than N lines past window edges (where N is the settings of
;; `scroll-conservatively'). This is especially slow in larger files
;; during large-scale scrolling commands. If kept over 100, the window is
;; never automatically recentered.
scroll-conservatively 101
scroll-margin 0
scroll-preserve-screen-position t
;; Reduce cursor lag by a tiny bit by not auto-adjusting `window-vscroll'
@ -216,19 +221,21 @@ read-only or not file-visiting."
(setq confirm-nonexistent-file-or-buffer t)
(defadvice! doom--switch-to-fallback-buffer-maybe-a (orig-fn)
(defadvice! doom--switch-to-fallback-buffer-maybe-a (&rest _)
"Switch to `doom-fallback-buffer' if on last real buffer.
Advice for `kill-current-buffer'. If in a dedicated window, delete it. If there
are no real buffers left OR if all remaining buffers are visible in other
windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
`kill-current-buffer'."
:around #'kill-current-buffer
:before-until #'kill-current-buffer
(let ((buf (current-buffer)))
(cond ((window-dedicated-p)
(delete-window))
(delete-window)
t)
((eq buf (doom-fallback-buffer))
(message "Can't kill the fallback buffer."))
(message "Can't kill the fallback buffer.")
t)
((doom-real-buffer-p buf)
(if (and buffer-file-name
(buffer-modified-p buf)
@ -247,8 +254,8 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
(switch-to-buffer (doom-fallback-buffer)))
(unless (delq (selected-window) (get-buffer-window-list buf nil t))
(kill-buffer buf)))
(run-hooks 'buffer-list-update-hook)))
((funcall orig-fn)))))
(run-hooks 'buffer-list-update-hook))
t))))
;;
@ -270,40 +277,46 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
(setq frame-title-format '("%b Doom Emacs")
icon-title-format frame-title-format)
;; Don't resize emacs in steps, it looks weird.
;; Don't resize windows & frames in steps; it's prohibitive to prevent the user
;; from resizing it to exact dimensions, and looks weird.
(setq window-resize-pixelwise t
frame-resize-pixelwise t)
(unless EMACS27+ ; We already do this in early-init.el
;; Disable tool and scrollbars; Doom encourages keyboard-centric workflows, so
;; these are just clutter (the scrollbar also impacts Emacs' performance).
(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist))
(unless (assq 'menu-bar-lines default-frame-alist)
;; We do this in early-init.el too, but in case the user is on Emacs 26 we do
;; it here too: disable tool and scrollbars, as Doom encourages
;; keyboard-centric workflows, so these are just clutter (the scrollbar also
;; impacts performance).
(add-to-list 'default-frame-alist '(menu-bar-lines . 0))
(add-to-list 'default-frame-alist '(tool-bar-lines . 0))
(add-to-list 'default-frame-alist '(vertical-scroll-bars)))
;; Sets `ns-appearance' and `ns-transparent-titlebar' on GUI frames (and fixes
;; mismatching text color in the frame title)
(when IS-MAC
;; Curse Lion and its sudden but inevitable fullscreen mode!
;; NOTE Meaningless to railwaycat's emacs-mac build
(setq ns-use-native-fullscreen nil
;; Visit files opened outside of Emacs in existing frame, rather than a
;; new one
ns-pop-up-frames nil)
(setq ns-use-native-fullscreen nil)
;; Sets ns-transparent-titlebar and ns-appearance frame parameters as is
;; appropriate for the loaded theme.
;; Visit files opened outside of Emacs in existing frame, not a new one
(setq ns-pop-up-frames nil)
;; Sets `ns-transparent-titlebar' and `ns-appearance' frame parameters so
;; window borders will match the enabled theme.
(and (or (daemonp)
(display-graphic-p))
(require 'ns-auto-titlebar nil t)
(ns-auto-titlebar-mode +1))
(add-hook! 'after-make-frame-functions
(defun doom-init-menu-bar-in-gui-frames-h (frame)
"On MacOS, the menu bar isn't part of the frame. Disabling it makes MacOS
treat Emacs as a non-application window."
(when (display-graphic-p frame)
(set-frame-parameter frame 'menu-bar-lines 1)))))
;; HACK On MacOS, disabling the menu bar makes MacOS treat Emacs as a
;; non-application window -- which means it doesn't automatically capture
;; focus when it is started, among other things. We enable menu-bar-lines
;; there, but we still want it disabled in terminal frames because there
;; it activates an ugly menu bar.
(add-hook! '(window-setup-hook after-make-frame-functions)
(defun doom-init-menu-bar-in-gui-frames-h (&optional frame)
"Re-enable menu-bar-lines in GUI frames."
(when-let (frame (or frame (selected-frame)))
(when (display-graphic-p frame)
(set-frame-parameter frame 'menu-bar-lines 1))))))
;; The native border "consumes" a pixel of the fringe on righter-most splits,
;; `window-divider' does not. Available since Emacs 25.1.
@ -317,13 +330,15 @@ treat Emacs as a non-application window."
;; always avoid GUI
(setq use-dialog-box nil)
;; Don't display floating tooltips; display their contents in the echo-area.
(if (bound-and-true-p tooltip-mode) (tooltip-mode -1))
;; native linux tooltips are ugly
;; Don't display floating tooltips; display their contents in the echo-area,
;; because native tooltips are ugly.
(when (bound-and-true-p tooltip-mode)
(tooltip-mode -1))
;; ...especially on linux
(when IS-LINUX
(setq x-gtk-use-system-tooltips nil))
;; Favor vertical splits over horizontal ones
;; Favor vertical splits over horizontal ones. Screens are usually wide.
(setq split-width-threshold 160
split-height-threshold nil)
@ -332,7 +347,7 @@ treat Emacs as a non-application window."
;;; Minibuffer
;; Allow for minibuffer-ception. Sometimes we need another minibuffer command
;; _while_ we're in the minibuffer.
;; while we're in the minibuffer.
(setq enable-recursive-minibuffers t)
;; Show current key-sequence in minibuffer, like vim does. Any feedback after
@ -345,11 +360,6 @@ treat Emacs as a non-application window."
;; But don't let the minibuffer grow beyond this size
max-mini-window-height 0.15)
;; Disable help mouse-overs for mode-line segments (i.e. :help-echo text).
;; They're generally unhelpful and only add confusing visual clutter.
(setq mode-line-default-help-echo nil
show-help-function nil)
;; Typing yes/no is obnoxious when y/n will do
(fset #'yes-or-no-p #'y-or-n-p)
@ -406,19 +416,20 @@ treat Emacs as a non-application window."
(setq hl-line-sticky-flag nil
global-hl-line-sticky-flag nil)
;; Disable `hl-line' in evil-visual mode (temporarily). `hl-line' can make the
;; selection region harder to see while in evil visual mode.
(after! evil
(defvar doom-buffer-hl-line-mode nil)
(add-hook! 'evil-visual-state-entry-hook
(defun doom-disable-hl-line-h ()
(when hl-line-mode
(setq-local doom-buffer-hl-line-mode t)
(hl-line-mode -1))))
(add-hook! 'evil-visual-state-exit-hook
(defun doom-enable-hl-line-maybe-h ()
(when doom-buffer-hl-line-mode
(hl-line-mode +1))))))
;; Temporarily disable `hl-line' when selection is active, since it doesn't
;; serve much purpose when the selection is so much more visible.
(defvar doom-buffer-hl-line-mode nil)
(add-hook! '(evil-visual-state-entry-hook activate-mark-hook)
(defun doom-disable-hl-line-h ()
(when hl-line-mode
(setq-local doom-buffer-hl-line-mode t)
(hl-line-mode -1))))
(add-hook! '(evil-visual-state-exit-hook deactivate-mark-hook)
(defun doom-enable-hl-line-maybe-h ()
(when doom-buffer-hl-line-mode
(hl-line-mode +1)))))
(use-package! winner
@ -464,15 +475,23 @@ treat Emacs as a non-application window."
all-the-icons-wicon
all-the-icons-material
all-the-icons-alltheicon)
:init
(defadvice! doom--disable-all-the-icons-in-tty-a (orig-fn &rest args)
"Return a blank string in tty Emacs, which doesn't support multiple fonts."
:around '(all-the-icons-octicon all-the-icons-material
all-the-icons-faicon all-the-icons-fileicon
all-the-icons-wicon all-the-icons-alltheicon)
(if (display-multi-font-p)
(apply orig-fn args)
"")))
:config
(cond ((daemonp)
(defadvice! doom--disable-all-the-icons-in-tty-a (orig-fn &rest args)
"Return a blank string in tty Emacs, which doesn't support multiple fonts."
:around '(all-the-icons-octicon all-the-icons-material
all-the-icons-faicon all-the-icons-fileicon
all-the-icons-wicon all-the-icons-alltheicon)
(if (or (not after-init-time) (display-multi-font-p))
(apply orig-fn args)
"")))
((not (display-graphic-p))
(defadvice! doom--disable-all-the-icons-in-tty-a (&rest _)
"Return a blank string for tty users."
:override '(all-the-icons-octicon all-the-icons-material
all-the-icons-faicon all-the-icons-fileicon
all-the-icons-wicon all-the-icons-alltheicon)
""))))
;;;###package hide-mode-line-mode
(add-hook! '(completion-list-mode-hook Man-mode-hook)
@ -499,15 +518,19 @@ treat Emacs as a non-application window."
;;
;;; Line numbers
;; Explicitly define a width to reduce computation
(setq-default display-line-numbers-width 3)
;; line numbers in most modes
;; Show absolute line numbers for narrowed regions makes it easier to tell the
;; buffer is narrowed, and where you are, exactly.
(setq-default display-line-numbers-widen t)
;; Enable line numbers in most text-editing modes. We avoid
;; `global-display-line-numbers-mode' because there are many special and
;; temporary modes where we don't need/want them.
(add-hook! '(prog-mode-hook text-mode-hook conf-mode-hook)
#'display-line-numbers-mode)
(defun doom-enable-line-numbers-h () (display-line-numbers-mode +1))
(defun doom-disable-line-numbers-h () (display-line-numbers-mode -1))
;;
;;; Theme & font
@ -521,22 +544,30 @@ behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.")
(defun doom-init-fonts-h ()
"Loads `doom-font'."
(cond (doom-font
(cl-pushnew
(cons 'font
(cond ((stringp doom-font) doom-font)
((fontp doom-font) (font-xlfd-name doom-font))
((signal 'wrong-type-argument (list '(fontp stringp)
doom-font)))))
default-frame-alist
:key #'car :test #'eq))
((display-graphic-p)
(setq doom-font (face-attribute 'default :font)))))
(cond
(doom-font
(cl-pushnew
;; Avoiding `set-frame-font' because it does a lot of extra, expensive
;; work we can avoid by setting the font frame parameter instead.
(cons 'font
(cond ((stringp doom-font) doom-font)
((fontp doom-font) (font-xlfd-name doom-font))
((signal 'wrong-type-argument (list '(fontp stringp)
doom-font)))))
default-frame-alist
:key #'car :test #'eq))
((display-graphic-p)
;; We try our best to record your system font, so `doom-big-font-mode'
;; can still use it to compute a larger font size with.
(setq font-use-system-font t
doom-font (face-attribute 'default :font)))))
(defun doom-init-extra-fonts-h (&optional frame)
"Loads `doom-variable-pitch-font',`doom-serif-font' and `doom-unicode-font'."
(condition-case e
(with-selected-frame (or frame (selected-frame))
(when doom-font
(set-face-attribute 'fixed-pitch nil :font doom-font))
(when doom-serif-font
(set-face-attribute 'fixed-pitch-serif nil :font doom-serif-font))
(when doom-variable-pitch-font
@ -616,7 +647,21 @@ startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
;;
;;; Fixes/hacks
;; doesn't exist in terminal Emacs; we define it to prevent errors
;; Doom doesn't support `customize' and it never will. It's a clumsy interface
;; that sets variables at a time where it can be easily and unpredictably
;; overwritten. Configure things from your $DOOMDIR instead.
(dolist (sym '(customize-option customize-browse customize-group customize-face
customize-rogue customize-saved customize-apropos
customize-changed customize-unsaved customize-variable
customize-set-value customize-customized customize-set-variable
customize-apropos-faces customize-save-variable
customize-apropos-groups customize-apropos-options
customize-changed-options customize-save-customized))
(put sym 'disabled "Doom doesn't support `customize', configure Emacs from $DOOMDIR/config.el instead"))
(put 'customize-themes 'disabled "Set `doom-theme' or use `load-theme' in $DOOMDIR/config.el instead")
;; Doesn't exist in terminal Emacs, so we define it to prevent void-function
;; errors emitted from packages use it without checking for it first.
(unless (fboundp 'define-fringe-bitmap)
(fset 'define-fringe-bitmap #'ignore))

View file

@ -23,13 +23,18 @@
;; This is consulted on every `require', `load' and various path/io functions.
;; You get a minor speed up by nooping this.
(setq file-name-handler-alist nil)
(unless noninteractive
(setq file-name-handler-alist nil))
;; Restore `file-name-handler-alist', because it is needed for handling
;; encrypted or compressed files, among other things.
(defun doom-reset-file-handler-alist-h ()
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
(add-hook 'emacs-startup-hook #'doom-reset-file-handler-alist-h)
;; Load the bare necessities
(require 'core-lib)
(autoload 'doom-initialize-packages "core-packages")
;;
;;; Global variables
@ -49,10 +54,6 @@ DEBUG envvar will enable this at startup.")
(defvar doom-interactive-mode (not noninteractive)
"If non-nil, Emacs is in interactive mode.")
(defvar doom-gc-cons-threshold 16777216 ; 16mb
"The default value to use for `gc-cons-threshold'. If you experience freezing,
decrease this. If you experience stuttering, increase this.")
;;; Directories/files
(defconst doom-emacs-dir
(eval-when-compile (file-truename user-emacs-directory))
@ -115,7 +116,7 @@ This file is compiled from the autoloads files of all installed packages
combined.")
(defconst doom-env-file (concat doom-local-dir "env")
"The location of your envvar file, generated by `doom env refresh`.
"The location of your envvar file, generated by `doom env`.
This file contains environment variables scraped from your shell environment,
which is loaded at startup (if it exists). This is helpful if Emacs can't
@ -134,6 +135,9 @@ users).")
;;
;;; Emacs core configuration
;; lo', longer logs ahoy, so we may reliably locate lapses in doom's logic
(setq message-log-max 8192)
;; Reduce debug output, well, unless we've asked for it.
(setq debug-on-error doom-debug-mode
jka-compr-verbose doom-debug-mode)
@ -194,11 +198,12 @@ users).")
(when IS-WINDOWS
(setq abbreviated-home-dir "\\`'"))
;; Don't litter `doom-emacs-dir'
;; Don't litter `doom-emacs-dir'. We don't use `no-littering' because it's a
;; mote too opinionated for our needs.
(setq abbrev-file-name (concat doom-local-dir "abbrev.el")
async-byte-compile-log-file (concat doom-etc-dir "async-bytecomp.log")
bookmark-default-file (concat doom-etc-dir "bookmarks")
custom-file (concat doom-private-dir "init.el")
custom-file (concat doom-local-dir "custom.el")
custom-theme-directory (concat doom-private-dir "themes/")
desktop-dirname (concat doom-etc-dir "desktop")
desktop-base-file-name "autosave"
@ -210,7 +215,6 @@ users).")
tramp-auto-save-directory (concat doom-cache-dir "tramp-auto-save/")
tramp-backup-directory-alist backup-directory-alist
tramp-persistency-file-name (concat doom-cache-dir "tramp-persistency.el")
tramp-histfile-override (concat doom-cache-dir "tramp-histfile.el")
url-cache-directory (concat doom-cache-dir "url/")
url-configuration-directory (concat doom-etc-dir "url/")
gamegrid-user-score-file-directory (concat doom-etc-dir "games/"))
@ -227,7 +231,8 @@ users).")
;; Disable bidirectional text rendering for a modest performance boost. Of
;; course, this renders Emacs unable to detect/display right-to-left languages
;; (sorry!), but for us left-to-right language speakers/writers, it's a boon.
(setq-default bidi-display-reordering 'left-to-right)
(setq-default bidi-display-reordering 'left-to-right
bidi-paragraph-direction 'left-to-right)
;; Reduce rendering/line scan work for Emacs by not rendering cursors or regions
;; in non-focused windows.
@ -246,8 +251,8 @@ users).")
;; Don't ping things that look like domain names.
(setq ffap-machine-p-known 'reject)
;; Performance on Windows is considerably worse than elsewhere. We'll need
;; everything we can get.
;; Performance on Windows is considerably worse than elsewhere, especially if
;; WSL is involved. We'll need everything we can get.
(when IS-WINDOWS
;; Reduce the workload when doing file IO
(setq w32-get-true-file-attributes nil)
@ -257,39 +262,34 @@ users).")
;; been determined.
(setq inhibit-compacting-font-caches t))
;; Remove command line options that aren't relevant to our current OS; that
;; means less to process at startup.
;; Remove command line options that aren't relevant to our current OS; means
;; slightly less to process at startup.
(unless IS-MAC (setq command-line-ns-option-alist nil))
(unless IS-LINUX (setq command-line-x-option-alist nil))
;; Restore `file-name-handler-alist' because it is necessary for handling
;; encrypted or compressed files, among other things.
(defun doom-restore-file-name-handler-alist-h ()
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
(add-hook 'emacs-startup-hook #'doom-restore-file-name-handler-alist-h)
;; Delete files to trash on macOS, as an extra layer of precaution against
;; accidentally deleting wanted files.
(setq delete-by-moving-to-trash IS-MAC)
;; To speed up minibuffer commands (like helm and ivy), we defer garbage
;; collection while the minibuffer is active.
(defun doom-defer-garbage-collection-h ()
"Increase `gc-cons-threshold' to stave off garbage collection."
(setq gc-cons-threshold most-positive-fixnum))
;; Adopt a sneaky garbage collection strategy of waiting until idle time to
;; collect; staving off the collector while the user is working.
(when doom-interactive-mode
(add-transient-hook! 'pre-command-hook (gcmh-mode +1))
(with-eval-after-load 'gcmh
(setq gcmh-idle-delay 10
gcmh-verbose doom-debug-mode
gcmh-high-cons-threshold 16777216) ; 16mb
(add-hook 'focus-out-hook #'gcmh-idle-garbage-collect)))
(defun doom-restore-garbage-collection-h ()
"Restore `gc-cons-threshold' to a reasonable value so the GC can do its job."
;; Defer it so that commands launched immediately after will enjoy the
;; benefits.
(run-at-time
1 nil (lambda () (setq gc-cons-threshold doom-gc-cons-threshold))))
(add-hook 'minibuffer-setup-hook #'doom-defer-garbage-collection-h)
(add-hook 'minibuffer-exit-hook #'doom-restore-garbage-collection-h)
;; Not restoring these to their defaults will cause stuttering/freezes.
(add-hook 'emacs-startup-hook #'doom-restore-garbage-collection-h)
;; When Emacs loses focus seems like a great time to do some garbage collection
;; all sneaky breeky like, so we can return to a fresh(er) Emacs.
(add-hook 'focus-out-hook #'garbage-collect)
;; HACK `tty-run-terminal-initialization' is *tremendously* slow for some
;; reason. Disabling it completely could have many side-effects, so we
;; defer it until later.
(unless (display-graphic-p)
(advice-add #'tty-run-terminal-initialization :override #'ignore)
(add-hook! 'window-setup-hook
(defun doom-init-tty-h ()
(advice-remove #'tty-run-terminal-initialization #'ignore)
(tty-run-terminal-initialization (selected-frame) nil t))))
;;
@ -396,9 +396,7 @@ If this is a daemon session, load them all immediately instead."
;;; Bootstrap helpers
(defun doom-try-run-hook (hook)
"Run HOOK (a hook function), but handle errors better, to make debugging
issues easier.
"Run HOOK (a hook function) with better error handling.
Meant to be used with `run-hook-wrapped'."
(doom-log "Running doom hook: %s" hook)
(condition-case e
@ -421,27 +419,29 @@ If RETURN-P, return the message as a string instead of displaying it."
(setq doom-init-time
(float-time (time-subtract (current-time) before-init-time))))))
(defun doom-load-autoloads-file (file)
"Tries to load FILE (an autoloads file). Return t on success, throws an error
in interactive sessions, nil otherwise (but logs a warning)."
(defun doom-load-autoloads-file (file &optional noerror)
"Tries to load FILE (an autoloads file).
Return t on success, nil otherwise (but logs a warning)."
(condition-case e
(let (command-switch-alist)
(load (substring file 0 -3) 'noerror 'nomessage))
(load (substring file 0 -3) noerror 'nomessage)
((debug error)
(message "Autoload file error: %s -> %s" (file-name-nondirectory file) e)
nil)))
(defun doom-load-envvars-file (file &optional noerror)
"Read and set envvars from FILE."
"Read and set envvars from FILE.
If NOERROR is non-nil, don't throw an error if the file doesn't exist or is
unreadable. Returns the names of envvars that were changed."
(if (not (file-readable-p file))
(unless noerror
(signal 'file-error (list "Couldn't read envvar file" file)))
(let (environment)
(let (envvars environment)
(with-temp-buffer
(save-excursion
(insert "\n")
(insert-file-contents file))
(while (re-search-forward "\n *\\([^#= \n]*\\)=" nil t)
(push (match-string 1) envvars)
(push (buffer-substring
(match-beginning 1)
(1- (or (save-excursion
@ -450,24 +450,26 @@ in interactive sessions, nil otherwise (but logs a warning)."
(point-max))))
environment)))
(when environment
(setq-default
process-environment (nreverse environment)
exec-path (append (parse-colon-path (getenv "PATH"))
(list exec-directory))
shell-file-name (or (getenv "SHELL")
shell-file-name))
process-environment))))
(setq process-environment
(append (nreverse environment) process-environment)
exec-path
(if (member "PATH" envvars)
(append (split-string (getenv "PATH") path-separator t)
(list exec-directory))
exec-path)
shell-file-name
(if (member "SHELL" envvars)
(or (getenv "SHELL") shell-file-name)
shell-file-name))
envvars))))
(defun doom-initialize (&optional force-p)
(defun doom-initialize (&optional force-p noerror)
"Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil).
The bootstrap process involves making sure 1) the essential directories exist,
2) the core packages are installed, 3) `doom-autoload-file' and
`doom-package-autoload-file' exist and have been loaded, and 4) Doom's core
files are loaded.
If the cache exists, much of this function isn't run, which substantially
reduces startup time.
The bootstrap process ensures that the essential directories exist, all core
packages are installed, `doom-autoload-file' and `doom-package-autoload-file'
exist and are loaded, and that `core-packages' is auto-loaded when `package' or
`straight' are.
The overall load order of Doom is as follows:
@ -496,7 +498,9 @@ to least)."
load-path doom--initial-load-path
process-environment doom--initial-process-environment)
;; Load shell environment, optionally generated from 'doom env'
;; Load shell environment, optionally generated from 'doom env'. No need to
;; do so if we're in terminal Emacs, because Emacs will correctly inherit
;; your shell environment there.
(when (and (or (display-graphic-p)
(daemonp))
(file-exists-p doom-env-file))
@ -506,12 +510,12 @@ to least)."
(let (;; `doom-autoload-file' tells Emacs where to load all its functions
;; from. This includes everything in core/autoload/*.el and autoload
;; files in enabled modules.
(core-autoloads-p (doom-load-autoloads-file doom-autoload-file))
(core-autoloads-p (doom-load-autoloads-file doom-autoload-file noerror))
;; Loads `doom-package-autoload-file', which loads a concatenated
;; package autoloads file which caches `load-path', `auto-mode-alist',
;; `Info-directory-list', and `doom-disabled-packages'. A big
;; reduction in startup time.
(pkg-autoloads-p (doom-load-autoloads-file doom-package-autoload-file)))
(pkg-autoloads-p (doom-load-autoloads-file doom-package-autoload-file noerror)))
(if (and core-autoloads-p pkg-autoloads-p (not force-p))
;; In case we want to use package.el or straight via M-x
@ -522,12 +526,17 @@ to least)."
(require 'core-packages)
(doom-initialize-packages)))
;; Eagerly load these libraries because we may be in a session that hasn't been
;; fully initialized (e.g. where autoloads files haven't been generated or
;; `load-path' populated).
(mapc (doom-rpartial #'load nil (not doom-debug-mode) 'nosuffix)
(file-expand-wildcards (concat doom-core-dir "autoload/*.el")))
;; Create all our core directories to quell file errors
(dolist (dir (list doom-local-dir
doom-etc-dir
doom-cache-dir))
(unless (file-directory-p dir)
(make-directory dir 'parents)))
(mapc (doom-rpartial #'make-directory 'parents)
(list doom-local-dir
doom-etc-dir
doom-cache-dir))
;; Ensure the package management system (and straight) are ready for
;; action (and all core packages/repos are installed)
@ -535,13 +544,16 @@ to least)."
(doom-initialize-packages force-p))
(unless (or (and core-autoloads-p pkg-autoloads-p)
force-p
(not doom-interactive-mode))
noerror)
(unless core-autoloads-p
(warn "Your Doom core autoloads file is missing"))
(unless pkg-autoloads-p
(warn "Your package autoloads file is missing"))
(signal 'doom-autoload-error (list "Run `bin/doom refresh' to generate them"))))
(signal 'doom-autoload-error (list "Run `bin/doom refresh' to generate them")))
(when doom-interactive-mode
(add-hook 'window-setup-hook #'doom-display-benchmark-h 'append)
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler))))
t))
(defun doom-initialize-core ()

View file

@ -2,39 +2,46 @@
;;; core/packages.el
;; core.el
(package! dotenv-mode)
(package! auto-minor-mode)
(package! auto-minor-mode :pin "17cfa1b548")
(package! gcmh :pin "8867533a73")
;; core-ui.el
(package! all-the-icons)
(package! hide-mode-line)
(package! highlight-numbers)
(package! rainbow-delimiters)
(package! restart-emacs)
(package! all-the-icons :pin "1416f37984")
(package! hide-mode-line :pin "88888825b5")
(package! highlight-numbers :pin "8b4744c7f4")
(package! rainbow-delimiters :pin "5125f4e476")
(package! restart-emacs :pin "9aa90d3df9")
;; core-editor.el
(package! better-jumper)
(package! dtrt-indent)
(package! helpful)
(package! ns-auto-titlebar :ignore (not IS-MAC))
(package! pcre2el)
(package! smartparens)
(package! better-jumper :pin "6d240032ca")
(package! dtrt-indent :pin "48221c928b")
(package! helpful :pin "c54e9ddbd6")
(when IS-MAC
(package! ns-auto-titlebar :pin "1efc30d385"))
(package! pcre2el :pin "0b5b2a2c17")
(package! smartparens :pin "be8d5c9a63")
(package! so-long
:built-in 'prefer
:built-in 'prefer ; included in Emacs 27+
;; REVIEW so-long is slated to be published to ELPA eventually, but until then
;; I've created my own mirror for it because git.savannah.gnu.org runs on a
;; potato.
:recipe (:host github :repo "hlissner/emacs-so-long"))
(package! undo-tree
;; Version 0.6.5 is on ELPA which lacks a fix we need, so we install 0.6.6
;; from emacsmirror/undo-tree instead.
:recipe (:host github :repo "emacsmirror/undo-tree"))
(package! ws-butler)
(package! xclip)
;; I've created my own mirror for it because git.savannah.gnu.org runs
;; on a potato.
:recipe (:host github :repo "hlissner/emacs-so-long")
:pin "ed666b0716")
(package! undo-tree :pin "5b6df03781")
(package! ws-butler
;; Use my fork of ws-butler, which has a few choice improvements and
;; optimizations (the original has been abandoned).
:recipe (:host github :repo "hlissner/ws-butler")
:pin "e4430d3778")
(unless IS-WINDOWS
(package! xclip :pin "d022cf947d"))
;; core-projects.el
(package! projectile)
(package! projectile :pin "341150c0e7")
;; core-keybinds.el
(package! general)
(package! which-key)
(package! general :pin "f6e928622d")
(package! which-key :pin "7b068f3e95")
;; autoload/cache.el
(package! persistent-soft :pin "a1e0ddf2a1")

View file

@ -15,7 +15,7 @@ Before you doom yourself, there are a few things you should know:
give you clues about what is wrong.
3. Use `bin/doom upgrade` to update Doom. Doing it any other way may require
additional work. When in doubt, run `bin/doom refresh`.
additional work. When in doubt, run `bin/doom sync`.
4. Check out `bin/doom help` to see what else `bin/doom` can do (and it is
recommended you add ~/.emacs.d/bin to your PATH).

View file

@ -0,0 +1,53 @@
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
;; Place your private configuration here! Remember, you do not need to run 'doom
;; sync' after modifying this file!
;; Some functionality uses this to identify you, e.g. GPG configuration, email
;; clients, file templates and snippets.
(setq user-full-name "John Doe"
user-mail-address "john@doe.com")
;; Doom exposes five (optional) variables for controlling fonts in Doom. Here
;; are the three important ones:
;;
;; + `doom-font'
;; + `doom-variable-pitch-font'
;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for
;; presentations or streaming.
;;
;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd
;; font string. You generally only need these two:
(setq doom-font (font-spec :family "monospace" :size 14))
;; There are two ways to load a theme. Both assume the theme is installed and
;; available. You can either set `doom-theme' or manually load a theme with the
;; `load-theme' function. This is the default:
(setq doom-theme 'doom-one)
;; If you use `org' and don't want your org files in the default location below,
;; change `org-directory'. It must be set before org loads!
(setq org-directory "~/org/")
;; This determines the style of line numbers in effect. If set to `nil', line
;; numbers are disabled. For relative line numbers, set this to `relative'.
(setq display-line-numbers-type t)
;; Here are some additional functions/macros that could help you configure Doom:
;;
;; - `load!' for loading external *.el files relative to this one
;; - `use-package' for configuring packages
;; - `after!' for running code after a package has loaded
;; - `add-load-path!' for adding directories to the `load-path', relative to
;; this file. Emacs searches the `load-path' when you load packages with
;; `require' or `use-package'.
;; - `map!' for binding new keys
;;
;; To get information about any of these functions/macros, move the cursor over
;; the highlighted symbol at press 'K' (non-evil users must press 'C-c g k').
;; This will open documentation for it, including demos of how they are used.
;;
;; You can also try 'gd' (or 'C-c g d') to jump to their definition and see how
;; they are implemented.

View file

@ -0,0 +1,51 @@
;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el
;; To install a package with Doom you must declare them here, run 'doom sync' on
;; the command line, then restart Emacs for the changes to take effect.
;; Alternatively, use M-x doom/reload.
;;
;; WARNING: Disabling core packages listed in ~/.emacs.d/core/packages.el may
;; have nasty side-effects and is not recommended.
;; All of Doom's packages are pinned to a specific commit, and updated from
;; release to release. To un-pin all packages and live on the edge, do:
;(unpin! t)
;; ...but to unpin a single package:
;(unpin! pinned-package)
;; Use it to unpin multiple packages
;(unpin! pinned-package another-pinned-package)
;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror:
;(package! some-package)
;; To install a package directly from a particular repo, you'll need to specify
;; a `:recipe'. You'll find documentation on what `:recipe' accepts here:
;; https://github.com/raxod502/straight.el#the-recipe-format
;(package! another-package
; :recipe (:host github :repo "username/repo"))
;; If the package you are trying to install does not contain a PACKAGENAME.el
;; file, or is located in a subdirectory of the repo, you'll need to specify
;; `:files' in the `:recipe':
;(package! this-package
; :recipe (:host github :repo "username/repo"
; :files ("some-file.el" "src/lisp/*.el")))
;; If you'd like to disable a package included with Doom, for whatever reason,
;; you can do so here with the `:disable' property:
;(package! builtin-package :disable t)
;; You can override the recipe of a built in package without having to specify
;; all the properties for `:recipe'. These will inherit the rest of its recipe
;; from Doom or MELPA/ELPA/Emacsmirror:
;(package! builtin-package :recipe (:nonrecursive t))
;(package! builtin-package-2 :recipe (:repo "myfork/package"))
;; Specify a `:branch' to install a package from a particular branch or tag.
;; This is required for some packages whose default branch isn't 'master' (which
;; our package manager can't deal with; see raxod502/straight.el#279)
;(package! builtin-package :recipe (:branch "develop"))

View file

@ -3,7 +3,7 @@
(eval-and-compile
(setq doom-interactive-mode 'test)
(doom-initialize 'force)
(doom-initialize 'force 'noerror)
(require 'buttercup)
(setq split-width-threshold 0
split-height-threshold 0

View file

@ -101,12 +101,6 @@
(expect (appendq! list '(d e f))
:to-equal '(a b c d e f)))))
(describe "nconcq!"
(it "nconc's a list to a list symbol"
(let ((list '(a b c)))
(expect (nconcq! list '(d e f))
:to-equal '(a b c d e f)))))
(describe "delq!"
(it "delete's a symbol from a list"
(let ((list '(a b c)))

View file

@ -13,15 +13,15 @@
(setq doom-init-p nil))
(it "initializes once"
(expect (doom-initialize))
(expect (not (doom-initialize)))
(expect (not (doom-initialize)))
(expect (doom-initialize nil 'noerror))
(expect (not (doom-initialize nil 'noerror)))
(expect (not (doom-initialize nil 'noerror)))
(expect doom-init-p))
(it "initializes multiple times, if forced"
(expect (doom-initialize))
(expect (not (doom-initialize)))
(expect (doom-initialize 'force)))
(expect (doom-initialize nil 'noerror))
(expect (not (doom-initialize nil 'noerror)))
(expect (doom-initialize 'force 'noerror)))
(describe "package initialization"
(before-each
@ -29,18 +29,18 @@
(it "initializes packages if core autoload file doesn't exist"
(let ((doom-autoload-file "doesnotexist"))
(doom-initialize))
(expect (doom-initialize nil 'noerror))
(expect 'doom-initialize-packages :to-have-been-called))
(it "doesn't initialize packages if core autoload file was loaded"
(let ((doom-interactive-mode t))
(spy-on 'doom-load-autoloads-file :and-return-value t)
(doom-initialize)
(doom-initialize nil 'noerror)
(expect 'doom-load-autoloads-file :to-have-been-called-with doom-package-autoload-file)
(expect 'doom-initialize-packages :to-have-been-called)))
(it "initializes packages when forced"
(doom-initialize 'force)
(doom-initialize 'force 'noerror)
(expect 'doom-initialize-packages :to-have-been-called)))
(describe "autoloads files"
@ -49,15 +49,14 @@
(spy-on 'warn :and-return-value t))
(it "loads autoloads files"
(ignore-errors (doom-initialize))
(ignore-errors (doom-initialize nil 'noerror))
(expect 'doom-load-autoloads-file
:to-have-been-called-with doom-autoload-file)
(expect 'doom-load-autoloads-file
:to-have-been-called-with doom-package-autoload-file))
(it "throws doom-autoload-error in interactive session where autoload files don't exist"
(let ((doom-interactive-mode t)
(doom-autoload-file "doesnotexist")
(it "throws doom-autoload-error when autoload files don't exist"
(let ((doom-autoload-file "doesnotexist")
(doom-package-autoload-file "doesnotexist"))
(expect (doom-initialize) :to-throw 'doom-autoload-error)))))
@ -117,7 +116,7 @@
(it "returns the new value for `process-environment'"
(expect (doom-load-envvars-file doom-env-file)
:to-equal '("A=1" "B=2" "C=3")))
:to-have-same-items-as '("A" "B" "C")))
(it "alters environment variables"
(dolist (key '("A" "B" "C"))

View file

@ -5,11 +5,12 @@ This appendix serves as a reference on how to use Doom Emacs' standard library.
It is integrated into Helpful, in Doom.
* Table of Contents :TOC_3:
- [[#examples-for-dooms-core-library][Examples for Doom's core library]]
- [[#examples-for-dooms-library][Examples for Doom's library]]
- [[#core-lib][core-lib]]
- [[#add-hook][add-hook!]]
- [[#add-transient-hook][add-transient-hook!]]
- [[#after][after!]]
- [[#appendq][appendq!]]
- [[#custom-set-faces][custom-set-faces!]]
- [[#custom-theme-set-faces][custom-theme-set-faces!]]
- [[#defer-feature][defer-feature!]]
@ -19,21 +20,24 @@ It is integrated into Helpful, in Doom.
- [[#file-exists-p][file-exists-p!]]
- [[#lambda][lambda!]]
- [[#lambda-1][lambda!!]]
- [[#letenv][letenv!]]
- [[#load][load!]]
- [[#map][map!]]
- [[#package][package!]]
- [[#pushnew][pushnew!]]
- [[#prependq][prependq!]]
- [[#quiet][quiet!]]
- [[#remove-hook][remove-hook!]]
- [[#setq][setq!]]
- [[#setq-hook][setq-hook!]]
- [[#unsetq-hook][unsetq-hook!]]
- [[#use-package][use-package!]]
- [[#interesting-snippets][Interesting snippets]]
- [[#persist-emacs-initial-frame-size-across-sessions][Persist Emacs' initial frame size across sessions]]
- [[#center-emacs-initial-frame-with-a-fixed-size][Center Emacs' initial frame with a fixed size]]
- [[#persist-emacs-initial-frame-position-dimensions-andor-full-screen-state-across-sessions][Persist Emacs' initial frame position, dimensions and/or full-screen state across sessions]]
- [[#update-cursor-shape-under-terminal-emacs][Update cursor shape under terminal Emacs]]
* Examples for Doom's core library
* Examples for Doom's library
** core-lib
*** add-hook!
#+BEGIN_SRC elisp :eval no
@ -90,6 +94,26 @@ It is integrated into Helpful, in Doom.
(after! rustic ...)
(after! python ...)
#+END_SRC
*** appendq!
#+BEGIN_SRC elisp
(let ((x '(a b c)))
(appendq! x '(c d e))
x)
#+END_SRC
#+RESULTS:
: (a b c c d e)
#+BEGIN_SRC elisp
(let ((x '(a b c))
(y '(c d e))
(z '(f g)))
(appendq! x y z '(h))
x)
#+END_SRC
#+RESULTS:
: (a b c c d e f g h)
*** custom-set-faces!
#+BEGIN_SRC elisp :eval no
@ -214,8 +238,47 @@ It is integrated into Helpful, in Doom.
#+RESULTS:
: /home/hlissner/.emacs.d/LICENSE
*** TODO lambda!
*** TODO lambda!!
*** lambda!
#+BEGIN_SRC elisp :eval no
(map! "C-j" (lambda! (newline) (indent-according-to-mode)))
;; The `λ!' short-form alias exists. If you have the snippets module enabled and
;; Doom's default snippets, the 'lam' snippet will expand into 'λ!'. Otherwise,
;; you can use `lambda!'.
(map! "C-j" (λ! (newline) (indent-according-to-mode)))
#+END_SRC
*** lambda!!
When ~newline~ is passed a numerical prefix argument (=C-u 5 M-x newline=), it
inserts N newlines. We can use ~lambda!!~ to easily create a keybinds that bakes
in the prefix arg into the command call:
#+BEGIN_SRC elisp :eval no
(map! "C-j" (lambda!! #'newline 5))
;; The `λ!!' short-form alias exists. If you have the snippets module enabled
;; and Doom's default snippets, a 'lam' snippet is available to expand into
;; 'λ!'. Otherwise, you can use `lambda!!'.
(map! "C-j" (λ!! #'newline 5))
#+END_SRC
Or to create aliases for functions that behave differently:
#+BEGIN_SRC elisp :eval no
(fset 'insert-5-newlines (lambda!! #'newline 5))
;; The equivalent of C-u M-x org-global-cycle, which resets the org document to
;; its startup visibility settings.
(fset 'org-reset-global-visibility (lambda!! #'org-global-cycle '(4))
#+END_SRC
*** letenv!
#+BEGIN_SRC elisp
(letenv! (("SHELL" "/bin/sh"))
(shell-command-to-string "echo $SHELL"))
#+END_SRC
#+RESULTS:
: "/bin/sh\n"
*** load!
#+BEGIN_SRC elisp :eval no
;;; Lets say we're in ~/.doom.d/config.el
@ -269,9 +332,9 @@ These are side-by-side comparisons, showing how to bind keys with and without
(map! :map lua-mode-map "SPC m b" nil)
;; bind multiple keys
(global-set-key "C-x x" #'do-something)
(global-set-key "C-x y" #'do-something-else)
(global-set-key "C-x z" #'do-another-thing)
(global-set-key (kbd "C-x x") #'do-something)
(global-set-key (kbd "C-x y") #'do-something-else)
(global-set-key (kbd "C-x z") #'do-another-thing)
(map! "C-x x" #'do-something
"C-x y" #'do-something-else
"C-x z" #'do-another-thing)
@ -325,7 +388,7 @@ These are side-by-side comparisons, showing how to bind keys with and without
*** package!
#+BEGIN_SRC elisp :eval no
;; To install a package that can be found on ELPA or any of the sources
;; specified in `doom-core-package-sources':
;; specified in `straight-recipe-repositories':
(package! evil)
(package! js2-mode)
(package! rainbow-delimiters)
@ -342,22 +405,49 @@ These are side-by-side comparisons, showing how to bind keys with and without
;; you can tell the package manager not to clone the repo recursively:
(package! ansible :recipe (:nonrecursive t))
;; To install a particular branch, commit or tag:
(package! evil
;; if :host and :fetcher aren't specified, the package manager will fall back
;; to evil's default source provided by their (M)ELPA recipes:
:recipe (:commit "e7bc39de2f961505e8e112da8c1b315ae8afce52"))
;; To pin a package to a specific commit:
(package! evil :pin "e7bc39de2f9")
;; ...or branch:
(package! evil :recipe (:branch "stable"))
(package! evil :recipe (:tag "1.2.9"))
;; To unpin a pinned package:
(package! evil :pin nil)
;; If you share your config between two computers, and don't want bin/doom
;; refresh to delete packages used only on one system, use :ignore
(package! evil :ignore (not (equal system-name "my-desktop")))
#+END_SRC
*** TODO pushnew!
*** pushnew!
#+BEGIN_SRC elisp
(let ((list '(a b c)))
(pushnew! list 'c 'd 'e)
list)
#+END_SRC
#+RESULTS:
: (e d a b c)
*** prependq!
#+BEGIN_SRC elisp
(let ((x '(a b c)))
(prependq! x '(c d e))
x)
#+END_SRC
#+RESULTS:
: (c d e a b c)
#+BEGIN_SRC elisp
(let ((x '(a b c))
(y '(c d e))
(z '(f g)))
(prependq! x y z '(h))
x)
#+END_SRC
#+RESULTS:
: (c d e f g h a b c)
*** quiet!
#+BEGIN_SRC elisp :eval no
;; Enters recentf-mode without extra output
@ -381,6 +471,14 @@ These are side-by-side comparisons, showing how to bind keys with and without
;; Removing arbitrary forms (must be exactly the same as the definition)
(remove-hook! (one-mode second-mode) (setq v 5) (setq a 2))
#+END_SRC
*** setq!
#+BEGIN_SRC elisp
;; Each of these have a setter associated with them, which must be triggered in
;; order for their new values to have an effect.
(setq! evil-want-Y-yank-to-eol nil
evil-want-C-u-scroll nil
evil-want-C-d-scroll nil)
#+END_SRC
*** setq-hook!
#+BEGIN_SRC elisp :eval no
;; Set multiple variables after a hook
@ -423,15 +521,15 @@ These are side-by-side comparisons, showing how to bind keys with and without
:defer-incrementally t)
#+END_SRC
* Interesting snippets
** Persist Emacs' initial frame size across sessions
** Center Emacs' initial frame with a fixed size
#+BEGIN_SRC elisp
(let ((display-height (display-pixel-height))
(display-width (display-pixel-width)))
(add-to-list 'initial-frame-alist
`((left . ,(/ new-frame-width 2))
(top . ,(/ new-frame-height 2))
(width . ,(/ display-width 2))
(height . ,(/ display-height 2)))))
(pushnew! initial-frame-alist
`(left . ,(/ display-width 2))
`(top . ,(/ display-height 2))
`(width . ,display-width)
`(height . ,display-height)))
#+END_SRC
** Persist Emacs' initial frame position, dimensions and/or full-screen state across sessions

View file

@ -1,14 +1,14 @@
#+TITLE: Contributing
#+STARTUP: nofold
I can't say Doom Emacs is a one man show anymore. It wouldn't have gotten this
far without the help of folks like you! Still, I struggle to maintain it all;
especially the modules I do not use. If Doom has been useful to you, consider
pitching in and helping me out.
Doom Emacs is an active and ongoing project, maintained mostly by a single
person, but includes the efforts of 200 contributors and growing. There is no
shortage of things that need doing; bugs that need stomping, features that need
implementing, and documentation that needs documenting. If Doom's been useful to
you, convert some caffiene into code; it'd be a huge help!
Help can range from reporting bugs, proposing enhancements, submitting code and
documentation, or just spreading the good word. To ensure no toes get stepped on
or wires crossed, this guide was created to help you help us.
You are welcome to [[https://discord.gg/qvGgnVx][join us on our Discord server]], otherwise read on to learn how
to contribute to our fine corner of the interwebs.
* Table of Contents :TOC_3:
- [[#where-can-i-help][Where can I help?]]
@ -32,19 +32,20 @@ or wires crossed, this guide was created to help you help us.
- [[#contributing-documentation][Contributing documentation]]
- [[#contributing-to-dooms-manual][Contributing to Doom's manual]]
- [[#contributing-module-documentation][Contributing module documentation]]
- [[#help-keep-packages-up-to-date][Help keep packages up-to-date!]]
- [[#other-ways-to-support-doom-emacs][Other ways to support Doom Emacs]]
- [[#special-thanks][Special thanks]]
* Where can I help?
+ Our [[https://github.com/hlissner/doom-emacs/issues][issue tracker]] has many issues. If you find one that you have an answer to,
please don't hold back!
it would be a huge help!
+ Look for issues tagged [[https://github.com/hlissner/doom-emacs/labels/good%20first%20issue][good first issue]]. These were judged to have a low
barrier of entry.
+ Look for issues tagged [[https://github.com/hlissner/doom-emacs/labels/help%20wanted][help wanted]]. These tend to be a little (or a lot)
harder, and are issues outside my own expertise.
+ If you've encountered a bug, [[https://github.com/hlissner/doom-emacs/issues/new/choose][file a bug report]].
+ The [[https://github.com/hlissner/doom-emacs/projects/3][development roadmap board]] is a rough timeline of what is being worked on
and when. It will give you some idea of what will change and where you can
and when. It will give you an idea of what will change and where you can
redirect your efforts.
+ The [[https://github.com/hlissner/doom-emacs/projects/2][plugins under review board]] lists third party plugins being considered (or
rejected) for inclusion in Doom Emacs. Approved and unclaimed packages are
@ -54,30 +55,21 @@ or wires crossed, this guide was created to help you help us.
cause) perhaps you can address them at the source.
* TODO Reporting issues
So you've found a problem. Before you fire off that bug report, there are a few
things you should try first:
You've found a problem and you're ready to fire off that bug report. Hold up!
Before you do that, [[file:getting_started.org::*Troubleshoot][have a look at our Troubleshooting guide]]. If none of these
suggestions pan out, /then/ it is time to file a bug report.
+ Make sure your configuration (or Doom Emacs) is *not* byte-compiled. Run ~doom
clean~ to ensure it isn't. *Byte-compilation interferes with debugging!*
+ Run ~bin/doom refresh~ to ensure all plugins are installed and autoload files
generated.
+ Run ~bin/doom doctor~ to diagnose common issues with your system.
+ Check [[file:faq.org::*Common%20Issues][Common Issues]] in the FAQ to see if yours is a known issue.
+ If you happen to know what module(s) are relevant to your issue, check their
documentation (press =<leader> h m= to jump to a module's documentation). Your
issue may be documented.
+ If possible, check if the issue can be reproduced in vanilla Emacs (Emacs
without Doom) and/or vanilla Doom (Doom without your private config). To test
this, use ~M-x doom/sandbox~ (bound to =<leader> h E=). [[file:getting_started.org::*Use the sandbox][A guide for using the
sandbox can be found in the manual]].
+ Make sure your issue hasn't already been reported by searching the [[https://github.com/hlissner/doom-emacs/issues][issue
tracker]].
+ Make sure your issue hasn't been resolved on the =develop= branch of Doom.
An effective bug report is informative. Please try to provide:
If these suggestions haven't worked for you, it's time [[https://github.com/hlissner/doom-emacs/issues/new/choose][to write a bug report]].
Please make sure of the following before you submit:
+ A backtrace of all mentioned errors.
+ A step-by-step reproduction of the issue.
+ Information about your Doom config and system environment.
+ Screenshots/casts of the issue (if possible).
** TODO Collect backtraces of any error messages
This section will show you how to collect this information.
** Acquire a backtrace from errors
See "[[file:getting_started.org::*How to extract a backtrace from an error][How to extract a backtrace from an error]]" in the [[file:getting_started.org][Getting Started]] guide.
** TODO Create a step-by-step reproduction guide
@ -165,6 +157,11 @@ contact via our [[https://discord.gg/bcZ6P3y][Discord server]] or [[mailto:henri
** TODO Contributing module documentation
* TODO Help keep packages up-to-date!
Doom pins all its packages to reduce the likelihood of upstream breakage leaking
into Doom Emacs. However, we may miss when a package releases hotfixes for
critical issues. Let us know or PR a bump to our pinned packages.
* TODO Other ways to support Doom Emacs
* TODO Special thanks

View file

@ -20,11 +20,6 @@
- [[#should-i-fork-doom-to-customize-it][Should I fork Doom to customize it?]]
- [[#how-do-i-configure-doom-emacs][How do I configure Doom Emacs?]]
- [[#how-do-i-enable-or-disable-a-doom-module][How do I enable or disable a Doom module?]]
- [[#how-do-i-install-a-package-from-elpa][How do I install a package from ELPA?]]
- [[#how-do-i-install-a-package-from-githubanother-source][How do I install a package from github/another source?]]
- [[#how-do-i-change-where-an-existing-package-is-installed-from][How do I change where an existing package is installed from?]]
- [[#how-do-i-disable-a-package-completely][How do I disable a package completely?]]
- [[#how-do-i-reconfigure-a-package-included-in-doom][How do I reconfigure a package included in Doom?]]
- [[#how-do-i-change-the-theme][How do I change the theme?]]
- [[#how-do-i-change-the-fonts][How do I change the fonts?]]
- [[#how-do-i-bind-my-own-keys-or-change-existing-ones][How do I bind my own keys (or change existing ones)?]]
@ -32,12 +27,20 @@
- [[#how-do-i-change-the-leaderlocalleader-keys][How do I change the leader/localleader keys?]]
- [[#how-do-i-change-the-style-of-line-numbers-or-disable-them-altogether][How do I change the style of line-numbers (or disable them altogether)?]]
- [[#how-do-i-change-the-behavior-and-appearance-of-popup-windows][How do I change the behavior and appearance of popup windows?]]
- [[#how-do-i-change-the-appearance-a-face-or-faces][How do I change the appearance a face (or faces)?]]
- [[#can-doom-be-customized-without-restarting-emacs][Can Doom be customized without restarting Emacs?]]
- [[#can-vimevil-be-removed-for-a-more-vanilla-emacs-experience][Can Vim/Evil be removed for a more vanilla Emacs experience?]]
- [[#should-i-use-make-or-bindoom][Should I use ~make~ or ~bin/doom~?]]
- [[#when-should-and-shouldnt-i-use-bindoom][When should and shouldn't I use ~bin/doom~?]]
- [[#when-to-run-doom-refresh][When to run ~doom refresh~]]
- [[#when-to-run-doom-sync][When to run ~doom sync~]]
- [[#how-to-suppress-confirmation-prompts-while-bindoom-is-running][How to suppress confirmation prompts while ~bin/doom~ is running]]
- [[#package-management][Package Management]]
- [[#how-do-i-install-a-package-from-elpa][How do I install a package from ELPA?]]
- [[#how-do-i-install-a-package-from-githubanother-source][How do I install a package from github/another source?]]
- [[#how-do-i-change-where-an-existing-package-is-installed-from][How do I change where an existing package is installed from?]]
- [[#how-do-i-disable-a-package-completely][How do I disable a package completely?]]
- [[#how-do-i-reconfigure-a-package-included-in-doom][How do I reconfigure a package included in Doom?]]
- [[#where-does-straight-clonebuild-packages-to][Where does straight clone/build packages to?]]
- [[#defaults][Defaults]]
- [[#why-ivy-over-helm][Why Ivy over Helm?]]
- [[#why-are-there-no-default-keybinds-for-smartparens-for-evil-users][Why are there no default keybinds for Smartparens (for evil users)?]]
@ -55,34 +58,38 @@
- [[#changes-to-my-config-arent-taking-effect][Changes to my config aren't taking effect]]
- [[#the-frame-goes-black-on-macos-while-in-full-screen-mode][The frame goes black on MacOS, while in full-screen mode]]
- [[#doom-crashes-when][Doom crashes when...]]
- [[#cant-load-my-theme-unable-to-find-theme-file-for-x-errors][Can't load my theme; ~unable to find theme file for X~ errors]]
- [[#tramp-connections-hang-forever-when-connecting][TRAMP connections hang forever when connecting]]
- [[#an-upstream-package-was-broken-and-i-cant-update-it][An upstream package was broken and I can't update it]]
- [[#why-do-i-see-ugly-indentation-highlights-for-tabs][Why do I see ugly indentation highlights for tabs?]]
- [[#contributing][Contributing]]
* General
** Why is it called Doom?
An homage to idsoftware's classic game, whose open sourced code was my first
exposure to programming.
It's an homage to idsoftware's classic game, whose open sourced code was
Henrik's (Doom's maintainer) first exposure to programming.
Also, if you're obsessed enough with a text editor that you write a community
config for it, you're doomed from the get go.
And if you're obsessed enough with a text editor that you write a community
config for it, you're doomed from the start.
** Does Doom work on Windows?
Windows support is weak and will generally lag behind Linux/MacOS support, so
your mileage will vary. However, many have reported success installing Doom
Emacs on Windows (using WSL, WSL2 or scope/chocolatey). You'll find install
instructions for Windows in the [[file:getting_started.org::On Windows][Getting Starting guide]].
Windows support is weak and generally lags behind Linux/MacOS support, so your
mileage will vary. However, some have reported success using Doom Emacs on
Windows (using WSL, WSL2 or scoop/chocolatey). You'll find install instructions
in the [[file:getting_started.org::On Windows][Getting Starting guide]].
If you're a Windows user, help us improve our documentation on Windows support!
If you're a Windows user, help us improve our documentation!
** Is Doom only for vimmers?
Henrik is a dyed-in-the-wool vimmer with more than a decade of vim muscle
memory. Vim's is the only paradigm he truly knows, so vimmers will always be his
primary audience.
No, but it is Doom's primary audience. Its maintainer is a dyed-in-the-wool
vimmer with almost two decades of vim muscle memory, and he came to Emacs to
find a better vim.
That's not to say Doom won't work without evil, only that it is less polished in
that respect. Our growing non-evil userbase are slowly improving the situation
however. We welcome suggestions and PRs to help accommodate a non-evil workflow.
Although Doom is less polished without evil, its growing non-evil user base is
slowly improving the situation. We welcome suggestions and PRs to help
accommodate a non-evil workflow.
If you'd still like a go at it, see the [[file:../modules/editor/evil/README.org::Removing%20evil-mode][Removing evil-mode]] section in the
If you'd still like a go at it, see the [[file:../modules/editor/evil/README.org::Removing%20evil-mode][removing evil-mode]] section in the
[[file:../modules/editor/evil/README.org][:editor evil]] module's documentation.
** I am a beginner. Can I use Doom?
@ -115,12 +122,12 @@ To paraphrase (and expand upon) a [[https://www.reddit.com/r/emacs/comments/6pa0
you into Doom.
+ *Doom manages its packages outside of Emacs.* Spacemacs installs (and checks
for packages) on startup or on demand. Doom leaves package management to be
done externally, through the ~bin/doom~ script. This allows package management
can be scripted on the command line and enables a number of startup
done externally, through the ~bin/doom~ script. This allows for package
management to be scripted on the command line and enables a number of startup
optimizations we wouldn't have otherwise.
** Why such a complicated package management system?
Doom had ++four++ *five* goals for its package management system:
Doom had +four+ *five* goals for its package management system:
1. *Scriptability:* package management should be shell-scriptable, so updating
can be automated.
@ -129,15 +136,15 @@ Doom had ++four++ *five* goals for its package management system:
are out-of-date through official channels, have changed hands, have a
superior fork, or aren't available in ELPA repos.
3. *Performance:* lazy-loading the package management system is a tremendous
boon to start up speed. Initializing package.el and quelpa (and/or checking
that your packages are installed) every time you start up is expensive.
boon to start up speed. Initializing package.el and straight (and/or checking
that your packages are installed) each time you start up is expensive.
4. *Organization:* an Emacs configuration grows so quickly, in complexity and
size. A clear separation of concerns (configuration of packages from their
installation) is more organized.
5. *Reproducibility:* /This goal hasn't been implemented yet/, but all our work
up until now is aimed at this goal. Emacs is a tumultuous ecosystem; packages
break left and right, and we rely on hundreds of them. Eventually, we want
package versions to be locked to versions of Doom so that Doom installs are
package versions to be locked to Doom's releases so that Doom installs are
reproducible.
** How does Doom start up so quickly?
@ -155,10 +162,10 @@ up ~gc-cons-threshold~ (and perhaps ~gc-cons-percentage~) temporarily:
;; ... your emacs config here ...
#+END_SRC
However, it is important to reset it eventually (as late as possible). Not doing
so will cause garbage collection freezes during long-term interactive use.
Conversely, a ~gc-cons-threshold~ that is too small will cause stuttering. We
use 16mb as our default.
However, it is important to reset it eventually. Not doing so will cause garbage
collection freezes during long-term interactive use. Conversely, a
~gc-cons-threshold~ that is too small will cause stuttering. We use 16mb as our
default.
#+BEGIN_SRC emacs-lisp
(add-hook 'emacs-startup-hook
@ -185,14 +192,16 @@ helm and ivy). Here is how Doom does it:
(add-hook 'minibuffer-exit-hook #'doom-restore-garbage-collection-h)
#+END_SRC
Another alternative (which is [[https://github.com/hlissner/doom-emacs/blob/develop/core/core.el#L269-L274][what Doom uses]]) is to use the [[https://gitlab.com/koral/gcmh/][gcmh]] package to
stave off the GC until you are idle or unfocus the Emacs frame.
*** Unset ~file-name-handler-alist~ temporarily
Emacs consults this variable every time a file is read or library loaded, or
when certain functions in the file API are used (like ~expand-file-name~ or
~file-truename~).
They do so to check if a special handler is needed to read it, but none of these
handlers are necessary for the initialization work we do at startup, so it is
generally safe to disable it (temporarily!):
Emacs does to check if a special handler is needed to read that file, but none
of them are (typically) necessary at startup, so we disable them (temporarily!):
#+BEGIN_SRC emacs-lisp
(defvar doom--file-name-handler-alist file-name-handler-alist)
@ -209,60 +218,38 @@ generally safe to disable it (temporarily!):
(setq file-name-handler-alist doom--file-name-handler-alist)))
#+END_SRC
It is important to restore this variable, otherwise you won't be able to use
TRAMP and Emacs will be unable to read compressed/encrypted files.
*** Cut down on ~load-path~ lookups
Each ~load~ and ~require~ call (without an second argument) costs an O(n) lookup
on ~load-path~. The average Doom config has approximately 260 packages including
dependencies, and around 40 built-in packages. That means a minimum of 300
entries in ~load-path~ with a worst case of =n=300= for /each/ package load (but
realistically, =n= will be somewhere between =2= and =20=).
The cost isn't great, but it does add up. There isn't much to do about this,
except be mindful of it where we can:
+ Paths in Doom's autoloads file are replaced with absolute ones, thus incurring
no lookup cost to lazy load them.
+ The ~load!~ macro is used instead of ~require~ where possible. This builds
paths with string concatenation (which is baked in at compile time, removing
most of the associated cost).
+ ~load-path~ is let-bound to a subset of itself where possible (the
~doom--initial-load-path~ variable contains the value of ~load-path~ before it
was touched by Doom).
Don't forget to restore ~file-name-handler-alist~, otherwise TRAMP won't work
and compressed/encrypted files won't open.
*** Concatenate package autoloads
When you install a package, a PACKAGE-autoloads.el file is generated. This file
contains a map of autoloaded functions and snippets declared by the package
(that's what those ~;;;###autoload~ comments are for in packages). They tell
Emacs where to find them, when they are eventually called. In your conventional
Emacs config, every single one of these autoloads files are loaded immediately
at startup.
contains a map of autoloaded functions and snippets declared by the package.
They tell Emacs where to find them when they are eventually called. In your
conventional Emacs config, every one of these autoloads files are loaded
immediately at startup (when ~package-initialize~ is called).
Since you'll commonly have hundreds of packages, loading hundreds of autoloads
file can hurt startup times. We get around this by concatenating these autoloads
files into one giant one (in =~/.emacs.d/.local/autoloads.pkg.el=) when you run
~doom refresh~.
file can hurt startup times, especially without an SSD. We get around this by
concatenating these files into one giant one when you run ~doom sync~.
Emacs 27+ will introduce a ~package-quickstart~ feature that will do this for
you -- the =straight= package manager does this for you too -- but Doom Emacs
has its own specialized mechanism for doing this, and has tacked a number of
Doom-specific optimizations on top of it.
Emacs 27+ introduces a ~package-quickstart~ command does this for you, and
=straight=, our package manager, does this for you too, but [[https://github.com/hlissner/doom-emacs/tree/develop/core/cli/autoloads.el][Doom Emacs has its
own specialized mechanism]] for this, topped off with a few Doom-specific
optimizations.
*** Lazy load package management system(s)
Initializing package.el or straight.el at startup is expensive. We can save some
time by delaying that initialization until we actually need these libraries (and
only eagerly load them when we're doing package management, e.g. when we run
~doom refresh~).
load them only when we're doing package management, e.g. when we run ~doom
sync~).
Among other things, ~doom refresh~ does a lot for us. It generates concatenated
Among other things, ~doom sync~ does a lot for us. It generates concatenated
autoloads files; caches expensive variables like caches ~load-path~,
~Info-directory-list~ and ~auto-mode-alist~; and preforms all your package
management activities there -- far away from your interactive sessions.
How exactly Doom accomplishes all this is a little complex, so instead, here is
a boiled-down version you can use in your own configs (for package.el, not
straight.el):
How exactly Doom accomplishes all this is a long story, so here is a boiled-down
version you can use in your own configs (for package.el, not straight.el):
#+BEGIN_SRC emacs-lisp
(defvar cache-file "~/.emacs.d/cache/autoloads")
@ -273,26 +260,12 @@ straight.el):
(package-initialize)
(with-temp-buffer
(cl-pushnew doom-core-dir load-path :test #'string=)
(dolist (spec package-alist)
(when-let (desc (cdr spec))
(let ((file (concat (package--autoloads-file-name desc) ".el")))
(when (file-readable-p file)
;; Ensure that the contents of this autoloads file believes they
;; haven't been moved:
(insert "(let ((load-file-name " (prin1-to-string (abbreviate-file-name file)) "))\n")
(insert-file-contents file)
(save-excursion
;; Delete forms that modify `load-path' and `auto-mode-alist', we
;; will set them once, later.
(while (re-search-forward "^\\s-*\\((\\(?:add-to-list\\|\\(?:when\\|if\\) (boundp\\)\\s-+'\\(?:load-path\\|auto-mode-alist\\)\\)" nil t)
(goto-char (match-beginning 1))
(kill-sexp)))
;; Remove unnecessary comment lines and (provide ...) forms
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
(unless (nth 8 (syntax-ppss))
(replace-match "" t t)))
(unless (bolp) (insert "\n"))
(insert ")\n")))))
(dolist (desc (delq nil (mapcar #'cdr package-alist)))
(let ((load-file-name (concat (package--autoloads-file-name desc) ".el")))
(when (file-readable-p load-file-name)
(condition-case _
(while t (insert (read (current-buffer))))
(end-of-file)))))
(prin1 `(setq load-path ',load-path
auto-mode-alist ',auto-mode-alist
Info-directory-list ',Info-directory-list)
@ -304,10 +277,9 @@ straight.el):
#+END_SRC
You'll need to delete ~cache-files~ any time you install, remove, or update a
new package, however. In that case you could advise ~package-install~ and
~package-delete~ to call ~initialize~ when they succeed. Or, you could make
~initialize~ interactive and call it manually when you determine it's necessary.
Up to you!
new package. You could advise ~package-install~ and ~package-delete~ to call
~initialize~ when they succeed, or make ~initialize~ interactive and call it
manually when necessary. Up to you!
Note: package.el is sneaky, and will initialize itself if you're not careful.
*Not on my watch, criminal scum!*
@ -322,20 +294,21 @@ Note: package.el is sneaky, and will initialize itself if you're not careful.
*** Lazy load more than everything
~use-package~ can defer your packages. Using it is a no-brainer, but Doom goes a
little further with lazy loading. There are some massive plugins out there. For
many of them, ordinary lazy loading techniques simply don't work. To name a few:
some of them, ordinary lazy loading techniques don't work. To name a few:
+ The =lang/org= module defers loading babel packages until their src blocks are
executed. You no longer need ~org-babel-do-load-languages~ in your config.
executed or read. You no longer need ~org-babel-do-load-languages~ in your
config -- in fact, you shouldn't use it at all!
+ Company and yasnippet are loaded as late as possible (waiting until the user
opens a non-read-only, file-visiting buffer (that isn't in fundamental-mode)).
+ The =evil-easymotion= package has many keybinds. You'd need to load the
package for them to all take effect, so instead, =gs= is bound to a command
that loads the package and then invisibly populates =gs=, then simulates the
=gs= keypress as though those new keys had always been there.
+ A number of packages are "incrementally" loaded. This is a Doom feature where,
after a few seconds of idle time post-startup, Doom will load packages
piecemeal while Emacs. It will quickly abort if it detects input, as to make
the process as subtle as possible.
+ The =evil-easymotion= package binds many keys, none of which are available
until you load the package. Instead of loading it at startup, =gs= is bound to
a command that loads the package, populates =gs=, then simulates the =gs= key
press as though those new keys had always been there.
+ Doom loads some packages "incrementally". i.e. after a few seconds of idle
time post-startup, Doom loads packages piecemeal (one dependency at a time)
while Emacs. It aborts if it detects input, as to make the process as subtle
as possible.
For example, instead of loading =org= (a giant package), it will load these
dependencies, one at a time, before finally loading =org=:
@ -349,21 +322,6 @@ many of them, ordinary lazy loading techniques simply don't work. To name a few:
This ensures packages load as quickly as possible when you first load an org
file.
*** +Exploit byte-compilation!+
It used to be that byte-compilation bought a 40-60% improvement in startup
times, because expensive operations (like ~package-initialize~ or
~exec-path-from-shell~) were evaluated at compile time, but Doom has changed.
I've since adopted a pre-cache approach (when running ~doom refresh~), which
brings these startup benefits to uncompiled Emacs. This renders byte-compilation
significantly less beneficial for startup time.
That said, compilation will still benefit Doom's snappiness in general.
Run ~doom compile :core~ to only compile Doom's core files, or ~doom compile~ to
compile the /entire/ config (=~/.emacs.d= and =~/.doom.d=) -- which may take a
while.
*** Use [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical-binding]] everywhere
Add ~;; -*- lexical-binding: t; -*-~ to the top of your elisp files. This can
break code if you've written it to depend on undeclared dynamic variables, but
@ -376,32 +334,30 @@ find more about it in:
+ [[http://nullprogram.com/blog/2016/12/22/]["Some Performance Advantages of Lexical Scope."]]
** Why is startup time important? Why not use the daemon?
One of my motivations for a config that starts up fast (aside from the learning
experience) was to shape Emacs into a viable alternative to vim for one-shot
editing in the terminal (without ~-Q~). This also facilitates:
The central motivation for a config that starts up fast (aside from the learning
experience) was to have a viable alternative to vim for quick, one-shot editing
in the terminal (without ~-Q~).
- Running multiple, independent instances of Emacs (e.g. on a per-project basis, or
for nix-shell users, or to isolate one instance for IRC from an instance for
writing code, etc).
Besides that, it happens to facilitate:
- Running multiple, independent instances of Emacs (e.g. on a per-project basis,
or for nix-shell users, or to isolate one instance for IRC from an instance
for writing code, etc).
- Quicker restarting of Emacs, to reload package settings or recover from
disastrous errors which can leave Emacs in a broken state.
- Faster integration with "edit in Emacs" solutions (like [[https://github.com/alpha22jp/atomic-chrome][atomic-chrome]]), and
the potential to use them without a running daemon.
without a daemon.
What's more, I don't like using more tools than I need. We should not need a
second program just to make the first run comfortably.
What's more, I believe a daemon shouldn't be necessary to get a sane startup
time out of Emacs.
** How do I use Doom alongside other Emacs configs?
I recommend [[https://github.com/plexus/chemacs][Chemacs]]. You can think of it as a bootloader for Emacs. You'll [[file:getting_started.org::*Alongside other Emacs configs (with Chemacs)][find
instructions on how to use it with Doom in the user manual]].
If you only want to try it out without affecting your current config, it is safe
to install Doom anywhere you like. The ~bin/doom~ utility will only address the
config the script is located under.
You'll still need a separate folder for personal configuration (=~/.doom.d= or
=~/.config/doom= by default), but the =-p PATH= flag (or ~DOOMDIR~ environment
variable) will allow you to use a different location:
=~/.config/doom= by default), but the =--doomdir PATH= switch (or ~DOOMDIR~
environment variable) will allow you to use a different location:
#+BEGIN_SRC bash
# First install Doom somewhere
@ -467,153 +423,57 @@ to as your ~$DOOMDIR~.
Your private config is typically comprised of an =init.el=, =config.el= and
=packages.el= file. Put all your config in =config.el=, install packages by
adding ~package!~ declarations to =packagse.el=, and enable/disable modules in
adding ~package!~ declarations to =packages.el=, and enable/disable modules in
you ~doom!~ block, which should have been created in your =init.el= when you
first ran ~doom install~.
Check out the [[file:getting_started.org::Customize][Customize section]] in the [[file:getting_started.org][Getting Started]] guide for details.
** How do I enable or disable a Doom module?
You'll find your ~doom!~ block in =~/.doom.d/init.el=. This block contains a
list of modules you want enabled and what order to load them in. Disable modules
by commenting them out with semicolons. To enable them, remove those leading
semicolons:
Comment or uncomment the module in your ~doom!~ block, found in
=$DOOMDIR/init.el=.
#+BEGIN_SRC emacs-lisp
(doom! :lang
python ; this is enabled
;;ruby ; this is disabled
rust)
#+END_SRC
Remember to run ~bin/doom refresh~ afterwards, on the command line, to sync your
Remember to run ~bin/doom sync~ afterwards, on the command line, to sync your
module list with Doom.
You can find a comprehensive list of modules in the [[file:index.org::*Module list][Module Index]].
** How do I install a package from ELPA?
Add a ~package!~ declaration to =~/.doom.d/packages.el= for each package you
want installed.
#+BEGIN_SRC elisp
(package! winum)
#+END_SRC
Remember to run ~doom refresh~ afterwards to ensure the package is installed.
You'll find more information in the "[[file:getting_started.org::*Installing%20packages][Installing packages]]" section of the [[file:getting_started.org][Getting
Started]] guide.
** How do I install a package from github/another source?
The ~package!~ macro can be passed a MELPA style recipe, allowing you to install
packages from just about anywhere:
#+BEGIN_SRC elisp
(package! evil :recipe (:host github :repo "hlissner/my-evil-fork"))
#+END_SRC
Remember to run ~doom refresh~ every time you modify you package list, to ensure
your packages are set up and installed.
You can find more information about the recipe format [[https://github.com/raxod502/straight.el#the-recipe-format][in the straight.el package
readme]].
#+begin_quote
If a MELPA recipe exists for the package you are writing a ~package!~
declaration for, you may omit keywords and Doom's package manager will fill them
in with values from its original recipe.
#+end_quote
You'll find more information in the "[[file:getting_started.org::*Installing%20packages%20from%20external%20sources][Installing packages from external sources]]"
section of the [[file:getting_started.org][Getting Started]] guide.
** How do I change where an existing package is installed from?
~package!~ declarations in your private =packages.el= file have precedence over
modules (even your own). Simply add a new one for that package with the new
recipe.
You'll find more information in the "[[file:getting_started.org::*Changing%20a%20built-in%20recipe%20for%20a%20package][Changing a built-in recipe for a package]]"
section of the [[file:getting_started.org][Getting Started]] guide.
** How do I disable a package completely?
With the ~package!~ macro's ~:disable~ property:
#+BEGIN_SRC elisp
;;; in DOOMDIR/packages.el
(package! irony :disable t)
#+END_SRC
Remember to run ~doom refresh~ afterwards to ensure that the package is
uninstalled and disabled.
You'll find more information in the "[[file:getting_started.org::*Disabling%20packages][Disabling packages]]" section of the [[file:getting_started.org][Getting
Started]] guide.
** How do I reconfigure a package included in Doom?
~use-package!~ and ~after!~ (wrappers around ~use-package~ and
~eval-after-load~, respectively) are your bread and butter for configuring
packages in Doom.
#+BEGIN_SRC elisp
;; Takes a feature symbol or a library name (string)
(after! evil
(setq evil-magic nil))
;; Takes a major-mode, a quoted hook function or a list of either
(add-hook! python-mode
(setq python-shell-interpreter "bpython"))
(use-package! hl-todo
;; if you omit :defer, :hook, :commands, or :after, then the package is loaded
;; immediately. By using :hook here, the `hl-todo` package won't be loaded
;; until prog-mode-hook is triggered (by activating a major mode derived from
;; it, e.g. python-mode)
:hook (prog-mode . hl-todo-mode)
:init
;; code here will run immediately
:config
;; code here will run after the package is loaded
(setq hl-todo-highlight-punctuation ":"))
;; There's also `setq-hook!' for setting variables buffer-locally
(setq-hook! python-mode python-indent-offset 2)
#+END_SRC
See the "[[file:getting_started.org::*Configuring%20Doom][Configuring Doom]]" section of the [[file:getting_started.org][Getting Started]] guide for more
explanation and examples.
See the "[[file:getting_started.org::*Configuration modules][Configuration modules]]" section of the [[file:getting_started.org][Getting Started]] guide for more
information.
** How do I change the theme?
There are two ways to load a theme. Both assume the theme is installed and
available. They are:
available. You can either set ~doom-theme~ or manually load a theme with the
~load-theme~ function.
#+BEGIN_SRC emacs-lisp
;;; in ~/.doom.d/config.el
;;; add to ~/.doom.d/config.el
(setq doom-theme 'doom-tomorrow-night)
;; or
(load-theme 'doom-tomorrow-night t)
#+END_SRC
#+begin_quote
At the moment, the only difference between the two is that ~doom-theme~ is
loaded when Emacs has finished initializing at startup and ~load-theme~ loads
the theme immediately. Which you choose depends on your needs, but I recommend
setting ~doom-theme~ because, if I later discover a better way to load themes, I
can easily change how Doom uses ~doom-theme~, but I can't (easily) control how
you use the ~load-theme~ function.
#+end_quote
*** Installing a third party theme
To install a theme from a third party plugin, say, [[https://github.com/bbatsov/solarized-emacs][solarized]], you need only
install it, then load it:
#+BEGIN_SRC emacs-lisp
;; in ~/.doom.d/packages.el
(package! solarized)
;;; add to ~/.doom.d/packages.el
(package! solarized-theme)
;; in ~/.doom.d/config.el
;;; add to ~/.doom.d/config.el
(setq doom-theme 'solarized-dark)
#+END_SRC
Don't forget to run ~doom refresh~ afterwards to ensure the package is
installed.
Don't forget to run ~doom sync~ after adding that ~package!~ statement to ensure
the package is installed.
** How do I change the fonts?
Doom exposes five (optional) variables for controlling fonts in Doom, they are:
@ -624,12 +484,12 @@ Doom exposes five (optional) variables for controlling fonts in Doom, they are:
+ ~doom-unicode-font~
+ ~doom-big-font~ (used for ~doom-big-font-mode~)
Each of these will accept either a =font-spec=, font string (="Input Mono-12"=),
or [[https://wiki.archlinux.org/index.php/X_Logical_Font_Description][xlfd font string]].
They all accept either a =font-spec=, font string (="Input Mono-12"=), or [[https://wiki.archlinux.org/index.php/X_Logical_Font_Description][xlfd
font string]].
e.g.
#+BEGIN_SRC emacs-lisp
;; ~/.doom.d/config.el
;;; Add to ~/.doom.d/config.el
(setq doom-font (font-spec :family "Input Mono Narrow" :size 12 :weight 'semi-light)
doom-variable-pitch-font (font-spec :family "Fira Sans") ; inherits `doom-font''s :size
doom-unicode-font (font-spec :family "Input Mono Narrow" :size 12)
@ -697,7 +557,7 @@ These variables control what key to use for leader and localleader keys:
e.g.
#+BEGIN_SRC emacs-lisp
;; in ~/.doom.d/config.el
;;; add to ~/.doom.d/config.el
(setq doom-leader-key ","
doom-localleader-key "\\")
#+END_SRC
@ -705,13 +565,9 @@ e.g.
** How do I change the style of line-numbers (or disable them altogether)?
Doom uses the ~display-line-numbers~ package, which is built into Emacs 26+.
#+begin_quote
This package has been backported for Emacs 25 users, but is powered by =nlinum=
there (which will be removed when we drop 25 support).
#+end_quote
*** Disabling line numbers entirely
#+BEGIN_SRC elisp
;;; add to ~/.doom.d/config.el
(setq display-line-numbers-type nil)
;; or
(remove-hook! '(prog-mode-hook text-mode-hook conf-mode-hook)
@ -720,16 +576,25 @@ there (which will be removed when we drop 25 support).
*** Switching to relative line numbers (permanently)
To change the style of line numbers, change the value of the
~display-line-numbers-type~ variable. It accepts =t= (normal line numbers),
='relative= (relative line numbers), ='visual= (relative line numbers in screen
space) and =nil= (no line numbers).
~display-line-numbers-type~ variable. It accepts the following values:
You'll find more precise documentation on the variable through =SPC h v
display-line-numbers-type= or =C-h v display-line-numbers-type=.
#+begin_example
t normal line numbers
'relative relative line numbers
'visual relative line numbers in screen space
nil no line numbers
#+end_example
#+begin_quote
The ~'visual~ option is unavailable in Emacs 25.
#+end_quote
For example:
#+BEGIN_SRC elisp
;;; add to ~/.doom.d/config.el
(setq display-line-numbers-type 'relative)
#+END_SRC
You'll find more precise documentation on the variable through =<help> v
display-line-numbers-type= (=<help>= is =SPC h= for evil users, =C-h=
otherwise).
*** Switching the style of line numbers (temporarily)
Use ~M-x doom/toggle-line-numbers~ (bound to =SPC t l= by default) to cycle
@ -748,6 +613,19 @@ rules.
You'll find more comprehensive documentation on ~set-popup-rule!~ in its
docstring (available through =SPC h f= -- or =C-h f= for non-evil users).
** How do I change the appearance a face (or faces)?
Doom provides the ~custom-set-faces!~ and ~custom-theme-set-faces!~ macros as a
convenience.
#+begin_quote
*Do not use ~M-x customize~ or any of the built-in Emacs customize-* API.* Doom
does not support it and never will; those settings could break at any time.
#+end_quote
See =<help> f custom-set-faces\!= (or =M-x helpful-function custom-set-faces\!=)
for documentation and examples on how to use it. =<help>= is =SPC h= for evil
users and =C-h= for non-evil users.
** Can Doom be customized without restarting Emacs?
Short answer: You can, but you shouldn't.
@ -757,20 +635,17 @@ tools for experienced Emacs users to skirt around it (most of the time):
- Evaluate your changes on-the-fly with ~+eval/region~ (bound to the =gr=
operator for evil users) or ~eval-last-sexp~ (bound to =C-x C-e=). Changes
take effect immediately.
- On-the-fly evaluation won't work for all changes. For instance, changing your
~doom!~ block (i.e. the list of modules for Doom to enable) will always
require a restart (and ~bin/doom refresh~).
- On-the-fly evaluation won't work for all changes. e.g. Changing your ~doom!~
block (i.e. the list of modules for Doom to enable).
Doom provides ~M-x doom/reload~ for your convenience, which will run ~doom
refresh~, restart the Doom initialization process, and re-evaluate your
personal config, but this won't clear pre-existing state. That may or may not
be a problem, this hasn't be thoroughly tested and Doom cannot anticipate
complications arising from your private config.
If you intend to use ~doom/reload~, you must design your config to be
idempotent.
- Many ~bin/doom~ commands are available as elisp commands with the ~doom//*~
prefix. e.g. ~doom//refresh~, ~doom//update~, etc. Feel free to use them, but
But rather than running ~doom sync~ and restarting Emacs, Doom provides ~M-x
doom/reload~ for your convenience (bound to =SPC h r r= and =C-h r r=). This
runs ~doom sync~, restarts the Doom initialization process and re-evaluates
your personal config. However, this won't clear pre-existing state; Doom won't
unload modules/packages that have already been loaded and it can't anticipate
complications arising from a private config that isn't idempotent.
- Some ~bin/doom~ commands are available as elisp commands. e.g. ~doom/reload~
for ~doom sync~, ~doom/upgrade~ for ~doom upgrade~ ~doom//s~, ~doom//update~, etc. Feel free to use them, but
consider them highly experimental and subject to change without notice.
- You can quickly restart Emacs and restore the last session with
~doom/restart-and-restore~ (bound to =SPC q r=).
@ -792,7 +667,7 @@ commands that you may find particularly useful:
+ ~doom doctor~ :: Diagnose common issues in your environment and list missing
external dependencies for your enabled modules.
+ ~doom refresh~ :: Ensures that all missing packages are installed, orphaned
+ ~doom sync~ :: Ensures that all missing packages are installed, orphaned
packages are removed, and metadata properly generated.
+ ~doom install~ :: Install any missing packages.
+ ~doom update~ :: Update all packages that Doom's (enabled) modules use.
@ -806,12 +681,12 @@ commands that you may find particularly useful:
#+BEGIN_SRC bash
git pull
doom refresh
doom sync
doom update
#+END_SRC
** When to run ~doom refresh~
As a rule of thumb you should run ~doom refresh~ whenever you:
** When to run ~doom sync~
As a rule of thumb you should run ~doom sync~ whenever you:
+ Update Doom with ~git pull~ instead of ~doom upgrade~,
+ Change your ~doom!~ block in =$DOOMDIR/init.el=,
@ -820,8 +695,8 @@ As a rule of thumb you should run ~doom refresh~ whenever you:
+ Install an Emacs package or dependency outside of Emacs (i.e. through your OS
package manager).
If anything is misbehaving, it's a good idea to run ~doom refresh~ first. ~doom
refresh~ is responsible for regenerating your autoloads file (which tells Doom
If anything is misbehaving, it's a good idea to run ~doom sync~ first. ~doom
sync~ is responsible for regenerating your autoloads file (which tells Doom
where to find lazy-loaded functions and libraries), installing missing packages,
and uninstall orphaned (unneeded) packages.
@ -835,9 +710,32 @@ doom --yes update
YES=1 doom update
#+END_SRC
* Package Management
** How do I install a package from ELPA?
See the "[[file:getting_started.org::*Installing%20packages][Installing packages]]" section of the [[file:getting_started.org][Getting Started]] guide.
** How do I install a package from github/another source?
See the "[[file:getting_started.org::*Installing%20packages%20from%20external%20sources][Installing packages from external sources]]" section of the [[file:getting_started.org][Getting
Started]] guide.
** How do I change where an existing package is installed from?
See the "[[file:getting_started.org::*Changing a recipe for a included package][Changing a recipe for a included package]]" section of the [[file:getting_started.org][Getting
Started]] guide.
** How do I disable a package completely?
See the "[[file:getting_started.org::*Disabling%20packages][disabling packages]]" section of the [[file:getting_started.org][Getting Started]] guide.
** How do I reconfigure a package included in Doom?
See the "[[file:getting_started.org::*Configuring packages][configuring packages]]" section of the Getting Started guide.
** Where does straight clone/build packages to?
Straight clones packages to =~/.emacs.d/.local/straight/repos/REPO-NAME=, then
later symlinks and byte-compiles them to
=~/.emacs.d/.local/straight/build/PACKAGE-NAME= when they are "built".
* Defaults
** Why Ivy over Helm?
Short answer: I chose ivy because it is the simpler of the two.
Short answer: ivy is simpler to maintain.
Long answer: Features and performance appear to be the main talking points when
comparing the two, but as far as I'm concerned they are equal in both respects
@ -898,39 +796,38 @@ putting in the time to learn them.
Otherwise, it is trivial to install expand-region and binds keys to it yourself:
#+BEGIN_SRC elisp
;; in ~/.doom.d/packages.el
;;; add to ~/.doom.d/packages.el
(package! expand-region)
;; in ~/.doom.d/config.el
;;; add to ~/.doom.d/config.el
(map! :nv "C-=" #'er/contract-region
:nv "C-+" #'er/expand-region)
#+END_SRC
** Why not use exec-path-from-shell instead of ~doom env~?
In a nutshell, the ~doom env~ approach is a faster and more robust solution.
The ~doom env~ approach is a faster and more reliable solution.
1. ~exec-path-from-shell~ must spawn (at least) one process at startup to scrape
your shell environment. This can be arbitrarily slow depending on the user's
shell configuration. A single program (like pyenv or nvm) or config framework
(like oh-my-zsh) could undo all of Doom's startup optimizations in one fell
swoop.
your shell environment. This can be slow depending on the user's shell
configuration. A single program (like pyenv or nvm) or config framework (like
oh-my-zsh) could undo Doom's startup optimizations in one fell swoop.
2. ~exec-path-from-shell~ only scrapes /some/ state from your shell. You have to
be proactive in order to get it to capture all the envvars relevant to your
development environment.
2. ~exec-path-from-shell~ takes a whitelist approach and captures only ~PATH~
and ~MANPATH~ by default. You must be proactive in order to capture all the
envvars relevant to your development environment and tools.
I'd rather it inherit your shell environment /correctly/ (and /completely/)
or not at all. It frontloads the debugging process rather than hiding it
until it you least want to deal with it.
~doom env~ takes the blacklist approach and captures all of your shell
environment. This front loads the debugging process, which is nicer than dealing
with it later, while you're getting work done.
That said, if you still want ~exec-path-from-shell~, it is trivial to install
yourself:
#+BEGIN_SRC emacs-lisp
;; in ~/.doom.d/packages.el
;;; add to ~/.doom.d/packages.el
(package! exec-path-from-shell)
;; in ~/.doom.d/config.el
;;; add to ~/.doom.d/config.el
(require 'exec-path-from-shell)
(when (display-graphic-p)
(exec-path-from-shell-initialize))
@ -941,16 +838,16 @@ TL;DR: =ws-butler= is less imposing.
Don't be that guy who PRs 99 whitespace adjustments around his one-line
contribution. Don't automate this aggressive behavior by attaching
~delete-trailing-whitespace~ (or ~whitespace-cleanup~) to ~before-save-hook~. If
you have rambunctious colleagues peppering trailing whitespace into your project,
you need to have a talk (with wiffle bats, preferably) rather than play this
passive-aggressive game of whack-a-mole.
you have rambunctious colleagues peppering trailing whitespace into your
project, you need to have a talk (with wiffle bats, preferably) rather than play
a passive-aggressive game of whack-a-mole.
Here at Doom Inc we believe that operations that mutate entire files should
never be automated. Rather, they should be invoked deliberately -- by someone
that is aware of the potential consequences. This is where =ws-butler= comes in.
It only cleans up whitespace /on the lines you've touched/ *and* it leaves
behind virtual whitespace (which is never written to the file, but remains there
so your cursor doesn't get thrown around in all that cleanup work).
Here at Doom Inc we believe that operations that mutate entire files should not
be automated. Rather, they should be invoked deliberately, when and where it is
needed, by someone that is aware of the potential consequences. This is where
=ws-butler= comes in. It only cleans up whitespace /on the lines you've touched/
*and* it leaves behind virtual whitespace (which is never written to the file)
so your cursor doesn't get thrown around in all that cleanup work.
In any case, if you had used =ws-butler= from the beginning, trailing whitespace
and newlines would never be a problem!
@ -987,14 +884,14 @@ manually (e.g. by double-clicking each file in explorer).
** ~void-variable~ and ~void-function~ errors on startup
The most common culprit for these types of errors are:
1. An out-of-date autoloads file. To regenerate it, run ~doom refresh~.
1. An out-of-date autoloads file. Run ~doom sync~ to regenerate them.
To avoid this issue, remember to run ~doom refresh~ whenever you modify your
To avoid this issue, remember to run ~doom sync~ whenever you modify your
~doom!~ block in =~/.doom.d/init.el=, or add ~package!~ declarations to
=~/.doom.d/packages.el=. Or if you modify =~/.emacs.d/.local= by hand, for
whatever reason.
See ~doom help refresh~ for details on what this command does and when you
See ~doom help sync~ for details on what this command does and when you
should use it.
2. Emacs byte-code isn't forward compatible. If you've recently switched to a
@ -1025,7 +922,7 @@ issues #1 and #3: generate an envvar file by running ~doom env~. This scrapes
your shell environment into a file that is loaded when Doom Emacs starts up.
Check out ~doom help env~ for details on how this works.
For issue #2, you'll need to investigate your launcher. [[https://discord.gg/bcZ6P3y][Our Discord]] is a good
For issue #2, you'll need to investigate your launcher. [[https://discord.gg/qvGgnVx][Our Discord]] is a good
place to ask about it.
** There's artefacting on my icon fonts in GUI Emacs ([[https://github.com/hlissner/doom-emacs/issues/956][#956]])
@ -1052,8 +949,8 @@ If you still want to restore the old behavior, simply disable evil-snipe-mode:
1. Make sure you don't have both =~/.doom.d= and =~/.config/doom= directories.
Doom will ignore the former if the latter exists.
2. Remember to run ~doom refresh~ when it is necessary. To get to know when,
exactly, you should run this command, run ~doom help refresh~.
2. Remember to run ~doom sync~ when it is necessary. To get to know when,
exactly, you should run this command, run ~doom help sync~.
If neither of these solve your issue, try ~bin/doom doctor~. It will detect a
variety of common issues, and may give you some clues as to what is wrong.
@ -1068,7 +965,6 @@ known fix for this. To work around it, you must either:
support it),
3. Install Emacs via the =emacs-mac= homebrew formula.
** Doom crashes when...
Here are a few common causes for random crashes:
@ -1091,4 +987,82 @@ Here are a few common causes for random crashes:
Or disable the =:ui doom-dashboard= & =:tools magit= modules (see [[https://github.com/hlissner/doom-emacs/issues/1170][#1170]]).
** Can't load my theme; ~unable to find theme file for X~ errors
This means Emacs can't find the X-theme.el file for the theme you want to load.
Emacs will search for this file in ~custom-theme-load-path~ and
~custom-theme-directory~. There are a couple reasons why it can't be found:
1. It is generally expected that third party themes will [[https://github.com/hlissner/emacs-doom-themes/blob/master/doom-themes.el#L400-L405][add themselves]] to
~custom-theme-load-path~, but you will occasionally encounter a theme that
does not. This should be reported upstream.
In the meantime, you can get around this by eagerly loading the package:
#+BEGIN_SRC elisp
(require 'third-party-theme)
(setq doom-theme 'third-party)
#+END_SRC
2. You've appended ~-theme~ to the end of your theme's name.
#+BEGIN_SRC elisp
(setq doom-theme 'third-party-theme)
#+END_SRC
When you load a theme Emacs searches for ~X-theme.el~. If you set
~doom-theme~ to ~'third-party-theme~, it will search for
~third-party-theme-theme.el~. This is rarely intentional. Omit the ~-theme~
suffix.
3. Did you run ~doom sync~ after adding your third party theme plugin's
~package!~ declaration to =~/.doom.d/packages.el=?
** TRAMP connections hang forever when connecting
You'll find solutions [[https://www.emacswiki.org/emacs/TrampMode#toc7][on the emacswiki]].
** An upstream package was broken and I can't update it
Sometimes, if you've installed a [[https://github.com/hlissner/doom-emacs/issues/2213][broken package]] which was subsequently fixed
upstream, you can't run ~doom update~ to get the latest fixes due to evaluation
errors.
In those cases, you need to delete the broken local copy before you can install
the new one, which is achieved by either deleting it from
=~/.emacs.d/.local/straight/repos=, or by cycling the module that installs it:
1. Comment out the broken module/package.
2. Run ~doom sync~.
3. Uncomment the module/package.
4. Run ~doom sync~.
** Why do I see ugly indentation highlights for tabs?
[[https://github.com/hlissner/doom-emacs/blob/develop/core/core-ui.el#L132-L150][Doom highlights non-standard indentation]]. i.e. Indentation that doesn't match
the indent style you've set for that file. Spaces are Doom's default style for
most languages (excluding languages where tabs are the norm, like Go).
There are a couple ways to address this:
1. Fix your indentation! If it's highlighted, you have tabs when you should have
spaces (or spaces when you should be using tabs).
Two easy commands for that:
- =M-x tabify=
- =M-x untabify=
2. Change ~indent-tabs-mode~ (nil = spaces, t = tabs) in =~/.doom.d/config.el=:
#+BEGIN_SRC elisp
;; use tab indentation everywhere
(setq-default indent-tabs-mode t)
;; or only in certain modes
(setq-hook! 'sh-mode-hook indent-tabs-mode t) ; shell scripts
(setq-hook! '(c-mode-hook c++-mode-hook) indent-tabs-mode t) ; C/C++
#+END_SRC
3. Use [[https://editorconfig.org/][editorconfig]] to configure code style on a per-project basis. If you
enable Doom's =:tools editorconfig= module, Doom will recognize
=.editorconfigrc= files.
4. Or trust in dtrt-indent; a plugin Doom uses to analyze and detect indentation
when you open a file (that isn't in a project with an editorconfig file).
This isn't foolproof, and won't work for files that have no content in them,
but it can help in one-off scenarios.
* TODO Contributing

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,20 @@
#+TITLE: Doom Emacs Documentation
#+STARTUP: nofold
Doom Emacs is a configuration for [[https://www.gnu.org/software/emacs/][GNU Emacs]] written by a stubborn,
shell-dwelling, and melodramatic ex-vimmer. It is designed to be a foundation
for your own Emacs configuration or a resource for enthusiasts to learn more
about our favorite OS.
Doom is a configuration framework for [[https://www.gnu.org/software/emacs/][GNU Emacs 26.3+]] tailored for Emacs
bankruptcy veterans who want less framework in their frameworks and the
performance of a hand rolled config (or better). It can be a foundation for your
own config or a resource for Emacs enthusiasts to learn more about our favorite
OS.
Doom is an opinionated collection of reasonable (and optional) defaults with a
focus on performance (both runtime and startup) and on abstraction-light,
readable code design, so that there is less between you and Emacs.
#+begin_quote
Github fails to render org links to sub-sections, so it is recommended that you
view the documentation from within Doom Emacs by pressing =<help> d h= (=<help>=
is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
=<help> d /=.
The documentation is designed to be viewed within Doom Emacs. Access it by
pressing =SPC h d h= (or =C-h d h= for non-evil users), or search it with =SPC h
d s= (or =C-h d s=).
#+end_quote
* Table of Contents :TOC:
@ -20,53 +24,47 @@ is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
- [[#frequently-asked-questions][Frequently Asked Questions]]
- [[#contributing][Contributing]]
- [[#workflow-tips-tricks--tutorials][Workflow Tips, Tricks & Tutorials]]
- [[#module-appendix][Module Appendix]]
- [[#community-resources][Community Resources]]
- [[#asking-for-help][Asking for help]]
- [[#project-roadmap][Project roadmap]]
- [[#tutorials--guides][Tutorials & guides]]
- [[#module-list][Module list]]
- [[#app][:app]]
- [[#completion][:completion]]
- [[#config][:config]]
- [[#editor][:editor]]
- [[#emacs][:emacs]]
- [[#email][:email]]
- [[#input][:input]]
- [[#lang][:lang]]
- [[#term][:term]]
- [[#tools][:tools]]
- [[#ui][:ui]]
- [[#projects-that-supportcompliment-doom][Projects that support/compliment Doom]]
- [[#similar-projects][Similar projects]]
* TODO Release Notes
* Documentation
** [[file:getting_started.org][Getting Started]]
- [[file:getting_started.org::*Install][Install]] - How to install Emacs, Doom and its plugins
- [[file:getting_started.org::*Update][Update]] - Keep Doom and its packages up-to-date
- [[file:getting_started.org::*Customize][Customize]] - A primer on customizing and reconfiguring Doom
- [[file:getting_started.org::*Troubleshoot][Troubleshoot]] - How to debug Emacs & Doom, find help or look up documentation
- [[file:getting_started.org::*Install][Install]]
- [[file:getting_started.org::*Update & Rollback][Update & Rollback]]
- [[file:getting_started.org::*Configure][Configure]]
- [[file:getting_started.org::*Migrate][Migrate]]
- [[file:getting_started.org::*Troubleshoot][Troubleshoot]]
** [[file:faq.org][Frequently Asked Questions]]
- [[file:faq.org::*General][General]]
- [[file:faq.org::*Configuration][Configuration]]
- [[file:faq.org::*Package Management][Package Management]]
- [[file:faq.org::*Defaults][Defaults]]
- [[file:faq.org::Common Issues][Common Issues]]
- [[file:faq.org::Contributing][Contributing]]
** TODO [[file:contributing.org][Contributing]]
- [[file:contributing.org::*Where can I help?][Where to get help]]
- Writing an effective bug report
- Suggesting features, keybinds or enhancements
- Contributing code
- Contributing documentation
- [[file:contributing.org::*Where can I help?][Where to get help?]]
- Reporting issues
- Suggesting features, keybinds and enhancements
- Contributing code or documentation
- Other ways to support Doom Emacs
- Special thanks
** TODO [[file:workflow.org][Workflow Tips, Tricks & Tutorials]]
** [[file:modules.org][Module Appendix]]
* Community Resources
** Asking for help
- [[https://discord.gg/bcZ6P3y][Our Discord server]]
- [[https://discord.gg/qvGgnVx][Our Discord server]]
- [[https://github.com/hlissner/doom-emacs/issues][Our issue tracker]]
** Project roadmap
@ -79,11 +77,12 @@ is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
** Tutorials & guides
+ *Doom Emacs*
- (video) [[https://www.youtube.com/watch?v=dr_iBj91eeI][Doom Emacs - Getting Started by DistroTube]]
- (video) [[https://www.youtube.com/playlist?list=PLhXZp00uXBk4np17N39WvB80zgxlZfVwj][DoomCasts]]
- [[https://noelwelsh.com/posts/2019-01-10-doom-emacs.html][Noel's crash course on Doom Emacs]]
- [[https://medium.com/@aria_39488/getting-started-with-doom-emacs-a-great-transition-from-vim-to-emacs-9bab8e0d8458][Getting Started with Doom Emacs -- a great transition from Vim to Emacs]]
- [[https://medium.com/@aria_39488/the-niceties-of-evil-in-doom-emacs-cabb46a9446b][The Niceties of evil in Doom Emacs]]
- [[https://www.youtube.com/playlist?list=PLhXZp00uXBk4np17N39WvB80zgxlZfVwj][DoomCasts (youtube series)]]
- [[https://www.youtube.com/watch?v=GK3fij-D1G8][Org-mode, literate programming in (Doom) Emacs]]
- (video) [[https://www.youtube.com/watch?v=GK3fij-D1G8][Org-mode, literate programming in (Doom) Emacs]]
+ *Emacs & Emacs Lisp*
- [[https://www.gnu.org/software/emacs/manual/html_node/elisp/index.html][The Official Emacs manual]]
- A variety of Emacs resources - https://github.com/ema2159/awesome-emacs
@ -92,186 +91,16 @@ is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
- http://steve-yegge.blogspot.com/2008/01/emergency-elisp.html
- Workflows for customizing Emacs and its packages (and its C/C++ modes):
- https://david.rothlis.net/emacs/customize_c.html
+ *Tools in Emacs*
- [[https://www.emacswiki.org/emacs/Calc_Tutorials_by_Andrew_Hyatt][How to use M-x calc]]
- *Tools in Emacs*
- [[https://www.emacswiki.org/emacs/Calc_Tutorials_by_Andrew_Hyatt][How to use M-x calc]]
+ *Vim & Evil*
- [[https://gist.github.com/dmsul/8bb08c686b70d5a68da0e2cb81cd857f][A crash course on modal editing and Ex commands]]
* Module list
** :app
Application modules are complex and opinionated modules that transform Emacs
toward a specific purpose. They may have additional dependencies and should be
loaded last, before =:config= modules.
** Projects that support/compliment Doom
+ [[https://github.com/plexus/chemacs][plexus/chemacs]]
+ [[https://github.com/r-darwish/topgrade][r-darwish/topgrade]]
+ [[file:../modules/app/calendar/README.org][calendar]] - TODO
+ [[file:../modules/app/irc/README.org][irc]] - how neckbeards socialize
+ rss =+org= - an RSS client in Emacs
+ twitter - A twitter client for Emacs
+ [[file:../modules/app/write/README.org][write]] =+wordnut +langtool= - Transforms emacs into an IDE for writers, and for
writing fiction, notes, papers and so on.
** :completion
Modules that provide new interfaces or frameworks for completion, including code
completion.
+ [[file:../modules/completion/company/README.org][company]] =+childframe +tng= - The ultimate code completion backend
+ helm =+fuzzy +childframe= - *Another* search engine for love and life
+ ido - The /other/ *other* search engine for love and life
+ [[file:../modules/completion/ivy/README.org][ivy]] =+fuzzy +prescient +childframe= - /The/ search engine for love and life
** :config
Modules that configure Emacs one way or another, or focus on making it easier
for you to customize it yourself. It is best to load these last.
+ literate - For users with literate configs. This will tangle+compile a
config.org in your ~doom-private-dir~ when it changes.
+ [[file:../modules/config/default/README.org][default]] =+bindings +smartparens= - The default module sets reasonable defaults
for Emacs. It also provides a Spacemacs-inspired keybinding scheme and a
smartparens config. Use it as a reference for your own modules.
** :editor
Modules that affect and augment your ability to manipulate or insert text.
+ [[file:../modules/editor/evil/README.org][evil]] =+everywhere= - transforms Emacs into Vim
+ [[file:../modules/editor/file-templates/README.org][file-templates]] - Auto-inserted templates in blank new files
+ [[file:../modules/editor/fold/README.org][fold]] - universal code folding
+ format =+onsave= - TODO
+ god - run Emacs commands without modifier keys
+ [[file:../modules/editor/lispy/README.org][lispy]] - TODO
+ multiple-cursors - TODO
+ objed - TODO
+ [[file:../modules/editor/parinfer/README.org][parinfer]] - TODO
+ rotate-text - TODO
+ [[file:../modules/editor/snippets/README.org][snippets]] - Snippet expansion for lazy typists
+ [[file:../modules/editor/word-wrap/README.org][word-wrap]] - soft wrapping with language-aware indent
** :emacs
Modules that reconfigure or augment packages or features built into Emacs.
+ [[file:../modules/emacs/dired/README.org][dired]] =+ranger +icons= - TODO
+ electric - TODO
+ [[file:../modules/emacs/ibuffer/README.org][ibuffer]] =+icons= - TODO
+ vc - TODO
** :email
+ [[file:../modules/email/mu4e/README.org][mu4e]] =+gmail= - TODO
+ notmuch - TODO
+ wanderlust =+gmail= - TODO
** :input
+ chinese - TODO
+ japanese - TODO
** :lang
Modules that bring support for a language or group of languages to Emacs.
+ agda - TODO
+ assembly - TODO
+ [[file:../modules/lang/cc/README.org][cc]] =+lsp= - TODO
+ clojure - TODO
+ common-lisp - TODO
+ [[file:../modules/lang/coq/README.org][coq]] - TODO
+ crystal - TODO
+ [[file:../modules/lang/csharp/README.org][csharp]] - TODO
+ data - TODO
+ [[file:../modules/lang/elixir/README.org][elixir]] =+lsp= - TODO
+ elm - TODO
+ emacs-lisp - TODO
+ erlang - TODO
+ [[file:../modules/lang/ess/README.org][ess]] - TODO
+ [[file:../modules/lang/faust/README.org][faust]] - TODO
+ [[file:../modules/lang/fsharp/README.org][fsharp]] - TODO
+ [[file:../modules/lang/go/README.org][go]] =+lsp= - TODO
+ [[file:../modules/lang/haskell/README.org][haskell]] =+intero +dante +lsp= - TODO
+ hy - TODO
+ [[file:../modules/lang/idris/README.org][idris]] - TODO
+ java =+meghanada +lsp= - TODO
+ [[file:../modules/lang/javascript/README.org][javascript]] =+lsp= - TODO
+ julia - TODO
+ kotlin - TODO
+ [[file:../modules/lang/latex/README.org][latex]] - TODO
+ lean - TODO
+ ledger - TODO
+ lua =+moonscript= - TODO
+ [[file:../modules/lang/markdown/README.org][markdown]] =+grip= - TODO
+ [[file:../modules/lang/nim/README.org][nim]] - TODO
+ nix - TODO
+ [[file:../modules/lang/ocaml/README.org][ocaml]] =+lsp= - TODO
+ [[file:../modules/lang/org/README.org][org]] =+dragndrop +gnuplot +hugo +ipython +pandoc +pomodoro +present= - TODO
+ [[file:../modules/lang/perl/README.org][perl]] - TODO
+ [[file:../modules/lang/php/README.org][php]] =+lsp= - TODO
+ plantuml - TODO
+ purescript - TODO
+ [[file:../modules/lang/python/README.org][python]] =+lsp +pyenv +conda= - TODO
+ qt - TODO
+ racket - TODO
+ [[file:../modules/lang/rest/README.org][rest]] - TODO
+ ruby =+lsp +rvm +rbenv= - TODO
+ [[file:../modules/lang/rust/README.org][rust]] =+lsp= - TODO
+ scala =+lsp= - TODO
+ [[file:../modules/lang/scheme/README.org][scheme]] - TODO
+ [[file:../modules/lang/sh/README.org][sh]] =+fish +lsp= - TODO
+ [[file:../modules/lang/solidity/README.org][solidity]] - TODO
+ swift =+lsp= - TODO
+ terra - TODO
+ web =+lsp= - HTML and CSS (SCSS/SASS/LESS/Stylus) support.
** :term
Modules that offer terminal emulation.
+ eshell - TODO
+ shell - TODO
+ term - TODO
+ [[file:../modules/term/vterm/README.org][vterm]] - TODO
** :tools
Small modules that give Emacs access to external tools & services.
+ ansible - TODO
+ debugger - A (nigh-)universal debugger in Emacs
+ [[file:../modules/tools/direnv/README.org][direnv]] - TODO
+ [[file:../modules/tools/docker/README.org][docker]] - TODO
+ [[file:../modules/tools/editorconfig/README.org][editorconfig]] - TODO
+ [[file:../modules/tools/ein/README.org][ein]] - TODO
+ [[file:../modules/tools/eval/README.org][eval]] =+overlay= - REPL & code evaluation support for a variety of languages
+ flycheck - Live error/warning highlights
+ flyspell - Spell checking
+ gist - TODO
+ [[file:../modules/tools/lookup/README.org][lookup]] =+docsets= - Universal jump-to & documentation lookup backend
+ [[file:../modules/tools/lsp/README.org][lsp]] - TODO
+ macos - TODO
+ magit - TODO
+ make - TODO
+ pass - TODO
+ pdf - TODO
+ prodigy - TODO
+ rgb - TODO
+ terraform - TODO
+ tmux - TODO
+ upload - TODO
+ [[file:../modules/tools/wakatime/README.org][wakatime]] - TODO
** :ui
Aesthetic modules that affect the Emacs interface or user experience.
+ [[file:../modules/ui/deft/README.org][deft]] - TODO
+ [[file:../modules/ui/doom/README.org][doom]] - TODO
+ [[file:../modules/ui/doom-dashboard/README.org][doom-dashboard]] - TODO
+ [[file:../modules/ui/doom-quit/README.org][doom-quit]] - TODO
+ fill-column - TODO
+ [[file:../modules/ui/hl-todo/README.org][hl-todo]] - TODO
+ hydra - TODO
+ indent-guides - TODO
+ [[file:../modules/ui/modeline/README.org][modeline]] - TODO
+ [[file:../modules/ui/nav-flash/README.org][nav-flash]] - TODO
+ [[file:../modules/ui/neotree/README.org][neotree]] - TODO
+ [[file:../modules/ui/ophints/README.org][ophints]] - TODO
+ [[file:../modules/ui/popup/README.org][popup]] =+all +defaults= - Makes temporary/disposable windows less intrusive
+ pretty-code - TODO
+ [[file:../modules/ui/tabs/README.org][tabs]] - TODO
+ treemacs - TODO
+ [[file:../modules/ui/unicode/README.org][unicode]] - TODO
+ vc-gutter - TODO
+ vi-tilde-fringe - TODO
+ [[file:../modules/ui/window-select/README.org][window-select]] =+switch-window +numbers= - TODO
+ [[file:../modules/ui/workspaces/README.org][workspaces]] - Isolated workspaces
** Similar projects
+ [[https://github.com/purcell/emacs.d][purcell/emacs.d]]
+ [[https://github.com/seagle0128/.emacs.d][seagle0128/.emacs.d]]
+ [[https://github.com/syl20bnr/spacemacs][syl20bnr/spacemacs]]

201
docs/modules.org Normal file
View file

@ -0,0 +1,201 @@
#+TITLE: Module Appendix
#+STARTUP: nofold
Functionality in Doom is divided into collections of code called modules (à la
Spacemacs' layers). A module is a bundle of packages, configuration and
commands, organized into a unit that can be enabled or disabled by adding or
removing them from your ~doom!~ block (found in =$DOOMDIR/init.el=).
* Table of Contents :TOC:
- [[#app][:app]]
- [[#checkers][:checkers]]
- [[#completion][:completion]]
- [[#config][:config]]
- [[#editor][:editor]]
- [[#emacs][:emacs]]
- [[#email][:email]]
- [[#input][:input]]
- [[#lang][:lang]]
- [[#term][:term]]
- [[#tools][:tools]]
- [[#ui][:ui]]
* :app
Application modules are complex and opinionated modules that transform Emacs
toward a specific purpose. They may have additional dependencies and should be
loaded last, before =:config= modules.
+ [[file:../modules/app/calendar/README.org][calendar]] - TODO
+ [[file:../modules/app/irc/README.org][irc]] - how neckbeards socialize
+ rss =+org= - an RSS client in Emacs
+ [[file:../modules/app/twitter/README.org][twitter]] - A twitter client for Emacs
* :checkers
+ syntax =+childframe= - Live error/warning highlights
+ spell =+everywhere= - Spell checking
+ grammar - TODO
* :completion
Modules that provide new interfaces or frameworks for completion, including code
completion.
+ [[file:../modules/completion/company/README.org][company]] =+childframe +tng= - The ultimate code completion backend
+ helm =+fuzzy +childframe= - *Another* search engine for love and life
+ ido - The /other/ *other* search engine for love and life
+ [[file:../modules/completion/ivy/README.org][ivy]] =+fuzzy +prescient +childframe= - /The/ search engine for love and life
* :config
Modules that configure Emacs one way or another, or focus on making it easier
for you to customize it yourself. It is best to load these last.
+ literate - For users with literate configs. This will tangle+compile a
config.org in your ~doom-private-dir~ when it changes.
+ [[file:../modules/config/default/README.org][default]] =+bindings +smartparens= - The default module sets reasonable defaults
for Emacs. It also provides a Spacemacs-inspired keybinding scheme and a
smartparens config. Use it as a reference for your own modules.
* :editor
Modules that affect and augment your ability to manipulate or insert text.
+ [[file:../modules/editor/evil/README.org][evil]] =+everywhere= - transforms Emacs into Vim
+ [[file:../modules/editor/file-templates/README.org][file-templates]] - Auto-inserted templates in blank new files
+ [[file:../modules/editor/fold/README.org][fold]] - universal code folding
+ format =+onsave= - TODO
+ [[file:../modules/editor/lispy/README.org][lispy]] - TODO
+ multiple-cursors - TODO
+ [[file:../modules/editor/objed/README.org][objed]] - TODO
+ [[file:../modules/editor/parinfer/README.org][parinfer]] - TODO
+ rotate-text - TODO
+ [[file:../modules/editor/snippets/README.org][snippets]] - Snippet expansion for lazy typists
+ [[file:../modules/editor/word-wrap/README.org][word-wrap]] - soft wrapping with language-aware indent
* :emacs
Modules that reconfigure or augment packages or features built into Emacs.
+ [[file:../modules/emacs/dired/README.org][dired]] =+ranger +icons= - TODO
+ electric - TODO
+ [[file:../modules/emacs/ibuffer/README.org][ibuffer]] =+icons= - TODO
+ vc - TODO
* :email
+ [[file:../modules/email/mu4e/README.org][mu4e]] =+gmail= - TODO
+ notmuch - TODO
+ wanderlust =+gmail= - TODO
* :input
+ [[file:../modules/input/chinese/README.org][chinese]] - TODO
+ [[file:../modules/input/japanese/README.org][japanese]] - TODO
* :lang
Modules that bring support for a language or group of languages to Emacs.
+ [[file:../modules/lang/agda/README.org][agda]] - TODO
+ assembly - TODO
+ [[file:../modules/lang/cc/README.org][cc]] =+lsp= - TODO
+ [[file:/mnt/projects/conf/doom-emacs/modules/lang/clojure/README.org][clojure]] =+lsp= - TODO
+ common-lisp - TODO
+ [[file:../modules/lang/coq/README.org][coq]] - TODO
+ crystal - TODO
+ [[file:../modules/lang/csharp/README.org][csharp]] - TODO
+ data - TODO
+ [[file:../modules/lang/elixir/README.org][elixir]] =+lsp= - TODO
+ elm - TODO
+ emacs-lisp - TODO
+ erlang - TODO
+ [[file:../modules/lang/ess/README.org][ess]] =+lsp= - TODO
+ [[file:../modules/lang/faust/README.org][faust]] - TODO
+ [[file:../modules/lang/fsharp/README.org][fsharp]] - TODO
+ [[file:../modules/lang/fstar/README.org][fstar]] - F* support
+ [[file:../modules/lang/go/README.org][go]] =+lsp= - TODO
+ [[file:../modules/lang/haskell/README.org][haskell]] =+dante +intero +lsp= - TODO
+ hy - TODO
+ [[file:../modules/lang/idris/README.org][idris]] - TODO
+ java =+meghanada +lsp= - TODO
+ [[file:../modules/lang/javascript/README.org][javascript]] =+lsp= - JavaScript, TypeScript, and CoffeeScript support
+ julia - TODO
+ kotlin =+lsp+= - TODO
+ [[file:../modules/lang/latex/README.org][latex]] =+latexmk +cdlatex= - TODO
+ lean - TODO
+ [[file:../modules/lang/ledger/README.org][ledger]] - TODO
+ lua =+moonscript= - TODO
+ [[file:../modules/lang/markdown/README.org][markdown]] =+grip= - TODO
+ [[file:../modules/lang/nim/README.org][nim]] - TODO
+ nix - TODO
+ [[file:../modules/lang/ocaml/README.org][ocaml]] =+lsp= - TODO
+ [[file:../modules/lang/org/README.org][org]] =+brain +dragndrop +gnuplot +hugo +ipython +journal +jupyter +pandoc +pomodoro +present= - TODO
+ [[file:../modules/lang/perl/README.org][perl]] - TODO
+ [[file:../modules/lang/php/README.org][php]] =+lsp= - TODO
+ plantuml - TODO
+ purescript - TODO
+ [[file:../modules/lang/python/README.org][python]] =+lsp +pyenv +conda= - TODO
+ qt - TODO
+ racket - TODO
+ [[file:../modules/lang/rest/README.org][rest]] - TODO
+ ruby =+lsp +rvm +rbenv= - TODO
+ [[file:../modules/lang/rust/README.org][rust]] =+lsp= - TODO
+ scala =+lsp= - TODO
+ [[file:../modules/lang/scheme/README.org][scheme]] - TODO
+ [[file:../modules/lang/sh/README.org][sh]] =+fish +lsp= - TODO
+ [[file:../modules/lang/solidity/README.org][solidity]] - TODO
+ swift =+lsp= - TODO
+ terra - TODO
+ web =+lsp= - HTML and CSS (SCSS/SASS/LESS/Stylus) support.
* :term
Modules that offer terminal emulation.
+ eshell - TODO
+ shell - TODO
+ term - TODO
+ [[file:../modules/term/vterm/README.org][vterm]] - TODO
* :tools
Small modules that give Emacs access to external tools & services.
+ ansible - TODO
+ debugger - A (nigh-)universal debugger in Emacs
+ [[file:../modules/tools/direnv/README.org][direnv]] - TODO
+ [[file:../modules/tools/docker/README.org][docker]] =+lsp= - TODO
+ [[file:../modules/tools/editorconfig/README.org][editorconfig]] - TODO
+ [[file:../modules/tools/ein/README.org][ein]] - TODO
+ [[file:../modules/tools/eval/README.org][eval]] =+overlay= - REPL & code evaluation support for a variety of languages
+ gist - TODO
+ [[file:../modules/tools/lookup/README.org][lookup]] =+dictionary +docsets= - Universal jump-to & documentation lookup
backend
+ [[file:../modules/tools/lsp/README.org][lsp]] - TODO
+ macos - TODO
+ magit - TODO
+ make - TODO
+ pass - TODO
+ pdf - TODO
+ prodigy - TODO
+ rgb - TODO
+ [[file:../modules/tools/terraform/README.org][terraform]]
+ tmux - TODO
+ upload - TODO
* :ui
Aesthetic modules that affect the Emacs interface or user experience.
+ [[file:../modules/ui/deft/README.org][deft]] - TODO
+ [[file:../modules/ui/doom/README.org][doom]] - TODO
+ [[file:../modules/ui/doom-dashboard/README.org][doom-dashboard]] - TODO
+ [[file:../modules/ui/doom-quit/README.org][doom-quit]] - TODO
+ fill-column - TODO
+ [[file:../modules/ui/hl-todo/README.org][hl-todo]] - TODO
+ [[file:../modules/ui/hydra/README.org][hydra]] - TODO
+ indent-guides - TODO
+ [[file:../modules/ui/modeline/README.org][modeline]] - TODO
+ [[file:../modules/ui/nav-flash/README.org][nav-flash]] - TODO
+ [[file:../modules/ui/neotree/README.org][neotree]] - TODO
+ [[file:../modules/ui/ophints/README.org][ophints]] - TODO
+ [[file:../modules/ui/popup/README.org][popup]] =+all +defaults= - Makes temporary/disposable windows less intrusive
+ pretty-code - TODO
+ [[file:../modules/ui/tabs/README.org][tabs]] - TODO
+ treemacs - TODO
+ [[file:../modules/ui/unicode/README.org][unicode]] - TODO
+ vc-gutter - TODO
+ vi-tilde-fringe - TODO
+ [[file:../modules/ui/window-select/README.org][window-select]] =+switch-window +numbers= - TODO
+ [[file:../modules/ui/workspaces/README.org][workspaces]] - Isolated workspaces
+ [[file:../modules/ui/zen/README.org][zen]] - Distraction-free coding (or writing)

View file

@ -1,7 +1,15 @@
#+TITLE: Workflow tips, tricks & tutorials
#+TITLE: Getting to know Doom Emacs
#+STARTUP: nofold
This page is a WIP.
Once you've installed Doom and launched it, the next step of your masochistic
journey is to master it. This guide will walk you through many Doom-centric
workflows you'll commonly find in a text editor (and beyond). It isn't
exhaustive because I don't have enough lives to make it so.
#+begin_quote
If you feel like we've missed something, don't hesitate to let us know! You're
welcome to [[https://discord.gg/qvGgnVx][join us on our Discord server]].
#+end_quote
* Table of Contents :TOC:
- [[#day-1-in-doom-emacs][Day 1 in Doom Emacs]]
@ -14,6 +22,7 @@ This page is a WIP.
- [[#pipe-text-through-ex-commands-and-programs][Pipe text through ex commands and programs]]
- [[#transposingswapping-text][Transposing/swapping text]]
- [[#managing-your-projects][Managing your projects]]
- [[#reconfiguring-emacs-on-a-per-project-basis][Reconfiguring Emacs on a per-project basis]]
- [[#search--replace][Search & replace]]
- [[#project-wide-text-search][Project-wide text search]]
- [[#search--replace-1][Search & replace]]
@ -32,6 +41,8 @@ This page is a WIP.
- [[#using-emacs-for][Using Emacs for...]]
- [[#writing-fiction][Writing fiction]]
- [[#writing-papers][Writing papers]]
- [[#note-keeping][Note-keeping]]
- [[#a-personal-organizer][A Personal Organizer]]
- [[#composing-music][Composing music]]
- [[#game-development][Game development]]
- [[#web-development][Web development]]
@ -48,6 +59,9 @@ This page is a WIP.
** TODO Pipe text through ex commands and programs
** TODO Transposing/swapping text
* TODO Managing your projects
** TODO Reconfiguring Emacs on a per-project basis
*** TODO .dir-locals.el
*** TODO editorconfig
* TODO Search & replace
** TODO Project-wide text search
** TODO Search & replace
@ -66,6 +80,8 @@ This page is a WIP.
* TODO Using Emacs for...
** TODO Writing fiction
** TODO Writing papers
** TODO Note-keeping
** TODO A Personal Organizer
** TODO Composing music
** TODO Game development
** TODO Web development

View file

@ -10,6 +10,7 @@
;; loaded, but after `early-init-file'. Doom handles package initialization, so
;; we must prevent Emacs from doing it early!
(setq package-enable-at-startup nil)
(advice-add #'package--ensure-init-file :override #'ignore)
;; Prevent the glimpse of un-styled Emacs by disabling these UI elements early.
(push '(menu-bar-lines . 0) default-frame-alist)

11
init.el
View file

@ -28,14 +28,13 @@
;;; License: MIT
;; A big contributor to startup times is garbage collection. We up the gc
;; threshold to temporarily prevent it from running, then reset it later with
;; `doom-restore-garbage-collection-h'. Not resetting it will cause
;; stuttering/freezes.
;; threshold to temporarily prevent it from running, then reset it later by
;; enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes.
(setq gc-cons-threshold most-positive-fixnum)
;; In noninteractive sessions, prioritize non-byte-compiled source files to
;; prevent the use of stale byte-code. Otherwise, it saves us a little IO time
;; to skip the mtime checks on every *.elc file we load.
;; to skip the mtime checks on every *.elc file.
(setq load-prefer-newer noninteractive)
(let (file-name-handler-alist)
@ -51,6 +50,4 @@
(if noninteractive
(doom-initialize-packages)
(doom-initialize-core)
(doom-initialize-modules)
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler)))
(doom-initialize-modules))

View file

@ -1,12 +1,18 @@
;;; init.el -*- lexical-binding: t; -*-
;; Copy this file to ~/.doom.d/init.el or ~/.config/doom/init.el ('doom install'
;; will do this for you). The `doom!' block below controls what modules are
;; enabled and in what order they will be loaded. Remember to run 'doom refresh'
;; after modifying it.
;; This file controls what Doom modules are enabled and what order they load in.
;; Remember to run 'doom sync' after modifying it!
;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
;; documentation. There you'll find information about all of Doom's modules
;; and what flags they support.
;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
;; 'C-c g k' for non-vim users) to view its documentation. This works on
;; flags as well (those symbols that start with a plus).
;;
;; More information about these modules (and what flags they support) can be
;; found in modules/README.org.
;; Alternatively, press 'gd' (or 'C-c g d') on a module to browse its
;; directory (for easy access to its source code).
(doom! :input
;;chinese
@ -42,6 +48,7 @@
vi-tilde-fringe ; fringe tildes to mark beyond EOB
window-select ; visually switch windows
workspaces ; tab emulation, persistence & separate workspaces
;;zen ; distraction-free coding or writing
:editor
(evil +everywhere); come to the dark side, we have cookies
@ -69,6 +76,11 @@
;;term ; terminals in Emacs
;;vterm ; another terminals in Emacs
:checkers
syntax ; tasing you for every semicolon you forget
;;spell ; tasing you for misspelling mispelling
;;grammar ; tasing grammar mistake every you make
:tools
;;ansible
;;debugger ; FIXME stepping through code, to help you add bugs
@ -77,8 +89,6 @@
;;editorconfig ; let someone else argue about tabs vs spaces
;;ein ; tame Jupyter notebooks with emacs
(eval +overlay) ; run code, run (also, repls)
flycheck ; tasing you for every semicolon you forget
;;flyspell ; tasing you for misspelling mispelling
;;gist ; interacting with github gists
(lookup ; helps you navigate your code and documentation
+docsets) ; ...or in Dash docsets locally
@ -93,7 +103,6 @@
;;terraform ; infrastructure as code
;;tmux ; an API for interacting with tmux
;;upload ; map local to remote projects via ssh/ftp
;;wakatime
:lang
;;agda ; types of types of types of types...
@ -112,8 +121,9 @@
;;ess ; emacs speaks statistics
;;faust ; dsp, but you get to keep your soul
;;fsharp ; ML stands for Microsoft's Language
;;fstar ; (dependent) types and (monadic) effects and Z3
;;go ; the hipster dialect
;;(haskell +intero) ; a language that's lazier than I am
;;(haskell +dante) ; a language that's lazier than I am
;;hy ; readability of scheme w/ speed of python
;;idris ;
;;(java +meghanada) ; the poster child for carpal tunnel syndrome
@ -122,6 +132,7 @@
;;kotlin ; a better, slicker Java(Script)
;;latex ; writing papers in Emacs has never been so fun
;;lean
;;factor
;;ledger ; an accounting system in Emacs
;;lua ; one-based indices? one-based indices
markdown ; writing docs for people to ignore
@ -131,8 +142,8 @@
(org ; organize your plain life in plain text
+dragndrop ; drag & drop files/images into org buffers
;;+hugo ; use Emacs for hugo blogging
+ipython ; ipython/jupyter support for babel
+pandoc ; export-with-pandoc support
;;+jupyter ; ipython/jupyter support for babel
;;+pandoc ; export-with-pandoc support
;;+pomodoro ; be fruitful with the tomato technique
+present) ; using org-mode for presentations
;;perl ; write code no one else can comprehend
@ -164,7 +175,6 @@
;;irc ; how neckbeards socialize
;;(rss +org) ; emacs as an RSS reader
;;twitter ; twitter client https://twitter.com/vnought
;;write ; emacs for writers (fiction, notes, papers, etc.)
:config
;;literate

View file

@ -3,9 +3,9 @@
(defvar +calendar--wconf nil)
(defun +calendar--init ()
(if-let* ((win (cl-loop for win in (doom-visible-windows)
if (string-match-p "^\\*cfw:" (buffer-name (window-buffer win)))
return win)))
(if-let (win (cl-find-if (lambda (b) (string-match-p "^\\*cfw:" (buffer-name b)))
(doom-visible-windows)
:key #'window-buffer))
(select-window win)
(call-interactively +calendar-open-function)))

View file

@ -1,6 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; app/calendar/packages.el
(package! calfw)
(package! calfw-org)
(package! org-gcal)
(package! calfw :pin "03abce9762")
(package! calfw-org :pin "03abce9762")
(package! org-gcal :pin "6821e34967")

View file

@ -7,8 +7,11 @@
- [[#description][Description]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#dependencies][Dependencies]]
- [[#prerequisites][Prerequisites]]
- [[#macos][macOS]]
- [[#debian--ubuntu][Debian / Ubuntu]]
- [[#arch-linux][Arch Linux]]
- [[#nixos][NixOS]]
- [[#features][Features]]
- [[#an-irc-client-in-emacs][An IRC Client in Emacs]]
- [[#configuration][Configuration]]
@ -17,7 +20,7 @@
- [[#troubleshooting][Troubleshooting]]
* Description
This module turns adds an IRC client to Emacs with OS notifications.
This module turns Emacs into an IRC client, capable of OS notifications.
** Module Flags
This module provides no flags.
@ -26,11 +29,27 @@ This module provides no flags.
+ [[https://github.com/jorgenschaefer/circe][circe]]
+ [[https://github.com/eqyiel/circe-notifications][circe-notifications]]
* Dependencies
This module requires =gnutls-cli= or =openssl= for secure connections.
* Prerequisites
This module has no direct prerequisites.
This module requires =gnutls= for secure IRC connections to work.
** macOS
#+BEGIN_SRC sh
brew install gnutls
#+END_SRC
** Debian / Ubuntu
#+BEGIN_SRC sh
apt install gnutls-bin
#+END_SRC
** Arch Linux
#+BEGIN_SRC sh
pacman -S gnutls
#+END_SRC
** NixOS
#+BEGIN_SRC nix
environment.systemPackages = [ pkgs.gnutls ];
#+END_SRC
* Features
** An IRC Client in Emacs
@ -54,20 +73,23 @@ When in a circe buffer these keybindings will be available.
| ~circe-reconnect~ | =SPC m R= | Reconnect the current server |
* Configuration
Use ~set-irc-server!~ to configure IRC servers. Its second argument (a plist)
Use ~set-irc-server! SERVER PLIST~ to configure IRC servers. Its second argument (a plist)
takes the same arguments as ~circe-network-options~.
#+BEGIN_SRC emacs-lisp :tangle no
(set-irc-server! "chat.freenode.net"
`(:tls t
:nick "doom"
:sasl-username "myusername"
:sasl-password "mypassword"
:channels ("#emacs")))
;; if you omit =:host=, ~SERVER~ will be used instead.
(after! circe
(set-irc-server! "chat.freenode.net"
`(:tls t
:port 6697
:nick "doom"
:sasl-username "myusername"
:sasl-password "mypassword"
:channels ("#emacs"))))
#+END_SRC
*It is a obviously a bad idea to store auth-details in plaintext,* so here are
some ways to avoid that:
However, *it is a obviously a bad idea to store your password in plaintext,* so
here are ways to avoid that:
** Pass: the unix password manager
[[https://www.passwordstore.org/][Pass]] is my tool of choice. I use it to manage my passwords. If you activate the
@ -80,6 +102,7 @@ password store.
#+BEGIN_SRC emacs-lisp :tangle no
(set-irc-server! "chat.freenode.net"
`(:tls t
:port 6697
:nick "doom"
:sasl-username ,(+pass-get-user "irc/freenode.net")
:sasl-password ,(+pass-get-secret "irc/freenode.net")
@ -105,10 +128,10 @@ Note that =+pass-get-user= tries to find your username by looking for the fields
listed in =+pass-user-fields= (by default =login=, =user==, =username== and
=email=)=). An example configuration looks like
#+BEGIN_SRC txt :tangle no
#+begin_example
mysecretpassword
username: myusername
#+END_SRC
#+end_example
** Emacs' auth-source API
~auth-source~ is built into Emacs. As suggested [[https://github.com/jorgenschaefer/circe/wiki/Configuration#safer-password-management][in the circe wiki]], you can store

View file

@ -3,8 +3,9 @@
(defvar +irc--workspace-name "*IRC*")
(defun +irc-setup-wconf (&optional inhibit-workspace)
(unless inhibit-workspace
(+workspace-switch +irc--workspace-name t))
(when (and (featurep! :ui workspaces)
(not inhibit-workspace))
(+workspace-switch +irc--workspace-name 'auto-create))
(let ((buffers (doom-buffers-in-mode 'circe-mode nil t)))
(if buffers
(ignore (switch-to-buffer (car buffers)))
@ -20,17 +21,12 @@
If INHIBIT-WORKSPACE (the universal argument) is non-nil, don't spawn a new
workspace for it."
(interactive "P")
(cond ((and (featurep! :ui workspaces)
(+workspace-exists-p +irc--workspace-name))
(+workspace-switch +irc--workspace-name))
((not (+irc-setup-wconf inhibit-workspace))
(user-error "Couldn't start up a workspace for IRC")))
(if (doom-buffers-in-mode 'circe-mode (buffer-list) t)
(message "Circe buffers are already open")
(if circe-network-options
(cl-loop for network in circe-network-options
collect (circe (car network)))
(call-interactively #'circe))))
(+irc-setup-wconf inhibit-workspace)
(cond ((doom-buffers-in-mode 'circe-mode (doom-buffer-list) t)
(message "Circe buffers are already open"))
(circe-network-options
(mapc #'circe (mapcar #'car circe-network-options)))
((call-interactively #'circe))))
;;;###autoload
(defun +irc/connect (&optional inhibit-workspace)
@ -52,16 +48,17 @@ workspace for it."
(defun +irc/quit ()
"Kill current circe session and workgroup."
(interactive)
(if (y-or-n-p "Really kill IRC session?")
(let (circe-channel-killed-confirmation
circe-server-killed-confirmation)
(when +irc--defer-timer
(cancel-timer +irc--defer-timer))
(disable-circe-notifications)
(mapc #'kill-buffer (doom-buffers-in-mode 'circe-mode (buffer-list) t))
(when (equal (+workspace-current-name) +irc--workspace-name)
(+workspace/delete +irc--workspace-name)))
(message "Aborted")))
(unless (y-or-n-p "Really kill IRC session?")
(user-error "Aborted"))
(let (circe-channel-killed-confirmation
circe-server-killed-confirmation)
(when +irc--defer-timer
(cancel-timer +irc--defer-timer))
(disable-circe-notifications)
(mapc #'kill-buffer (doom-buffers-in-mode 'circe-mode (buffer-list) t))
(when (featurep! :ui workspaces)
(when (equal (+workspace-current-name) +irc--workspace-name)
(+workspace/delete +irc--workspace-name)))))
;;;###autoload
(defun +irc/ivy-jump-to-channel (&optional this-server)
@ -93,7 +90,7 @@ argument) is non-nil only show channels in current server."
;;;###autoload
(defun +irc/tracking-next-buffer ()
"Dissables switching to an unread buffer unless in the irc workspace."
"Disables switching to an unread buffer unless in the irc workspace."
(interactive)
(when (derived-mode-p 'circe-mode)
(tracking-next-buffer)))
@ -106,13 +103,12 @@ argument) is non-nil only show channels in current server."
(defun +circe-buffer-p (buf)
"Return non-nil if BUF is a `circe-mode' buffer."
(with-current-buffer buf
(and (derived-mode-p 'circe-mode)
(eq (safe-persp-name (get-current-persp))
+irc--workspace-name))))
(derived-mode-p 'circe-mode)))
;;;###autoload
(defun +irc--add-circe-buffer-to-persp-h ()
(when (bound-and-true-p persp-mode)
(when (and (bound-and-true-p persp-mode)
(+workspace-exists-p +irc--workspace-name))
(let ((persp (get-current-persp))
(buf (current-buffer)))
;; Add a new circe buffer to irc workspace when we're in another workspace

View file

@ -1,9 +1,17 @@
;;; app/irc/autoload/settings.el -*- lexical-binding: t; -*-
;;;###autodef
(defun set-irc-server! (server letvars)
(defun set-irc-server! (server plist)
"Registers an irc SERVER for circe.
SERVER can either be a name for the network (in which case you must specify a
:host), or it may be the hostname itself, in which case it will be used as the
:host.
See `circe-network-options' for details."
(after! circe
(push (cons server letvars) circe-network-options)))
(unless (plist-member plist :host)
(plist-put! plist :host server))
(setf (alist-get server circe-network-options
nil nil #'equal)
plist)))

View file

@ -93,6 +93,7 @@ playback.")
(add-hook 'doom-real-buffer-functions #'+circe-buffer-p)
(add-hook 'circe-channel-mode-hook #'turn-on-visual-line-mode)
(add-hook 'circe-mode-hook #'+irc--add-circe-buffer-to-persp-h)
(add-hook 'circe-mode-hook #'turn-off-smartparens-mode)
(defadvice! +irc--circe-run-disconnect-hook-a (&rest _)
"Runs `+irc-disconnect-hook' after circe disconnects."
@ -175,7 +176,7 @@ playback.")
(define-key lui-mode-map "\C-u" #'lui-kill-to-beginning-of-line)
(setq lui-fill-type nil)
(when (featurep! :tools flyspell)
(when (featurep! :checkers spell)
(setq lui-flyspell-p t))
(after! evil

View file

@ -1,5 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; app/irc/packages.el
(package! circe)
(package! circe-notifications)
(package! circe :pin "0c79138fb2")
(package! circe-notifications :pin "291149ac12")

View file

@ -49,4 +49,3 @@ https://mediatemple.net"
(set-popup-rules!
'(("^\\*doom-regex\\*$" :size 4 :quit nil)
("^\\*doom-regex-groups" :side 'left :size 28 :select nil :quit nil)))

View file

@ -4,10 +4,6 @@
;; by apps Reeder and Readkit. It can be invoked via `=rss'. Otherwise, if you
;; don't care for the UI you can invoke elfeed directly with `elfeed'.
(defvar +rss-elfeed-files (list "elfeed.org")
"Where to look for elfeed.org files, relative to `org-directory'. Can be
absolute paths.")
(defvar +rss-split-direction 'below
"What direction to pop up the entry buffer in elfeed.")
@ -67,8 +63,11 @@ easier to scroll through.")
(use-package! elfeed-org
:when (featurep! +org)
:after elfeed
:init
(setq rmh-elfeed-org-files (list "elfeed.org"))
:config
(let ((default-directory org-directory))
(setq rmh-elfeed-org-files
(mapcar #'expand-file-name +rss-elfeed-files)))
(elfeed-org))
(and (let ((default-directory org-directory))
(setq rmh-elfeed-org-files
(cl-remove-if-not
#'file-exists-p (mapcar #'expand-file-name rmh-elfeed-org-files))))
(elfeed-org)))

View file

@ -1,5 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; app/rss/packages.el
(package! elfeed)
(package! elfeed-org)
(package! elfeed :pin "3f0edb1737")
(package! elfeed-org :pin "77b6bbf222")

View file

@ -83,6 +83,7 @@ that works with the feature/popup module."
"Open a visible link, username or hashtag in a `twittering-mode' buffer."
(interactive)
(require 'avy)
;; REVIEW Is this necessary anymore with `link-hint'
(let ((pt (avy-with +twitter/ace-link
(avy--process
(+twitter--collect-links)

View file

@ -1,5 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; app/twitter/packages.el
(package! twittering-mode)
(package! avy)
(package! twittering-mode :pin "114891e8fd")
(package! avy :pin "cf95ba9582")

View file

@ -1,131 +0,0 @@
#+TITLE: app/write
#+DATE: October 10, 2019
#+SINCE: v1.3
#+STARTUP: inlineimages
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#language-tool][Language Tool]]
- [[#wordnut][Wordnut]]
- [[#features][Features]]
- [[#m-x-write-mode][~M-x +write-mode~]]
- [[#language-tool-langtool][Language Tool ~+langtool~]]
- [[#commands][Commands]]
- [[#wordnut-wordnut][Wordnut ~+wordnut~]]
- [[#commands-1][Commands]]
- [[#synosaurus][Synosaurus]]
- [[#commands-2][Commands]]
- [[#configuration][Configuration]]
- [[#mixed-pitch-mode][mixed-pitch-mode]]
- [[#appendix][Appendix]]
- [[#minor-modes][Minor modes]]
- [[#commands-3][Commands]]
* Description
Adds word processing tools and the ~+write-mode~ minor mode, which converts
Emacs into a more comfortable writing environment.
** Module Flags
This module provides two module flags:
- ~+langtool~ Enables language tool integration.
- ~+wordnut~ Enables wordnet integration.
** Plugins
+ [[https://github.com/hpdeifel/synosaurus][synosaurus]]
+ [[https://gitlab.com/jabranham/mixed-pitch][mixed-pitch]]
+ [[https://github.com/joostkremers/visual-fill-column][visual-fill-column]]
+ [[https://github.com/mhayashi1120/Emacs-langtool][langtool]]* (=+langtool=)
+ [[https://github.com/gromnitsky/wordnut][wordnut]]* (=+wordnut=)
* Prerequisites
** Language Tool
Either download and deploy it from https://languagetool.org/ or install it
through your OS package manager:
#+BEGIN_SRC sh
# MacOS/Homebrew users:
brew install languagetool
# Arch Linux users:
sudo pacman -S languagetool
#+END_SRC
This module tries to guess the location of languagetool-commandline.jar. If you
get a warning that Doom =couldn't find languagetool-commandline.jar=, you will
need to find langaugetool-commandline.jar and set ~langtool-language-tool-jar~
to its path.
** Wordnut
This requires =wordnet= to be installed, which should be available through your
OS package manager:
#+BEGIN_SRC sh
# MacOS/Homebrew users:
brew install wordnet
# Arch Linux users:
sudo pacaur -S wordnet # on the AUR
#+END_SRC
* Features
** ~M-x +write-mode~
Write mode makes Emacs a more comfortable writing environment by:
- Centering the buffer (with ~visual-fill-column-mode~), ala distraction-free
mode from other text editors.
- Soft-wrapping long text lines with ~visual-line-mode~.
- Enabling ~mixed-pitch-mode~, allowing fixed-width and variable-pitch fonts to
co-exist in one buffer. For example, a monospace font for SRC blocks and Arial
for everything else.
- In org-mode:
- Turns on ~org-indent-mode~
- Turns on ~+org-pretty-mode~
** Language Tool ~+langtool~
[[https://www.languagetool.org/][Language Tool]] is a polyglot proofreader service that checks for grammar and
stylistic issues in your writing. This requires Java 1.8+.
#+begin_quote
This requires Java 1.8+
#+end_quote
*** Commands
- ~langtool-check~
- ~langtool-correct-buffer~
** Wordnut ~+wordnut~
Wordnut provides a searchable dictionary frontend for Emacs. This requires
~wordnet~, which should be available in your OS's package manager.
*** Commands
- ~wordnut-search~
- ~wordnut-lookup-curent-word~
** Synosaurus
Synosaurus provides a service for looking up synonyms. It requires an internet
connection.
*** Commands
- ~synosaurus-lookup~
- ~synosaurus-choose-and-replace~
* Configuration
** mixed-pitch-mode
To configure which faces are displayed with fixed-pitch fonts in
~mixed-pitch-mode~, look into ~mixed-pitch-fixed-pitch-faces~.
* Appendix
** Minor modes
- ~+write-mode~
- ~mixed-pitch-mode~
** Commands
- ~langtool-check~
- ~langtool-correct-buffer~
- ~synosaurus-choose-and-replace~
- ~synosaurus-lookup~
- ~wordnut-lookup-curent-word~
- ~wordnut-search~

View file

@ -1,43 +0,0 @@
;;; app/write/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defvar +write-mode-map (make-sparse-keymap)
"TODO")
;;;###autoload
(define-minor-mode +write-mode
"Turns Emacs into a more comfortable writing environment and word processor."
:init-value nil
:keymap +write-mode-map
(setq-local visual-fill-column-center-text t)
(when +write-text-scale
(text-scale-set (if +write-mode 2 0)))
(when +write-line-spacing
(setq-local line-spacing +write-line-spacing)))
;;;###autoload
(defun +write|init-org-mode ()
"Initializes `org-mode' specific settings for `+write-mode'."
(when (eq major-mode 'org-mode)
(+org-pretty-mode (if +write-mode +1 -1))))
;;;###autoload
(defun +write|init-line-numbers ()
(display-line-numbers-mode (if +write-mode +1 -1)))
;;;###autoload
(defun +write|init-mixed-pitch ()
(mixed-pitch-mode (if +write-mode +1 -1)))
;;;###autoload
(defun +write|init-visual-fill-column ()
(visual-fill-column-mode (if +write-mode +1 -1)))
;;;###autoload
(add-hook! '+write-mode-hook
#'(flyspell-mode
visual-line-mode
+write|init-mixed-pitch
+write|init-visual-fill-column
+write|init-line-numbers
+write|init-org-mode))

View file

@ -1,56 +0,0 @@
;;; app/write/config.el -*- lexical-binding: t; -*-
(defvar +write-text-scale nil
"What to scale the text up to in `+write-mode'. Uses `text-scale-set'.")
(defvar +write-line-spacing nil
"What to set `line-spacing' in `+write-mode'.")
;;
;; Packages
(use-package! langtool
:when (featurep! +langtool)
:commands (langtool-check
langtool-check-done
langtool-show-message-at-point
langtool-correct-buffer)
:init (setq langtool-default-language "en-US")
:config
(unless langtool-language-tool-jar
(setq langtool-language-tool-jar
(cond (IS-MAC
(locate-file "libexec/languagetool-commandline.jar"
(doom-files-in "/usr/local/Cellar/languagetool"
:type 'dirs
:depth 2)))
(IS-LINUX
"/usr/share/java/languagetool/languagetool-commandline.jar")))))
;; `synosaurus'
(setq synosaurus-choose-method 'default)
;; `mixed-pitch'
(after! mixed-pitch
(setq mixed-pitch-fixed-pitch-faces
(append mixed-pitch-fixed-pitch-faces
'(org-todo-keyword-todo
org-todo-keyword-habt
org-todo-keyword-done
org-todo-keyword-wait
org-todo-keyword-kill
org-todo-keyword-outd
org-todo
org-indent
line-number
line-number-current-line
org-special-keyword
org-date
org-property-value
org-special-keyword
org-property-value
org-ref-cite-face
org-tag
font-lock-comment-face))))

View file

@ -1,7 +0,0 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; app/write/doctor.el
(when (featurep! +langtool)
(require 'langtool)
(unless (file-exists-p langtool-language-tool-jar)
(warn! "Couldn't find languagetool-commandline.jar")))

View file

@ -1,12 +0,0 @@
;; -*- no-byte-compile: t; -*-
;;; app/write/packages.el
(package! synosaurus)
(package! mixed-pitch)
(when (featurep! +langtool)
(package! langtool))
(when (featurep! +wordnut)
(package! wordnut))
(package! visual-fill-column)

View file

@ -0,0 +1,68 @@
#+TITLE: checkers/grammar
#+DATE: January 9, 2020
#+SINCE: v3.0.0
#+STARTUP: inlineimages nofold
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]
- [[#maintainers][Maintainers]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#features][Features]]
- [[#language-tool][Language Tool]]
- [[#commands][Commands]]
- [[#writegood-mode][writegood-mode]]
- [[#configuration][Configuration]]
- [[#troubleshooting][Troubleshooting]]
* Description
This module adds grammar checking to Emacs to aid your writing by combining
=lang-tool= and =writegood-mode=.
** Maintainers
This module has no dedicated maintainers.
** Module Flags
This module provides no flags.
** Plugins
+ [[https://github.com/mhayashi1120/Emacs-langtool][langtool]]
+ [[https://github.com/bnbeckwith/writegood-mode][writegood-mode]]
* Prerequisites
This module requires langtool (which requires =Java 1.8+=).
It can be acquired either from https://languagetool.org/ or your OS's package
manager:
+ macOS: ~brew install languagetool~
+ Arch Linux: ~pacman -S languagetool~
This module tries to guess the location of languagetool-commandline.jar. If you
get a warning that Doom =couldn't find languagetool-commandline.jar=, you will
need to set ~langtool-language-tool-jar~ to its location.
* Features
An in-depth list of features, how to use them, and their dependencies.
** Language Tool
[[https://www.languagetool.org/][Language Tool]] is a polyglot proofreader service that checks for grammar and
stylistic issues in your writing. This requires Java 1.8+.
#+begin_quote
This requires Java 1.8+
#+end_quote
*** Commands
- ~langtool-check~
- ~langtool-correct-buffer~
** writegood-mode
This minor mode highlights weasel words, duplication and passive voice.
* Configuration
How to configure this module, including common problems and how to address them.
* Troubleshooting
Common issues and their solution, or places to look for help.

View file

@ -0,0 +1,29 @@
;;; checkers/grammar/config.el -*- lexical-binding: t; -*-
(use-package! langtool
:commands (langtool-check
langtool-check-done
langtool-show-message-at-point
langtool-correct-buffer)
:init (setq langtool-default-language "en-US")
:config
(unless langtool-language-tool-jar
(setq langtool-language-tool-jar
(cond (IS-MAC
(locate-file "libexec/languagetool-commandline.jar"
(doom-files-in "/usr/local/Cellar/languagetool"
:type 'dirs
:depth 2)))
(IS-LINUX
"/usr/share/java/languagetool/languagetool-commandline.jar")))))
;; Detects weasel words, passive voice and duplicates. Proselint would be a
;; better choice.
(use-package! writegood-mode
:hook (org-mode markdown-mode rst-mode asciidoc-mode latex-mode)
:config
(map! :localleader
:map writegood-mode-map
"g" #'writegood-grade-level
"r" #'writegood-reading-ease))

View file

@ -0,0 +1,5 @@
;; -*- no-byte-compile: t; -*-
;;; checkers/grammar/packages.el
(package! langtool :pin "a71ed02ce0")
(package! writegood-mode :pin "b71757ec33")

View file

@ -0,0 +1,27 @@
;;; checkers/spell/autoload.el -*- lexical-binding: t; -*-
;;;###autodef
(defalias 'flyspell-mode! #'flyspell-mode)
(defvar +spell--flyspell-predicate-alist nil
"TODO")
;;;###autodef
(defun set-flyspell-predicate! (modes predicate)
"TODO"
(declare (indent defun))
(dolist (mode (doom-enlist modes) +spell--flyspell-predicate-alist)
(add-to-list '+spell--flyspell-predicate-alist (cons mode predicate))))
;;;###autoload
(defun +spell-init-flyspell-predicate-h ()
"TODO"
(when-let (pred (assq major-mode +spell--flyspell-predicate-alist))
(setq-local flyspell-generic-check-word-predicate (cdr pred))))
;;;###autoload
(defun +spell-correction-at-point-p (&optional point)
"TODO"
(cl-loop for ov in (overlays-at (or point (point)))
if (overlay-get ov 'flyspell-overlay)
return t))

View file

@ -1,11 +1,8 @@
;;; tools/flyspell/config.el -*- lexical-binding: t; -*-
;;; checkers/spell/config.el -*- lexical-binding: t; -*-
;;
;;; Packages
(defvar ispell-dictionary "en_US")
(after! ispell
(add-to-list 'ispell-extra-args "--dont-tex-check-comments")
;; Don't spellcheck org blocks
(pushnew! ispell-skip-region-alist
'(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:")
@ -23,13 +20,13 @@
((executable-find "hunspell") 'hunspell))
(`aspell
(setq ispell-program-name "aspell"
ispell-extra-args '("--sug-mode=ultra" "--run-together"))
ispell-extra-args '("--sug-mode=ultra" "--run-together" "--dont-tex-check-comments"))
(add-hook! 'text-mode-hook
(defun +flyspell-remove-run-together-switch-for-aspell-h ()
(defun +spell-remove-run-together-switch-for-aspell-h ()
(setq-local ispell-extra-args (remove "--run-together" ispell-extra-args))))
(defun +flyspell-setup-ispell-extra-args-a (orig-fun &rest args)
(defun +spell-init-ispell-extra-args-a (orig-fun &rest args)
:around '(ispell-word flyspell-auto-correct-word)
(let ((ispell-extra-args (remove "--run-together" ispell-extra-args)))
(ispell-kill-ispell t)
@ -49,12 +46,23 @@
;; messages for every word when checking the entire buffer
flyspell-issue-message-flag nil)
(add-hook 'text-mode-hook #'flyspell-mode)
(when (featurep! +prog)
(add-hook 'prog-mode-hook #'flyspell-prog-mode))
(add-hook! '(org-mode-hook
markdown-mode-hook
TeX-mode-hook
rst-mode-hook
mu4e-compose-mode-hook
message-mode-hook
git-commit-mode-hook)
#'flyspell-mode)
(when (featurep! +everywhere)
(add-hook! '(yaml-mode-hook
conf-mode-hook
prog-mode-hook)
#'flyspell-prog-mode))
(add-hook! 'flyspell-mode-hook
(defun +flyspell-inhibit-duplicate-detection-maybe-h ()
(defun +spell-inhibit-duplicate-detection-maybe-h ()
"Don't mark duplicates when style/grammar linters are present.
e.g. proselint and langtool."
(when (or (and (bound-and-true-p flycheck-mode)
@ -64,16 +72,21 @@ e.g. proselint and langtool."
;; Ensure mode-local predicates declared with `set-flyspell-predicate!' are
;; used in their respective major modes.
(add-hook 'flyspell-mode-hook #'+flyspell-init-predicate-h)
(add-hook 'flyspell-mode-hook #'+spell-init-flyspell-predicate-h)
(map! :map flyspell-mouse-map
"RET" #'flyspell-correct-word-generic
[return] #'flyspell-correct-word-generic
[mouse-1] #'flyspell-correct-word-generic))
(let ((flyspell-correct
(general-predicate-dispatch nil
(and (not (or mark-active (ignore-errors (evil-insert-state-p))))
(memq 'flyspell-incorrect (face-at-point nil t)))
#'flyspell-correct-at-point)))
(map! :map flyspell-mouse-map
"RET" flyspell-correct
[return] flyspell-correct
[mouse-1] #'flyspell-correct-at-point)))
(use-package! flyspell-correct
:commands flyspell-correct-word-generic flyspell-correct-previous-word-generic
:commands flyspell-correct-at-point flyspell-correct-previous
:config
(cond ((and (featurep! :completion helm)
(require 'flyspell-correct-helm nil t)))
@ -82,3 +95,7 @@ e.g. proselint and langtool."
((require 'flyspell-correct-popup nil t)
(setq flyspell-popup-correct-delay 0.8)
(define-key popup-menu-keymap [escape] #'keyboard-quit))))
(use-package! flyspell-lazy
:after flyspell)

View file

@ -0,0 +1,11 @@
;; -*- no-byte-compile: t; -*-
;;; checkers/spell/packages.el
(package! flyspell-correct :pin "b0353a41a7")
(cond ((featurep! :completion ivy)
(package! flyspell-correct-ivy :pin "b0353a41a7"))
((featurep! :completion helm)
(package! flyspell-correct-helm :pin "b0353a41a7"))
((package! flyspell-correct-popup :pin "b0353a41a7")))
(package! flyspell-lazy :pin "3ebf68cc9e")

View file

@ -0,0 +1,25 @@
;;; checkers/syntax/autoload.el -*- lexical-binding: t; -*-
;;;###autodef
(defun set-next-checker! (mode checker next &optional append)
"TODO"
(let ((fn (intern (format "+syntax--init-checkers-for-%s-h" mode))))
(fset fn
(lambda ()
(if (not (bound-and-true-p flycheck-mode))
(add-hook 'flycheck-mode-hook fn 'append 'local)
(flycheck-add-next-checker checker next append)
(remove-hook 'flycheck-mode-hook fn 'local))))
(add-hook (intern (format "%s-hook" mode)) fn)))
;;;###autoload
(defun +syntax-init-popups-h ()
"Activate `flycheck-posframe-mode' if available and in GUI Emacs.
Activate `flycheck-popup-tip-mode' otherwise.
Do nothing if `lsp-ui-mode' is active and `lsp-ui-sideline-enable' is non-nil."
(unless (and (bound-and-true-p lsp-ui-mode)
lsp-ui-sideline-enable)
(if (and (fboundp 'flycheck-posframe-mode)
(display-graphic-p))
(flycheck-posframe-mode +1)
(flycheck-popup-tip-mode +1))))

View file

@ -1,12 +1,7 @@
;;; tools/flycheck/config.el -*- lexical-binding: t; -*-
(defvar +flycheck-lazy-idle-delay 3.0
"The delay before flycheck checks the buffer, after a check that produces no
errors.")
;;; checkers/syntax/config.el -*- lexical-binding: t; -*-
;;
;;; Packages
;;; Flycheck
(use-package! flycheck
:commands flycheck-list-errors flycheck-buffer
@ -24,11 +19,10 @@ errors.")
;; Don't commandeer input focus if the error message pops up (happens when
;; tooltips and childframes are disabled).
(after! flycheck
(set-popup-rule! flycheck-error-message-buffer :select nil))
(set-popup-rule! "^\\*Flycheck error messages\\*" :select nil)
(add-hook! 'doom-escape-hook :append
(defun +flycheck-buffer-h ()
(defun +syntax-check-buffer-h ()
"Flycheck buffer on ESC in normal mode."
(when flycheck-mode
(ignore-errors (flycheck-buffer))
@ -47,7 +41,7 @@ errors.")
(use-package! flycheck-popup-tip
:commands flycheck-popup-tip-show-popup flycheck-popup-tip-delete-popup
:init (add-hook 'flycheck-mode-hook #'+flycheck-init-popups-h)
:init (add-hook 'flycheck-mode-hook #'+syntax-init-popups-h)
:config
(setq flycheck-popup-tip-error-prefix "")
(after! evil
@ -55,7 +49,7 @@ errors.")
;; the cursor's position or cause disruptive input delays.
(add-hook! '(evil-insert-state-entry-hook evil-replace-state-entry-hook)
#'flycheck-popup-tip-delete-popup)
(defadvice! +flycheck--disable-popup-tip-maybe-a (&rest _)
(defadvice! +syntax--disable-flycheck-popup-tip-maybe-a (&rest _)
:before-while #'flycheck-popup-tip-show-popup
(if evil-local-mode
(eq evil-state 'normal)
@ -65,7 +59,7 @@ errors.")
(use-package! flycheck-posframe
:when (featurep! +childframe)
:defer t
:init (add-hook 'flycheck-mode-hook #'+flycheck-init-popups-h)
:init (add-hook 'flycheck-mode-hook #'+syntax-init-popups-h)
:config
(setq flycheck-posframe-warning-prefix ""
flycheck-posframe-info-prefix "··· "
@ -79,3 +73,7 @@ errors.")
(add-hook! 'flycheck-posframe-inhibit-functions
#'evil-insert-state-p
#'evil-replace-state-p)))
;;
;;; TODO Flymake

View file

@ -0,0 +1,9 @@
;; -*- no-byte-compile: t; -*-
;;; checkers/syntax/packages.el
(package! flycheck :pin "74377fa9c7")
(package! flycheck-popup-tip :pin "ef86aad907")
(when (featurep! +childframe)
(package! flycheck-posframe :pin "2b3e94c2e4"))
;; TODO flymake?

View file

@ -26,9 +26,10 @@ https://assets.doomemacs.org/completion/company/overlay.png
** Module Flags
+ =+childframe= Enables displaying completion candidates in a child frame,
rather than an overlay or tooltip (among with other UI enhancements). *This
requires GUI Emacs 26.1+.*
requires GUI Emacs 26.1+ and is incompatible with the =+tng= flag*
+ =+tng= Enables completion using only ~TAB~. Pressing ~TAB~ will select the
next completion suggestion, while ~S-TAB~ will select the previous one.
next completion suggestion, while ~S-TAB~ will select the previous one. *This
is incompatible with the =+childframe= flag*
** Plugins
+ [[https://github.com/company-mode/company-mode][company-mode]]

View file

@ -20,7 +20,8 @@
:config
(when (featurep! :editor evil)
(add-hook 'company-mode-hook #'evil-normalize-keymaps)
;; Don't persist company popups when switching back to normal mode.
(add-hook 'evil-normal-state-entry-hook #'company-abort)
;; Allow users to switch between backends on the fly. E.g. C-x C-s followed
;; by C-x C-n, will switch from `company-yasnippet' to
;; `company-dabbrev-code'.
@ -70,47 +71,42 @@
company-box-max-candidates 50
company-box-icons-alist 'company-box-icons-all-the-icons
company-box-icons-functions
'(+company-box-icons--yasnippet-fn
company-box-icons--lsp
+company-box-icons--elisp-fn
company-box-icons--acphp)
(cons #'+company-box-icons--elisp-fn
(delq 'company-box-icons--elisp
company-box-icons-functions))
company-box-icons-all-the-icons
`((Unknown . ,(all-the-icons-material "find_in_page" :height 0.8 :face 'all-the-icons-purple))
(Text . ,(all-the-icons-material "text_fields" :height 0.8 :face 'all-the-icons-green))
(Method . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
(Function . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
(Constructor . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
(Field . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
(Variable . ,(all-the-icons-material "adjust" :height 0.8 :face 'all-the-icons-blue))
(Class . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red))
(Interface . ,(all-the-icons-material "settings_input_component" :height 0.8 :face 'all-the-icons-red))
(Module . ,(all-the-icons-material "view_module" :height 0.8 :face 'all-the-icons-red))
(Property . ,(all-the-icons-material "settings" :height 0.8 :face 'all-the-icons-red))
(Unit . ,(all-the-icons-material "straighten" :height 0.8 :face 'all-the-icons-red))
(Value . ,(all-the-icons-material "filter_1" :height 0.8 :face 'all-the-icons-red))
(Enum . ,(all-the-icons-material "plus_one" :height 0.8 :face 'all-the-icons-red))
(Keyword . ,(all-the-icons-material "filter_center_focus" :height 0.8 :face 'all-the-icons-red))
(Snippet . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-red))
(Color . ,(all-the-icons-material "color_lens" :height 0.8 :face 'all-the-icons-red))
(File . ,(all-the-icons-material "insert_drive_file" :height 0.8 :face 'all-the-icons-red))
(Reference . ,(all-the-icons-material "collections_bookmark" :height 0.8 :face 'all-the-icons-red))
(Folder . ,(all-the-icons-material "folder" :height 0.8 :face 'all-the-icons-red))
(EnumMember . ,(all-the-icons-material "people" :height 0.8 :face 'all-the-icons-red))
(Constant . ,(all-the-icons-material "pause_circle_filled" :height 0.8 :face 'all-the-icons-red))
(Struct . ,(all-the-icons-material "streetview" :height 0.8 :face 'all-the-icons-red))
(Event . ,(all-the-icons-material "event" :height 0.8 :face 'all-the-icons-red))
(Operator . ,(all-the-icons-material "control_point" :height 0.8 :face 'all-the-icons-red))
(TypeParameter . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red))
;; (Template . ,(company-box-icons-image "Template.png"))))
(Yasnippet . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-green))
(ElispFunction . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red))
(ElispVariable . ,(all-the-icons-material "check_circle" :height 0.8 :face 'all-the-icons-blue))
(ElispFeature . ,(all-the-icons-material "stars" :height 0.8 :face 'all-the-icons-orange))
(ElispFace . ,(all-the-icons-material "format_paint" :height 0.8 :face 'all-the-icons-pink))))
(defun +company-box-icons--yasnippet-fn (candidate)
(when (get-text-property 0 'yas-annotation candidate)
'Yasnippet))
(let ((all-the-icons-scale-factor 0.8))
`((Unknown . ,(all-the-icons-material "find_in_page" :face 'all-the-icons-purple))
(Text . ,(all-the-icons-material "text_fields" :face 'all-the-icons-green))
(Method . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Function . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Constructor . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Field . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Variable . ,(all-the-icons-material "adjust" :face 'all-the-icons-blue))
(Class . ,(all-the-icons-material "class" :face 'all-the-icons-red))
(Interface . ,(all-the-icons-material "settings_input_component" :face 'all-the-icons-red))
(Module . ,(all-the-icons-material "view_module" :face 'all-the-icons-red))
(Property . ,(all-the-icons-material "settings" :face 'all-the-icons-red))
(Unit . ,(all-the-icons-material "straighten" :face 'all-the-icons-red))
(Value . ,(all-the-icons-material "filter_1" :face 'all-the-icons-red))
(Enum . ,(all-the-icons-material "plus_one" :face 'all-the-icons-red))
(Keyword . ,(all-the-icons-material "filter_center_focus" :face 'all-the-icons-red))
(Snippet . ,(all-the-icons-material "short_text" :face 'all-the-icons-red))
(Color . ,(all-the-icons-material "color_lens" :face 'all-the-icons-red))
(File . ,(all-the-icons-material "insert_drive_file" :face 'all-the-icons-red))
(Reference . ,(all-the-icons-material "collections_bookmark" :face 'all-the-icons-red))
(Folder . ,(all-the-icons-material "folder" :face 'all-the-icons-red))
(EnumMember . ,(all-the-icons-material "people" :face 'all-the-icons-red))
(Constant . ,(all-the-icons-material "pause_circle_filled" :face 'all-the-icons-red))
(Struct . ,(all-the-icons-material "streetview" :face 'all-the-icons-red))
(Event . ,(all-the-icons-material "event" :face 'all-the-icons-red))
(Operator . ,(all-the-icons-material "control_point" :face 'all-the-icons-red))
(TypeParameter . ,(all-the-icons-material "class" :face 'all-the-icons-red))
(Template . ,(all-the-icons-material "short_text" :face 'all-the-icons-green))
(ElispFunction . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(ElispVariable . ,(all-the-icons-material "check_circle" :face 'all-the-icons-blue))
(ElispFeature . ,(all-the-icons-material "stars" :face 'all-the-icons-orange))
(ElispFace . ,(all-the-icons-material "format_paint" :face 'all-the-icons-pink)))))
(defun +company-box-icons--elisp-fn (candidate)
(when (derived-mode-p 'emacs-lisp-mode)
@ -118,7 +114,15 @@
(cond ((fboundp sym) 'ElispFunction)
((boundp sym) 'ElispVariable)
((featurep sym) 'ElispFeature)
((facep sym) 'ElispFace))))))
((facep sym) 'ElispFace)))))
(defadvice! +company-remove-scrollbar-a (orig-fn &rest args)
"This disables the company-box scrollbar, because:
https://github.com/sebastiencs/company-box/issues/44"
:around #'company-box--update-scrollbar
(cl-letf (((symbol-function #'display-buffer-in-side-window)
(symbol-function #'ignore)))
(apply orig-fn args))))
(use-package! company-dict

View file

@ -1,8 +1,8 @@
;; -*- no-byte-compile: t; -*-
;;; completion/company/packages.el
(package! company)
(package! company-dict)
(package! company-prescient)
(package! company :pin "9de9905ed2")
(package! company-dict :pin "cd7b8394f6")
(package! company-prescient :pin "7fd8c3b802")
(when (featurep! +childframe)
(package! company-box))
(package! company-box :pin "8fc6168f2d"))

View file

@ -38,7 +38,7 @@ workspace."
;;; Project search
;;;###autoload
(cl-defun +helm-file-search (&key query in all-files (recursive t))
(cl-defun +helm-file-search (&key query in all-files (recursive t) _prompt args)
"Conduct a file search using ripgrep.
:query STRING
@ -51,46 +51,21 @@ workspace."
(declare (indent defun))
(unless (executable-find "rg")
(user-error "Couldn't find ripgrep in your PATH"))
(require 'helm-ag)
(helm-ag--init-state)
(let* ((project-root (or (doom-project-root) default-directory))
(directory (or in project-root))
(default-directory directory)
(helm-ag--default-directory directory)
(helm-ag--default-target (list directory))
(query (or query
(when (use-region-p)
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
(end (or (bound-and-true-p evil-visual-end) (region-end))))
(when (> (abs (- end beg)) 1)
(rxt-quote-pcre (buffer-substring-no-properties beg end)))))
""))
(prompt (format "[rg %s] "
(cond ((file-equal-p directory project-root)
(projectile-project-name))
((file-equal-p directory default-directory)
"./")
((file-relative-name directory project-root)))))
(command
(list "rg --no-heading --line-number --color never"
"-S"
(when all-files "-z -uu")
(unless recursive "--maxdepth 1")))
(helm-ag-base-command (string-join (delq nil command) " ")))
;; TODO Define our own sources instead
(helm-attrset 'name (format "[rg %s] Searching %s"
(string-join (delq nil (cdr command)) " ")
(abbreviate-file-name directory))
helm-source-do-ag)
(helm-attrset '+helm-command command helm-source-do-ag)
(cl-letf (((symbol-function 'helm-do-ag--helm)
(lambda () (helm :sources '(helm-source-do-ag)
:prompt prompt
:buffer "*helm-rg*"
:keymap helm-do-ag-map
:input query
:history 'helm-ag--helm-history))))
(helm-do-ag directory))))
(require 'helm-rg)
(let ((this-command 'helm-rg)
(helm-rg-default-directory (or in (doom-project-root) default-directory))
(helm-rg-default-extra-args
(delq nil (append (list (when all-files "-z -uu")
(unless recursive "--maxdepth 1"))
args))))
(setq deactivate-mark t)
(helm-rg (or query
(when (use-region-p)
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
(end (or (bound-and-true-p evil-visual-end) (region-end))))
(when (> (abs (- end beg)) 1)
(buffer-substring-no-properties beg end))))
""))))
;;;###autoload
(defun +helm/project-search (&optional arg initial-query directory)

View file

@ -23,6 +23,7 @@ bottom, which is easier on the eyes on big displays."
(setq +helm--posframe-buffer buffer)
:position (point)
:poshandler +helm-posframe-handler
:respect-header-line helm-echo-input-in-header-line
:width
(max (cl-typecase .width
(integer .width)

View file

@ -57,8 +57,6 @@ be negative.")
helm-mode-line-string nil
helm-ff-auto-update-initial-value nil
helm-find-files-doc-header nil
;; Don't override evil-ex's completion
helm-mode-handle-completion-in-region nil
;; Default helm window sizes
helm-display-buffer-default-width nil
helm-display-buffer-default-height 0.25
@ -73,11 +71,13 @@ be negative.")
:init
(when (featurep! +childframe)
;; If this is set to 'iconify-top-level then Emacs will be minimized upon
;; helm completion.
(setq iconify-child-frame 'make-invisible)
(setq helm-display-function #'+helm-posframe-display-fn))
(let ((fuzzy (featurep! +fuzzy)))
(setq helm-M-x-fuzzy-match fuzzy
helm-ag-fuzzy-match fuzzy
helm-apropos-fuzzy-match fuzzy
helm-apropos-fuzzy-match fuzzy
helm-bookmark-show-location fuzzy
@ -101,9 +101,9 @@ be negative.")
;; HACK Doom doesn't support these commands, which invite the user to install
;; the package via ELPA. Force them to use +helm/* instead, because they work
;; out of the box.
(advice-add #'helm-projectile-rg :override #'+helm/rg)
(advice-add #'helm-projectile-ag :override #'+helm/ag)
(advice-add #'helm-projectile-grep :override #'+helm/grep)
(advice-add #'helm-projectile-rg :override #'+helm/project-search)
(advice-add #'helm-projectile-ag :override #'+helm/project-search)
(advice-add #'helm-projectile-grep :override #'+helm/project-search)
;; Hide the modeline
(defun +helm--hide-mode-line (&rest _)
@ -114,6 +114,9 @@ be negative.")
(advice-add #'helm-display-mode-line :override #'+helm--hide-mode-line)
(advice-add #'helm-ag-show-status-default-mode-line :override #'ignore)
;; Hide minibuffer if `helm-echo-input-in-header-line'
(add-hook 'helm-minibuffer-set-up-hook #'helm-hide-minibuffer-maybe)
;; Use helpful instead of describe-* to display documentation
(dolist (fn '(helm-describe-variable helm-describe-function))
(advice-add fn :around #'doom-use-helpful-a)))
@ -125,14 +128,16 @@ be negative.")
:config (helm-flx-mode +1))
(after! helm-ag
(map! :map helm-ag-edit-map :n "RET" #'compile-goto-error)
(define-key helm-ag-edit-map [remap quit-window] #'helm-ag--edit-abort)
(set-popup-rule! "^\\*helm-ag-edit" :size 0.35 :ttl 0 :quit nil)
;; Recenter after jumping to match
(advice-add #'helm-ag--find-file-action :after-while #'doom-recenter-a)
;; And record position before jumping
(advice-add #'helm-ag--find-file-action :around #'doom-set-jump-maybe-a))
(after! helm-rg
(setq helm-rg-display-buffer-normal-method #'pop-to-buffer)
(set-popup-rule! "^helm-rg-" :ttl nil :select t :size 0.45)
(map! :map helm-rg-map
"C-c C-e" #'helm-rg--bounce)
(map! :map helm-rg--bounce-mode-map
"q" #'kill-current-buffer
"C-c C-c" (λ! (helm-rg--bounce-dump) (kill-current-buffer))
"C-x C-c" #'helm-rg--bounce-dump-current-file
"C-c C-k" #'kill-current-buffer))
;;;###package helm-bookmark
@ -176,6 +181,7 @@ be negative.")
(set-keymap-parent helm-projectile-find-file-map helm-map))
(setq ivy-height 20) ; for `swiper-isearch'
(after! swiper-helm
(setq swiper-helm-display-function
(lambda (buf &optional _resume) (pop-to-buffer buf)))

View file

@ -1,16 +1,18 @@
;; -*- no-byte-compile: t; -*-
;;; completion/helm/packages.el
(package! helm)
(package! helm-ag)
(package! helm-c-yasnippet)
(package! helm-company)
(package! helm-describe-modes :recipe (:host github :repo "emacs-helm/helm-describe-modes"))
(package! helm-projectile)
(package! swiper-helm)
(package! helm :pin "8f56312053")
(package! helm-rg :pin "785a80fe5c")
(package! helm-c-yasnippet :pin "65ca732b51")
(package! helm-company :pin "6eb5c2d730")
(package! helm-describe-modes
:recipe (:host github :repo "emacs-helm/helm-describe-modes")
:pin "11fb36af11")
(package! helm-projectile :pin "5328b74ddd")
(package! swiper-helm :pin "93fb6db87b")
(when (featurep! +fuzzy)
(package! helm-flx))
(package! helm-flx :pin "6640fac5cb"))
(when (featurep! +childframe)
(package! posframe))
(package! posframe :pin "087a7fc3c8"))
(when (featurep! :lang org)
(package! helm-org))
(package! helm-org :pin "8457e1e462"))

View file

@ -1,7 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; completion/ido/packages.el
(package! flx-ido)
(package! ido-completing-read+)
(package! ido-vertical-mode)
(package! crm-custom)
(package! flx-ido :pin "17f5c9cb2a")
(package! ido-completing-read+ :pin "74861eabd0")
(package! ido-vertical-mode :pin "16c4c1a112")
(package! crm-custom :pin "f1aaccf643")

View file

@ -14,7 +14,7 @@
- [[#arch-linux][Arch Linux]]
- [[#opensuse][openSUSE]]
- [[#features][Features]]
- [[#jump-to-file-project-navigation][Jump-to-file project navigation]]
- [[#jump-to-navigation][Jump-to navigation]]
- [[#project-search--replace][Project search & replace]]
- [[#in-buffer-searching][In-buffer searching]]
- [[#ivy-integration-for-various-completing-commands][Ivy integration for various completing commands]]
@ -88,7 +88,7 @@ sudo zypper install ripgrep
Ivy and its ilk are large plugins. Covering everything about them is outside of
this documentation's scope, so only Doom-specific Ivy features are listed here:
** Jump-to-file project navigation
** Jump-to navigation
Inspired by Sublime Text's jump-to-anywhere, CtrlP/Unite in Vim, and Textmate's
Command-T, this module provides similar functionality by bringing ~projectile~
and ~ivy~ together.
@ -99,22 +99,23 @@ https://assets.doomemacs.org/completion/ivy/projectile.png
|----------------------+-------------------------------------|
| =SPC p f=, =SPC SPC= | Jump to file in project |
| =SPC f f=, =SPC .= | Jump to file from current directory |
| =SPC s i= | Jump to symbol in file |
** Project search & replace
This module provides interactive text search and replace using ripgrep.
| Keybind | Description |
|-----------+---------------------------------|
| =SPC s b= | Search the current buffer |
| =SPC s p= | Search project |
| =SPC s d= | Search this directory |
| =SPC p t= | List all TODO/FIXMEs in project |
| Keybind | Description |
|-----------+--------------------------|
| =SPC s p= | Search project |
| =SPC s P= | Search another project |
| =SPC s d= | Search this directory |
| =SPC s D= | Search another directory |
https://assets.doomemacs.org/completion/ivy/search.png
The universal argument (=SPC u= for evil users; =C-u= otherwise) changes the
behavior of these commands, instructing the underlying search engine to include
ignored files.
Prefixing these keys with the universal argument (=SPC u= for evil users; =C-u=
otherwise) changes the behavior of these commands, instructing the underlying
search engine to include ignored files.
This module also provides Ex Commands for evil users:
@ -123,15 +124,16 @@ This module also provides Ex Commands for evil users:
| ~:pg[rep][!] [QUERY]~ | Search project (if ~!~, include hidden files) |
| ~:pg[rep]d[!] [QUERY]~ | Search from current directory (if ~!~, don't search recursively) |
The optional BANG functions is equivalent to the universal argument for the
previous commands.
The optional `!` is equivalent to the universal argument for the previous
commands.
-----
While in a search these extra keybindings are available to you:
These keybindings are available while a search is active:
| Keybind | Description |
|-----------+-----------------------------------------------|
| =C-c C-o= | Open a buffer with your search results |
| =C-c C-e= | Open a writable buffer of your search results |
| =C-SPC= | Preview the current candidate |
| =M-RET= | Open the selected candidate in other-window |
@ -146,8 +148,9 @@ https://assets.doomemacs.org/completion/ivy/search-replace.png
The =swiper= package provides an interactive buffer search powered by ivy. It
can be invoked with:
+ =SPC s s=
+ =SPC s S= (uses thing at point as initial input)
+ =SPC s s= (~swiper-isearch~)
+ =SPC s S= (~swiper-isearch-thing-at-point~)
+ =SPC s b= (~swiper~)
+ ~:sw[iper] [QUERY]~
https://assets.doomemacs.org/completion/ivy/swiper.png

View file

@ -21,16 +21,7 @@ Buffers that are considered unreal (see `doom-real-buffer-p') are dimmed with
`+ivy-buffer-unreal-face'."
(let ((b (get-buffer candidate)))
(when (null uniquify-buffer-name-style)
(when-let* ((file-path (buffer-file-name b))
(uniquify-buffer-name-style 'forward))
(setq candidate
(uniquify-get-proposed-name
(replace-regexp-in-string "<[0-9]+>$" "" (buffer-name b))
(directory-file-name
(if file-path
(file-name-directory file-path)
default-directory))
1))))
(setq candidate (replace-regexp-in-string "<[0-9]+>$" "" candidate)))
(cond ((ignore-errors
(file-remote-p
(buffer-local-value 'default-directory b)))
@ -165,10 +156,10 @@ If ARG (universal argument), open selection in other-window."
(user-error "No completion session is active"))
(require 'wgrep)
(let ((caller (ivy-state-caller ivy-last)))
(if-let* ((occur-fn (plist-get +ivy-edit-functions caller)))
(if-let (occur-fn (plist-get +ivy-edit-functions caller))
(ivy-exit-with-action
(lambda (_) (funcall occur-fn)))
(if-let* ((occur-fn (plist-get ivy--occurs-list caller)))
(if-let (occur-fn (plist-get ivy--occurs-list caller))
(let ((buffer (generate-new-buffer
(format "*ivy-occur%s \"%s\"*"
(if caller (concat " " (prin1-to-string caller)) "")
@ -222,22 +213,26 @@ non-project, `projectile-find-file' if in a big project (more than
The point of this is to avoid Emacs locking up indexing massive file trees."
(interactive)
(call-interactively
(cond ((or (file-equal-p default-directory "~")
(when-let (proot (doom-project-root))
(file-equal-p proot "~")))
#'counsel-find-file)
;; Spoof the command so that ivy/counsel will display the (well fleshed-out)
;; actions list for `counsel-find-file' on C-o. The actions list for the other
;; commands aren't as well configured or are empty.
(let ((this-command 'counsel-find-file))
(call-interactively
(cond ((or (file-equal-p default-directory "~")
(when-let (proot (doom-project-root))
(file-equal-p proot "~")))
#'counsel-find-file)
((doom-project-p)
(let ((files (projectile-current-project-files)))
(if (<= (length files) ivy-sort-max-size)
#'counsel-projectile-find-file
#'projectile-find-file)))
((doom-project-p)
(let ((files (projectile-current-project-files)))
(if (<= (length files) ivy-sort-max-size)
#'counsel-projectile-find-file
#'projectile-find-file)))
(#'counsel-file-jump))))
(#'counsel-file-jump)))))
;;;###autoload
(cl-defun +ivy-file-search (&key query in all-files (recursive t))
(cl-defun +ivy-file-search (&key query in all-files (recursive t) prompt args)
"Conduct a file search using ripgrep.
:query STRING
@ -251,36 +246,35 @@ The point of this is to avoid Emacs locking up indexing massive file trees."
(unless (executable-find "rg")
(user-error "Couldn't find ripgrep in your PATH"))
(require 'counsel)
(let* ((ivy-more-chars-alist '((t . 1)))
(let* ((this-command 'counsel-rg)
(project-root (or (doom-project-root) default-directory))
(directory (or in project-root))
(default-directory directory)
(args (concat (if all-files " -uu")
(unless recursive " --maxdepth 1"))))
(unless recursive " --maxdepth 1")
" "
(mapconcat #'shell-quote-argument args " "))))
(setq deactivate-mark t)
(counsel-rg
(or (if query query)
(when (use-region-p)
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
(end (or (bound-and-true-p evil-visual-end) (region-end))))
(when (> (abs (- end beg)) 1)
(let ((query (buffer-substring-no-properties beg end)))
;; Escape characters that are special to ivy searches
(replace-regexp-in-string "[! |]" (lambda (substr)
(cond ((and (string= substr " ")
(not (featurep! +fuzzy)))
" ")
((string= substr "|")
"\\\\\\\\|")
((concat "\\\\" substr))))
(rxt-quote-pcre query)))))))
(or query
(when (doom-region-active-p)
(replace-regexp-in-string
"[! |]" (lambda (substr)
(cond ((and (string= substr " ")
(not (featurep! +fuzzy)))
" ")
((string= substr "|")
"\\\\\\\\|")
((concat "\\\\" substr))))
(rxt-quote-pcre (doom-thing-at-point-or-region)))))
directory args
(format "rg%s %s"
args
(cond ((equal directory default-directory)
"./")
((equal directory project-root)
(projectile-project-name))
((file-relative-name directory project-root)))))))
(or prompt
(format "rg%s [%s]: "
args
(cond ((equal directory default-directory)
"./")
((equal directory project-root)
(projectile-project-name))
((file-relative-name directory project-root))))))))
;;;###autoload
(defun +ivy/project-search (&optional arg initial-query directory)

View file

@ -7,16 +7,6 @@ When nil, don't preview anything.
When non-nil, preview non-virtual buffers.
When 'everything, also preview virtual buffers")
(defvar +ivy-project-search-engines '(rg ag)
"What search tools for `+ivy/project-search' (and `+ivy-file-search' when no
ENGINE is specified) to try, and in what order.
To disable a particular tool, remove it from this list. To prioritize a tool
over others, move it to the front of the list. Later duplicates in this list are
silently ignored.
If you want to already use git-grep or grep, set this to nil.")
(defvar +ivy-buffer-unreal-face 'font-lock-comment-face
"The face for unreal buffers in `ivy-switch-to-buffer'.")
@ -24,18 +14,6 @@ If you want to already use git-grep or grep, set this to nil.")
"A plist mapping ivy/counsel commands to commands that generate an editable
results buffer.")
(defvar +ivy-standard-search-fn
(if (featurep! +prescient)
#'+ivy-prescient-non-fuzzy
#'ivy--regex-plus)
"Function to use for non-fuzzy search commands.")
(defvar +ivy-alternative-search-fn
(cond ((featurep! +prescient) #'ivy-prescient-re-builder)
((featurep! +fuzzy) #'ivy--regex-fuzzy)
(#'ivy--regex-ignore-order))
"Function to use for fuzzy search commands.")
;;
;;; Packages
@ -43,15 +21,24 @@ results buffer.")
(use-package! ivy
:after-call pre-command-hook
:init
(setq ivy-re-builders-alist
`(,@(cl-loop for cmd in '(counsel-ag
counsel-rg
counsel-grep
swiper
swiper-isearch)
collect (cons cmd +ivy-standard-search-fn))
;; Ignore order for non-fuzzy searches by default
(t . ,+ivy-alternative-search-fn)))
(let ((standard-search-fn
(if (featurep! +prescient)
#'+ivy-prescient-non-fuzzy
#'ivy--regex-plus))
(alt-search-fn
(if (featurep! +fuzzy)
#'ivy--regex-fuzzy
;; Ignore order for non-fuzzy searches by default
#'ivy--regex-ignore-order)))
(setq ivy-re-builders-alist
`((counsel-rg . ,standard-search-fn)
(swiper . ,standard-search-fn)
(swiper-isearch . ,standard-search-fn)
(t . ,alt-search-fn))
ivy-more-chars-alist
'((counsel-rg . 1)
(counsel-search . 2)
(t . 3))))
(define-key!
[remap switch-to-buffer] #'+ivy/switch-buffer
@ -75,7 +62,7 @@ results buffer.")
;; ...but if that ever changes, show their full path
ivy-virtual-abbreviate 'full
;; don't quit minibuffer on delete-error
ivy-on-del-error-function nil
ivy-on-del-error-function #'ignore
;; enable ability to select prompt (alternative to `ivy-immediate-done')
ivy-use-selectable-prompt t)
@ -110,7 +97,9 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
(let ((completion-in-region-function #'completion--in-region))
(apply orig-fn args)))
(define-key ivy-minibuffer-map (kbd "C-c C-e") #'+ivy/woccur)
(define-key! ivy-minibuffer-map
"C-c C-e" #'+ivy/woccur
[remap doom/delete-backward-word] #'ivy-backward-kill-word)
(ivy-mode +1)
@ -128,6 +117,8 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
(use-package! ivy-rich
:after ivy
:config
(setq ivy-rich-parse-remote-buffer nil)
(when (featurep! +icons)
(cl-pushnew '(+ivy-rich-buffer-icon)
(cadr (plist-get ivy-rich-display-transformers-list
@ -182,61 +173,52 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
(define-key!
[remap apropos] #'counsel-apropos
[remap bookmark-jump] #'counsel-bookmark
[remap compile] #'+ivy/compile
[remap describe-bindings] #'counsel-descbinds
[remap describe-face] #'counsel-faces
[remap describe-function] #'counsel-describe-function
[remap describe-variable] #'counsel-describe-variable
[remap describe-bindings] #'counsel-descbinds
[remap set-variable] #'counsel-set-variable
[remap evil-ex-registers] #'counsel-evil-registers
[remap evil-show-marks] #'counsel-mark-ring
[remap execute-extended-command] #'counsel-M-x
[remap find-file] #'counsel-find-file
[remap find-library] #'counsel-find-library
[remap info-lookup-symbol] #'counsel-info-lookup-symbol
[remap imenu] #'counsel-imenu
[remap recentf-open-files] #'counsel-recentf
[remap swiper] #'counsel-grep-or-swiper
[remap evil-ex-registers] #'counsel-evil-registers
[remap evil-show-marks] #'counsel-mark-ring
[remap yank-pop] #'counsel-yank-pop
[remap info-lookup-symbol] #'counsel-info-lookup-symbol
[remap load-theme] #'counsel-load-theme
[remap locate] #'counsel-locate
[remap org-set-tags-command] #'counsel-org-tag
[remap projectile-compile-project] #'+ivy/project-compile
[remap recentf-open-files] #'counsel-recentf
[remap set-variable] #'counsel-set-variable
[remap swiper] #'counsel-grep-or-swiper
[remap unicode-chars-list-chars] #'counsel-unicode-char
[remap compile] #'+ivy/compile
[remap projectile-compile-project] #'+ivy/project-compile)
[remap yank-pop] #'counsel-yank-pop)
:config
(set-popup-rule! "^\\*ivy-occur" :size 0.35 :ttl 0 :quit nil)
;; HACK Fix an issue where `counsel-projectile-find-file-action' would try to
;; open a candidate in an occur buffer relative to the wrong buffer,
;; causing it to fail to find the file we want.
(defadvice! +ivy--run-from-ivy-directory-a (orig-fn &rest args)
:around #'counsel-projectile-find-file-action
(let ((default-directory (ivy-state-directory ivy-last)))
(apply orig-fn args)))
;; Don't use ^ as initial input. Set this here because `counsel' defines more
;; of its own, on top of the defaults.
(setq ivy-initial-inputs-alist nil)
;; REVIEW Move this somewhere else and perhaps generalize this so both
;; ivy/helm users can enjoy it.
(defadvice! +ivy--counsel-file-jump-use-fd-rg-a (args)
"Change `counsel-file-jump' to use fd or ripgrep, if they are available."
:override #'counsel--find-return-list
(cl-destructuring-bind (find-program . args)
(cond ((executable-find "fd")
(cons "fd" (list "-t" "f" "-E" ".git")))
((executable-find "rg")
(cons "rg" (list "--files" "--hidden" "--no-messages")))
((cons find-program args)))
(unless (listp args)
(user-error "`counsel-file-jump-args' is a list now, please customize accordingly."))
(counsel--call
(cons find-program args)
(lambda ()
(goto-char (point-min))
(let ((offset (if (member find-program '("fd" "rg")) 0 2))
files)
(while (< (point) (point-max))
(push (buffer-substring
(+ offset (line-beginning-position)) (line-end-position)) files)
(forward-line 1))
(nreverse files))))))
;; Integrate with `helpful'
(setq counsel-describe-function-function #'helpful-callable
counsel-describe-variable-function #'helpful-variable)
;; Record in jumplist when opening files via counsel-{ag,rg,pt,git-grep}
(add-hook 'counsel-grep-post-action-hook #'better-jumper-set-jump)
(ivy-add-actions
'counsel-rg ; also applies to `counsel-rg'
'(("O" +ivy-git-grep-other-window-action "open in other window")))
;; Make `counsel-compile' projectile-aware (if you prefer it over
;; `+ivy/compile' and `+ivy/project-compile')
(add-to-list 'counsel-compile-root-functions #'projectile-project-root)
@ -244,51 +226,62 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
;; Persist `counsel-compile' history
(add-to-list 'savehist-additional-variables 'counsel-compile-history))
;; Use spotlight on mac for `counsel-locate' by default
;; `counsel-imenu' -- no sorting for imenu. Sort it by appearance in page.
(add-to-list 'ivy-sort-functions-alist '(counsel-imenu))
;; `counsel-locate'
(when IS-MAC
;; Use spotlight on mac by default since it doesn't need any additional setup
(setq counsel-locate-cmd #'counsel-locate-cmd-mdfind))
;; `swiper'
;; Don't mess with font-locking on the dashboard; it causes breakages
(add-to-list 'swiper-font-lock-exclude #'+doom-dashboard-mode)
;; Record in jumplist when opening files via counsel-{ag,rg,pt,git-grep}
(add-hook 'counsel-grep-post-action-hook #'better-jumper-set-jump)
;; Factories
(defun +ivy-action-reloading (cmd)
(lambda (x)
(funcall cmd x)
(ivy--reset-state ivy-last)))
(defun +ivy-action-given-file (cmd prompt)
(lambda (source)
(let* ((enable-recursive-minibuffers t)
(target (read-file-name (format "%s %s to:" prompt source))))
(funcall cmd source target 1))))
;; Configure `counsel-find-file'
;; `counsel-find-file'
(setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)")
(ivy-add-actions
'counsel-find-file
`(("b" counsel-find-file-cd-bookmark-action "cd bookmark")
("s" counsel-find-file-as-root "open as root")
("m" counsel-find-file-mkdir-action "mkdir")
("c" ,(+ivy-action-given-file #'copy-file "Copy file") "copy file")
("d" ,(+ivy-action-reloading #'+ivy-confirm-delete-file) "delete")
("r" (lambda (path) (rename-file path (read-string "New name: "))) "rename")
("R" ,(+ivy-action-reloading (+ivy-action-given-file #'rename-file "Move")) "move")
("f" find-file-other-window "other window")
("F" find-file-other-frame "other frame")
("p" (lambda (path) (with-ivy-window (insert (file-relative-name path default-directory)))) "insert relative path")
("P" (lambda (path) (with-ivy-window (insert path))) "insert absolute path")
("l" (lambda (path) "Insert org-link with relative path"
(with-ivy-window (insert (format "[[./%s]]" (file-relative-name path default-directory))))) "insert org-link (rel. path)")
("L" (lambda (path) "Insert org-link with absolute path"
(with-ivy-window (insert (format "[[%s]]" path)))) "insert org-link (abs. path)")))
(dolist (fn '(counsel-rg counsel-find-file))
(ivy-add-actions
fn '(("p" (lambda (path) (with-ivy-window (insert (file-relative-name path default-directory))))
"insert relative path")
("P" (lambda (path) (with-ivy-window (insert path)))
"insert absolute path")
("l" (lambda (path) (with-ivy-window (insert (format "[[./%s]]" (file-relative-name path default-directory)))))
"insert relative org-link")
("L" (lambda (path) (with-ivy-window (insert (format "[[%s]]" path))))
"Insert absolute org-link"))))
(ivy-add-actions
'counsel-ag ; also applies to `counsel-rg'
'(("O" +ivy-git-grep-other-window-action "open in other window"))))
(ivy-add-actions 'counsel-file-jump (plist-get ivy--actions-list 'counsel-find-file))
;; `counsel-search': use normal page for displaying results, so that we see
;; custom ddg themes (if one is set).
(setf (nth 1 (alist-get 'ddg counsel-search-engines-alist))
"https://duckduckgo.com/?q=")
;; REVIEW Move this somewhere else and perhaps generalize this so both
;; ivy/helm users can enjoy it.
(defadvice! +ivy--counsel-file-jump-use-fd-rg-a (args)
"Change `counsel-file-jump' to use fd or ripgrep, if they are available."
:override #'counsel--find-return-list
(cl-destructuring-bind (find-program . args)
(cond ((executable-find doom-projectile-fd-binary)
(cons doom-projectile-fd-binary (list "-t" "f" "-E" ".git")))
((executable-find "rg")
(split-string (format counsel-rg-base-command "--files --no-messages") " " t))
((cons find-program args)))
(unless (listp args)
(user-error "`counsel-file-jump-args' is a list now, please customize accordingly."))
(counsel--call
(cons find-program args)
(lambda ()
(goto-char (point-min))
(let ((offset (if (member find-program (list "rg" doom-projectile-fd-binary)) 0 2))
files)
(while (< (point) (point-max))
(push (buffer-substring
(+ offset (line-beginning-position)) (line-end-position)) files)
(forward-line 1))
(nreverse files)))))))
(use-package! counsel-projectile
@ -310,7 +303,10 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
#'+ivy/projectile-find-file)
;; no highlighting visited files; slows down the filtering
(ivy-set-display-transformer #'counsel-projectile-find-file nil))
(ivy-set-display-transformer #'counsel-projectile-find-file nil)
(if (featurep! +prescient)
(setq counsel-projectile-sort-files t)))
(use-package! wgrep
@ -332,8 +328,10 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
(setf (alist-get t ivy-posframe-display-functions-alist)
#'+ivy-display-at-frame-center-near-bottom-fn)
;; posframe doesn't work well with async sources
(dolist (fn '(swiper counsel-ag counsel-grep counsel-git-grep))
;; posframe doesn't work well with async sources (the posframe will
;; occasionally stop responding/redrawing), and causes violent resizing of the
;; posframe.
(dolist (fn '(swiper counsel-rg counsel-grep counsel-git-grep))
(setf (alist-get fn ivy-posframe-display-functions-alist)
#'ivy-display-function-fallback)))
@ -353,7 +351,6 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
(if (featurep! +fuzzy)
'(literal regexp initialism fuzzy)
'(literal regexp initialism))
ivy-prescient-enable-filtering nil ; we do this ourselves
ivy-prescient-retain-classic-highlighting t)
:config

View file

@ -1,22 +1,23 @@
;; -*- no-byte-compile: t; -*-
;;; completion/ivy/packages.el
(package! amx)
(package! swiper :pin "7084d60312")
(package! ivy)
(package! counsel)
(package! counsel-projectile)
(package! swiper)
(package! ivy-hydra)
(package! ivy-rich)
(package! wgrep)
(package! counsel)
(package! amx :pin "e512e74e83")
(package! counsel-projectile :pin "b556ed8995")
(package! ivy-rich :pin "af43abad5c")
(package! wgrep :pin "5977b8e000")
(if (featurep! +prescient)
(package! ivy-prescient)
(package! ivy-prescient :pin "7fd8c3b802")
(when (featurep! +fuzzy)
(package! flx)))
(package! flx :pin "17f5c9cb2a")))
(when (featurep! +childframe)
(package! ivy-posframe))
(package! ivy-posframe :pin "6d697ff00a"))
(when (featurep! +icons)
(package! all-the-icons-ivy))
(package! all-the-icons-ivy :pin "a70cbfa1ef"))

Some files were not shown because too many files have changed in this diff Show more