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 name: Bug report
about: Something went wrong, please fix it! about: Doom might be misbehaving
labels: is:bug labels: is:bug
title: "[BUG] "
assignees: ''
--- ---
**Describe the issue** **What did you expect to happen?**
Start with a brief 1 or 2 sentence summary of issue. ...
Then follow with a longer explanation, if necessary. Here are some suggestions
on what to include: **What actually happened?**
- 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) **Additional details:**
- Any warnings or errors logged to \*Messages\* (`SPC h e` or `M-x - Include a link to your private config
view-echo-area-messages`). - 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> <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 How to acquire a backtrace:
are ways to enable `debug-on-error`: https://github.com/hlissner/doom-emacs/blob/develop/docs/getting_started.org#how-to-extract-a-backtrace-from-an-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.
</pre></details> </pre></details>
**Steps to reproduce** **Steps to reproduce:**
1. Select these example steps, 1. Select these example steps,
2. Delete them, 2. Delete them,
3. And replace them with precise steps to reproduce your issue. 3. And replace them with precise steps to reproduce your issue.
4. Fill in "system information" below. 4. Fill in "system information" below.
**System information** **System information:**
<details><pre> <details><pre>
Place 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> </pre></details>

View file

@ -1,28 +1,20 @@
--- ---
name: Feature request name: Feature request
about: Make suggestions for improving Doom Emacs about: It'd be cool if Doom did/had/would...
labels: is:request labels: is:new
title: "[REQUEST] "
assignees: ''
--- ---
**Describe the feature** **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 new plugins, include links to them
- iF the feature involves replacement of current functionality, describe how the - If the feature involves replacement of current functionality, how the new
new functionality is better. functionality is better?
- If the feature is implemented in another editor Emacs distro: - If the feature is implemented in another editor or Emacs distro, include:
- Include screenshots or screencasts of it - Screenshots or screencasts of it
- Include links to its implementation - Links to its implementation
- Include names of commands (and not just the keybinds to invoke them) - Names of relevant commands (and not only the keybinds to invoke them)
**System information** **System information**
<details><pre> <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> </pre></details>

View file

@ -1,23 +1,26 @@
--- ---
name: How do I... name: How do I...
about: How to get Doom/Emacs to behave a certain way about: How to get Doom/Emacs to behave a certain way
labels: is:howto, status:pending-review labels: is:question
title: "[HOWTO] "
assignees: ''
--- ---
**What I want to achieve** > Please visit our Discord server to ask how-to and workflow questions:
Start with a brief 1 or 2 sentence summary of what you're trying to achieve. > 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 **What are you trying to achieve?**
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 **What have you tried?**
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). **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** **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: name: General Contribution
> - [ ] This PR targets the develop branch and not master 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 > - [ ] If your PR is a work in progress, include [WIP] in its title
> - [ ] Its commits' summaries are reasonably descriptive > - [ ] Its commits' summaries are reasonably descriptive
> - [ ] You've described what this PR addresses below > - [ ] You've described what this PR addresses below

5
.gitignore vendored
View file

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

View file

@ -1,6 +1,6 @@
The MIT License (MIT) 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 Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the 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"> <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"> <img src="https://github.com/hlissner/doom-emacs/workflows/CI/badge.svg" alt="Build status: develop">
</a> </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"> <img src="https://img.shields.io/badge/Discord-blue.svg?logo=discord&label=join" alt="Join our discord server" align="right">
</a> </a>
<br><br> <br><br>
@ -35,6 +35,9 @@ git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
~/.emacs.d/bin/doom install ~/.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** **Table of Contents**
- [What is Doom Emacs](#what-is-doom-emacs) - [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 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. 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/) Doom is a configuration framework for [GNU
designed to make Emacs faster and easier to customize. It can serve as framework Emacs](https://www.gnu.org/software/emacs/) tailored for Emacs bankruptcy
for your own configuration or a resource for fellow Emacs enthusiasts who want veterans who want less framework in their frameworks and the performance of a
to learn more about our favorite OS. 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 ## Doom's mantras
- **Gotta go fast.** Startup and run-time performance are high priorities. - **Gotta go fast.** Startup and run-time performance are priorities. Doom goes
Expensive functionality (built-in or in plugins) is modified and optimized beyond lazy loading packages by modifying them to be snappier and load lazier!
toward this end, otherwise, they must be opt-in. - **Close to metal.** There's less between you and vanilla Emacs by design.
- **Close to metal.** There's less between you and vanilla Emacs, by design. There's less to grok, on top of Emacs.
There's less to grok. Modules should be syntactically sweet and backend logic - **Readability counts.** Internals ought to be written as if reading them were
explicit and abstraction-light. The code itself ought to be designed as if part of the user experience, and it is! Modules should be syntactically sweet.
grokking it were part of the user experience; and it is! Backend logic should be functional (as much as elisp permits), abstraction
- **Opinionated, but not stubborn.** Doom is a bundle of reasonable defaults light and (hopefully) documented.
and curated opinions, but you aren't stuck with it. Use as little or as much - **Opinionated, but not stubborn.** Doom is a bundle of reasonable defaults and
of it as you like. Use it as-is as a complete Emacs distribution; disable curated opinions, but all of it should be optional. Use as little or as much
everything and use it as a baseline for your own; or anywhere in between. of it as you like.
- **Your system, your rules.** There are more ways to set up your programming - **Your system, your rules.** There are more ways to set up your development
environment than there are dislikes on Youtube Rewind '18, so Doom and its environment than there are dislikes on Youtube Rewind '18, so Doom leaves it
plugins promise not to *automatically* (and definitely not *silently*) install to you. Doom will not *automatically* install system dependencies (and will
system dependencies. This means fonts, packages and programs. `doom doctor` coerce its plugins not to do so either). Use `doom doctor` to figure out
will tell you what's missing though! what's missing.
## Features ## 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 - A curated set of sane defaults for all packages, all (major) OSes, and Emacs
itself. itself.
- Support for *many* programming languages. Too many to list. Includes syntax - Support for *many* programming languages. Too many to list. Includes syntax
highlighting, linters/checker integration, inline code evaluation, code highlighting, linters/checker integration, inline code evaluation, code
completion (where possible), REPLs, documentation lookups, snippets, and more! completion (where possible), REPLs, documentation lookups, snippets, and more!
- Support for *many* tools, like docker, pass, ansible, terraform, 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 - 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 and localleader prefix keys (<kbd>SPC</kbd> and <kbd>SPC</kbd><kbd>m</kbd>, by
default). default).
@ -104,12 +108,11 @@ to learn more about our favorite OS.
integration. Let someone else argue about tabs vs **\_\***spaces**\*\_**. integration. Let someone else argue about tabs vs **\_\***spaces**\*\_**.
- Project-management tools and framework-specific minor modes with their own - Project-management tools and framework-specific minor modes with their own
snippets libraries. snippets libraries.
- Project search (and replace) utilities, powered by - Project search (and replace) utilities, powered by [ripgrep][url:ripgrep].
[the_silver_searcher][url:the_silver_searcher] or [ripgrep][url:ripgrep].
- Isolated and persistent workspaces (also substitutes for vim tabs). - Isolated and persistent workspaces (also substitutes for vim tabs).
- An environment variables file generator and loader, so that Emacs can - An envvar file generator that captures a snapshot of your shell environment
perfectly inherit your shell configuration. for Doom to load at startup. No more struggling to get Emacs to inherit your
- Everything is optional! `PATH`, among other things.
# Getting Help # 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 Encountered strange behavior or an error? Here are some things to try before you
shoot off that bug report: 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. files are up-to-date.
- If you have byte-compiled your config (with `bin/doom compile`), see if - 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 `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:bindings]: modules/config/default/+evil-bindings.el
[doom:packages]: core/autoload/packages.el [doom:packages]: core/autoload/packages.el
[doom:popups]: modules/ui/popup/README.org [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:liberapay]: https://liberapay.com/hlissner/donate
[url:paypal]: https://paypal.me/henriklissner/10 [url:paypal]: https://paypal.me/henriklissner/10
[url:editorconfig]: http://editorconfig.org/ [url:editorconfig]: http://editorconfig.org/
[url:evil-mode]: https://github.com/emacs-evil/evil [url:evil-mode]: https://github.com/emacs-evil/evil
[url:ripgrep]: https://github.com/BurntSushi/ripgrep [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 [url:straight]: https://github.com/raxod502/straight.el

View file

@ -9,10 +9,11 @@
:; exec $EMACS --script "$0" -- "$@" :; exec $EMACS --script "$0" -- "$@"
:; exit 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")) (emacsdir (getenv "EMACSDIR"))
(user-emacs-directory (or emacsdir (expand-file-name "../" loaddir))) (user-emacs-directory
(load-prefer-newer t)) (abbreviate-file-name (or emacsdir (expand-file-name "../" loaddir)))))
(push (expand-file-name "core" user-emacs-directory) load-path) (push (expand-file-name "core" user-emacs-directory) load-path)
(require 'core) (require 'core)
@ -51,9 +52,18 @@ with a different private module."
(setq doom-auto-accept t) (setq doom-auto-accept t)
(print! (info "Auto-yes on"))) (print! (info "Auto-yes on")))
(when help-p (when help-p
(push command args) (when command
(push command args))
(setq command "help")) (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. ;; Reload core in case any of the directories were changed.
(when (or emacsdir doomdir localdir) (when (or emacsdir doomdir localdir)
(load! "core/core.el" user-emacs-directory)) (load! "core/core.el" user-emacs-directory))
@ -69,29 +79,43 @@ with a different private module."
((condition-case e ((condition-case e
(let ((start-time (current-time))) (let ((start-time (current-time)))
(and (doom-cli-execute command args) (and (doom-cli-execute command args)
(terpri)
(print! (success "Finished! (%.4fs)") (print! (success "Finished! (%.4fs)")
(float-time (float-time
(time-subtract (current-time) (time-subtract (current-time)
start-time))))) start-time)))))
(user-error (user-error
(print! (error "%s\n") (error-message-string e)) (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) ((debug error)
(message "--------------------------------------------------\n") (print! (error "There was an unexpected error:"))
(message "There was an unexpected error:") (print-group!
(message " %s (%s)" (get (car e) 'error-message) (car e)) (print! "%s %s" (bold "Type:") (car e))
(dolist (item (cdr e)) (print! (bold "Message:"))
(message " %s" item)) (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 (unless debug-on-error
(message (terpri)
(concat "\nRun the command again with the -d (or --debug) option to enable debug\n" (print!
"mode and, hopefully, generate a stack trace. If you decide to file a bug\n" (concat "Run the command again with the -d (or --debug) switch to enable debug\n"
"report, please include it!\n\n" "mode and (hopefully) generate a backtrace from this error:\n"
"Emacs outputs to standard error, so you'll need to redirect stderr to\n" "\n %s\n\n"
"stdout to pipe this to a file or clipboard!\n\n" "If you file a bug report, please include it!")
" e.g. doom -d install 2>&1 | clipboard-program\n")) (string-join (append (list (file-name-nondirectory load-file-name) "-d" command)
(signal 'doom-error e))))))) args)
" "))
(error ""))))))) ; Ensure non-zero exit code
(doom-cli-execute :main (cdr (member "--" argv))) (doom-cli-execute :main (cdr (member "--" argv)))
(setq argv nil)) (setq argv nil))

View file

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

View file

@ -195,7 +195,9 @@ If DERIVED-P, test with `derived-mode-p', otherwise use `eq'."
;;;###autoload ;;;###autoload
(defun doom-set-buffer-real (buffer flag) (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 (with-current-buffer buffer
(setq doom-real-buffer-p flag))) (setq doom-real-buffer-p flag)))
@ -251,7 +253,9 @@ regex PATTERN. Returns the number of killed buffers."
;;;###autoload ;;;###autoload
(defun doom-mark-buffer-as-real-h () (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)) (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))) (set-buffer-modified-p nil)))
(doom-kill-buffer-fixup-windows buffer)) (doom-kill-buffer-fixup-windows buffer))
(defun doom--message-or-count (interactive message count)
(if interactive
(message message count)
count))
;;;###autoload ;;;###autoload
(defun doom/kill-all-buffers (&optional buffer-list interactive) (defun doom/kill-all-buffers (&optional buffer-list interactive)
"Kill all buffers and closes their windows. "Kill all buffers and closes their windows.
@ -286,14 +296,14 @@ belong to the current project."
(if (null buffer-list) (if (null buffer-list)
(message "No buffers to kill") (message "No buffers to kill")
(save-some-buffers) (save-some-buffers)
(delete-other-windows)
(when (memq (current-buffer) buffer-list) (when (memq (current-buffer) buffer-list)
(switch-to-buffer (doom-fallback-buffer))) (switch-to-buffer (doom-fallback-buffer)))
(mapc #'doom-kill-buffer-and-windows buffer-list) (mapc #'kill-buffer buffer-list)
(delete-other-windows) (doom--message-or-count
(when interactive interactive "Killed %d buffers"
(message "Killed %s buffers" (- (length buffer-list)
(- (length buffer-list) (length (cl-remove-if-not #'buffer-live-p buffer-list))))))
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))))
;;;###autoload ;;;###autoload
(defun doom/kill-other-buffers (&optional buffer-list interactive) (defun doom/kill-other-buffers (&optional buffer-list interactive)
@ -308,10 +318,10 @@ project."
(doom-buffer-list))) (doom-buffer-list)))
t)) t))
(mapc #'doom-kill-buffer-and-windows buffer-list) (mapc #'doom-kill-buffer-and-windows buffer-list)
(when interactive (doom--message-or-count
(message "Killed %s buffers" interactive "Killed %d other buffers"
(- (length buffer-list) (- (length buffer-list)
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))) (length (cl-remove-if-not #'buffer-live-p buffer-list)))))
;;;###autoload ;;;###autoload
(defun doom/kill-matching-buffers (pattern &optional buffer-list interactive) (defun doom/kill-matching-buffers (pattern &optional buffer-list interactive)
@ -340,7 +350,11 @@ current project."
(list (doom-buried-buffers (list (doom-buried-buffers
(if current-prefix-arg (doom-project-buffer-list))) (if current-prefix-arg (doom-project-buffer-list)))
t)) 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 ;;;###autoload
(defun doom/kill-project-buffers (project &optional interactive) (defun doom/kill-project-buffers (project &optional interactive)
@ -358,9 +372,9 @@ current project."
nil) nil)
t)) t))
(when project (when project
(let ((buffers (doom-project-buffer-list project))) (let ((buffer-list (doom-project-buffer-list project)))
(doom-kill-buffers-fixup-windows buffers) (doom-kill-buffers-fixup-windows buffer-list)
(when interactive (doom--message-or-count
(message "Killed %d buffer(s)" interactive "Killed %d project buffers"
(- (length buffers) (- (length buffer-list)
(length (cl-remove-if-not #'buffer-live-p buffers)))))))) (length (cl-remove-if-not #'buffer-live-p buffer-list)))))))

View file

@ -1,86 +1,5 @@
;;; core/autoload/cli.el -*- lexical-binding: t; -*- ;;; 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 ;;; Library
@ -113,7 +32,7 @@ Warning: freezes indefinitely on any stdin prompt."
:connection-type 'pipe)) :connection-type 'pipe))
done-p) done-p)
(set-process-filter (set-process-filter
process (lambda (process output) process (lambda (_process output)
(princ output (current-buffer)) (princ output (current-buffer))
(princ output))) (princ output)))
(set-process-sentinel (set-process-sentinel

View file

@ -1,5 +1,8 @@
;;; core/autoload/config.el -*- lexical-binding: t; -*- ;;; 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 ;;;###autoload
(defvar doom-reload-hook nil (defvar doom-reload-hook nil
"A list of hooks to run when `doom/reload' is called.") "A list of hooks to run when `doom/reload' is called.")
@ -23,8 +26,9 @@
(doom-project-find-file doom-private-dir)) (doom-project-find-file doom-private-dir))
;;;###autoload ;;;###autoload
(defun doom/goto-doomblock () (defun doom/goto-private-init-file ()
"Open your private init.el and go to your `doom!' block." "Open your private init.el file.
And jumps to your `doom!' block."
(interactive) (interactive)
(find-file (expand-file-name "init.el" doom-private-dir)) (find-file (expand-file-name "init.el" doom-private-dir))
(goto-char (goto-char
@ -34,46 +38,58 @@
(point)))) (point))))
;;;###autoload ;;;###autoload
(defun doom/goto-config-file () (defun doom/goto-private-config-file ()
"Open your private config.el file." "Open your private config.el file."
(interactive) (interactive)
(find-file (expand-file-name "config.el" doom-private-dir))) (find-file (expand-file-name "config.el" doom-private-dir)))
;;;###autoload ;;;###autoload
(defun doom/goto-packages-file () (defun doom/goto-private-packages-file ()
"Open your private packages.el file." "Open your private packages.el file."
(interactive) (interactive)
(find-file (expand-file-name "packages.el" doom-private-dir))) (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 ;;;###autoload
(defun doom/reload () (defun doom/reload ()
"Reloads your private config. "Reloads your private config.
This is experimental! It will try to do as `bin/doom refresh' does, but from This is experimental! It will try to do as `bin/doom sync' does, but from within
within this Emacs session. i.e. it reload autoloads files (if necessary), this Emacs session. i.e. it reload autoloads files (if necessary), reloads your
reloads your package list, and lastly, reloads your private config.el. package list, and lastly, reloads your private config.el.
Runs `doom-reload-hook' afterwards." Runs `doom-reload-hook' afterwards."
(interactive) (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) (require 'core-cli)
(let ((doom-reloading-p t)) (when (and IS-WINDOWS (file-exists-p doom-env-file))
(compile (format "%s/bin/doom refresh -f" doom-emacs-dir)) (warn "Can't regenerate envvar file from within Emacs. Run 'doom env' from the console"))
(while compilation-in-progress (doom--compile (format "%s sync -e" doom-bin)
(sit-for 1)) :on-success
(doom-initialize 'force) (let ((doom-reloading-p t))
(with-demoted-errors "PRIVATE CONFIG ERROR: %s" (doom-initialize 'force)
(general-auto-unbind-keys) (with-demoted-errors "PRIVATE CONFIG ERROR: %s"
(unwind-protect (general-auto-unbind-keys)
(doom-initialize-modules 'force) (unwind-protect
(general-auto-unbind-keys t))) (doom-initialize-modules 'force)
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook)) (general-auto-unbind-keys t)))
(message "Finished!")) (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 ;;;###autoload
(defun doom/reload-autoloads () (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 reloads your package and module visibility, but does not install new packages or
remove orphaned ones. It also doesn't reload your private config. 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." line."
(interactive) (interactive)
(require 'core-cli) (require 'core-cli)
(require 'core-packages) (require 'core-packages)
(doom-initialize-packages) (doom-initialize-packages)
(doom-reload-autoloads nil 'force)) (doom-cli-reload-autoloads))
;;;###autoload ;;;###autoload
(defun doom/reload-env () (defun doom/reload-env (&optional arg)
"Regenerates and reloads your shell environment. "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) (interactive)
(compile (format "%s env" (expand-file-name "bin/doom" doom-emacs-dir))) (doom--compile (format "%s upgrade" doom-bin)
(while compilation-in-progress :on-success
(sit-for 1)) (when (y-or-n-p "You must restart Emacs for the upgrade to take effect.\n\nRestart Emacs?")
(unless (file-readable-p doom-env-file) (doom/restart-and-restore))))
(error "Failed to generate env file"))
(doom-load-envvars-file doom-env-file))

View file

@ -23,11 +23,25 @@
(when (file-exists-p file) (when (file-exists-p file)
(insert-file-contents 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 ;;;###autoload
(defun doom-info () (defun doom-info ()
"Returns diagnostic information about the current Emacs session in markdown, "Returns diagnostic information about the current Emacs session in markdown,
ready to be pasted in a bug report on github." ready to be pasted in a bug report on github."
(require 'vc-git) (require 'vc-git)
(require 'core-packages)
(let ((default-directory doom-emacs-dir) (let ((default-directory doom-emacs-dir)
(doom-modules (doom-modules))) (doom-modules (doom-modules)))
(cl-letf (cl-letf
@ -46,7 +60,8 @@ ready to be pasted in a bug report on github."
'server-running)))) 'server-running))))
(doom (doom
(version . ,doom-version) (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 (system
(type . ,system-type) (type . ,system-type)
(config . ,system-configuration) (config . ,system-configuration)
@ -78,24 +93,29 @@ ready to be pasted in a bug report on github."
(cdr key)))) (cdr key))))
'("n/a"))) '("n/a")))
(packages (packages
,@(or (ignore-errors ,@(or (condition-case e
(let ((doom-interactive-mode t) (mapcar
doom-packages #'cdr (doom--collect-forms-in
doom-disabled-packages) (doom-path doom-private-dir "packages.el")
(doom--read-module-packages-file "package!"))
(doom-path doom-private-dir "packages.el") (error (format "<%S>" e)))
nil t) '("n/a")))
(cl-loop for (name . plist) in (nreverse doom-packages) (unpin
collect ,@(or (condition-case e
(if-let (splist (doom-plist-delete (copy-sequence plist) (mapcan #'identity
:modules)) (mapcar
(prin1-to-string (cons name splist)) #'cdr (doom--collect-forms-in
name)))) (doom-path doom-private-dir "packages.el")
"unpin!")))
(error (format "<%S>" e)))
'("n/a"))) '("n/a")))
(elpa (elpa
,@(or (ignore-errors ,@(or (condition-case e
(cl-loop for (name . _) in package-alist (progn
collect (format "%s" name))) (package-initialize)
(cl-loop for (name . _) in package-alist
collect (format "%s" name)))
(error (format "<%S>" e)))
'("n/a")))))))) '("n/a"))))))))
@ -197,7 +217,7 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
(prin1-to-string (prin1-to-string
(macroexp-progn (macroexp-progn
(append `((setq noninteractive nil (append `((setq noninteractive nil
doom-debug-mode t init-file-debug t
load-path ',load-path load-path ',load-path
package--init-file-ensured t package--init-file-ensured t
package-user-dir ,package-user-dir 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)))) (setq-default buffer-undo-tree (make-undo-tree))))
(pcase mode (pcase mode
(`vanilla-doom+ ; Doom core + modules - private config (`vanilla-doom+ ; Doom core + modules - private config
`((setq doom-init-modules-p t) `((load-file ,(expand-file-name "core.el" doom-core-dir))
(load-file ,user-init-file) (doom-initialize)
(doom-initialize-core)
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
(setq doom-modules ',doom-modules) (setq doom-modules ',doom-modules)
(maphash (lambda (key plist) (maphash (lambda (key plist)
(let ((doom--current-module key) (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) (run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
(doom-run-all-startup-hooks-h))) (doom-run-all-startup-hooks-h)))
(`vanilla-doom ; only Doom core (`vanilla-doom ; only Doom core
`((setq doom-init-modules-p t) `((load-file ,(expand-file-name "core.el" doom-core-dir))
(load-file ,user-init-file) (doom-initialize)
(doom-initialize-core)
(doom-run-all-startup-hooks-h))) (doom-run-all-startup-hooks-h)))
(`vanilla ; nothing loaded (`vanilla ; nothing loaded
`((package-initialize))))))) `((package-initialize)))))))
@ -335,6 +358,10 @@ will be automatically appended to the result."
((> (prefix-numeric-value arg) 0))))) ((> (prefix-numeric-value arg) 0)))))
(setq doom-debug-mode value (setq doom-debug-mode value
debug-on-error value debug-on-error value
garbage-collection-messages value
use-package-verbose value
jka-compr-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")))) (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. 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." MATCH is a string regexp. Only entries that match it will be included."
(let (file-name-handler-alist (let (result file-name-handler-alist)
result)
(dolist (file (mapcan (doom-rpartial #'doom-glob "*") (doom-enlist paths))) (dolist (file (mapcan (doom-rpartial #'doom-glob "*") (doom-enlist paths)))
(cond ((file-directory-p file) (cond ((file-directory-p file)
(nconcq! result (appendq!
(and (memq type '(t dirs)) result
(string-match-p match file) (and (memq type '(t dirs))
(not (and filter (funcall filter file))) (string-match-p match file)
(not (and (file-symlink-p file) (not (and filter (funcall filter file)))
(not follow-symlinks))) (not (and (file-symlink-p file)
(<= mindepth 0) (not follow-symlinks)))
(list (cond (map (funcall map file)) (<= mindepth 0)
(relative-to (file-relative-name file relative-to)) (list (cond (map (funcall map file))
(file)))) (relative-to (file-relative-name file relative-to))
(and (>= depth 1) (file))))
(apply #'doom-files-in file (and (>= depth 1)
(append (list :mindepth (1- mindepth) (apply #'doom-files-in file
:depth (1- depth) (append (list :mindepth (1- mindepth)
:relative-to relative-to) :depth (1- depth)
rest))))) :relative-to relative-to)
rest)))))
((and (memq type '(t files)) ((and (memq type '(t files))
(string-match-p match file) (string-match-p match file)
(not (and filter (funcall filter file))) (not (and filter (funcall filter file)))
@ -178,6 +178,7 @@ single file or nested compound statement of `and' and `or' statements."
file)) file))
(nth 7 (file-attributes file)))) (nth 7 (file-attributes file))))
(defvar w32-get-true-file-attributes)
;;;###autoload ;;;###autoload
(defun doom-directory-size (dir) (defun doom-directory-size (dir)
"Returns the size of FILE (in DIR) in kilobytes." "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 ;;; Helpers
(defun doom--forget-file (old-path &optional new-path) (defun doom--forget-file (path)
"Ensure `recentf', `projectile' and `save-place' forget OLD-PATH." "Ensure `recentf', `projectile' and `save-place' forget OLD-PATH."
(when (bound-and-true-p recentf-mode) (when (bound-and-true-p recentf-mode)
(when new-path (recentf-remove-if-non-kept path))
(recentf-add-file new-path))
(recentf-remove-if-non-kept old-path))
(when (and (bound-and-true-p projectile-mode) (when (and (bound-and-true-p projectile-mode)
(doom-project-p) (doom-project-p)
(projectile-file-cached-p old-path (doom-project-root))) (projectile-file-cached-p path (doom-project-root)))
(projectile-purge-file-from-cache old-path)) (projectile-purge-file-from-cache path))
(when (bound-and-true-p save-place-mode) (when (bound-and-true-p save-place-mode)
(save-place-forget-unreadable-files))) (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-file-clearprops path)
(vc-resynch-buffer path nil t)) (vc-resynch-buffer path nil t))
(when (featurep 'magit) (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) (defun doom--copy-file (old-path new-path &optional force-p)
(let* ((new-path (expand-file-name new-path)) (let* ((new-path (expand-file-name new-path))
@ -306,11 +306,18 @@ file if it exists, without confirmation."
(let ((old-path (buffer-file-name)) (let ((old-path (buffer-file-name))
(new-path (expand-file-name new-path))) (new-path (expand-file-name new-path)))
(when-let (dest (doom--copy-file old-path new-path force-p)) (when-let (dest (doom--copy-file old-path new-path force-p))
(doom--forget-file old-path)
(when (file-exists-p old-path) (when (file-exists-p old-path)
(delete-file 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) (kill-current-buffer)
(doom--forget-file old-path new-path)
(doom--update-file new-path)
(find-file new-path) (find-file new-path)
(message "File successfully moved to %s" dest)))) (message "File successfully moved to %s" dest))))
(`overwrite-self (error "Cannot overwrite self")) (`overwrite-self (error "Cannot overwrite self"))
@ -339,4 +346,21 @@ file if it exists, without confirmation."
(defun doom/sudo-this-file () (defun doom/sudo-this-file ()
"Open the current file as root." "Open the current file as root."
(interactive) (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 "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.") `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 ;;; Library
(defun doom--font-name (fontname frame) (defun doom--font-name (fontname)
(when (query-fontset 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)))) (setq fontname (nth 2 ascii))))
(or (x-decompose-font-name fontname) (or (x-decompose-font-name fontname)
(error "Cannot decompose font name"))) (error "Cannot decompose font name")))
(defun doom--frame-list (&optional frame) (defvar doom--font-scale nil)
"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))))
;;;###autoload ;;;###autoload
(defun doom-adjust-font-size (increment &optional frame) (defun doom-adjust-font-size (increment)
"Increase size of font in FRAME by INCREMENT. "Increase size of font in FRAME by INCREMENT.
FRAME parameter defaults to current frame." FRAME parameter defaults to current frame."
(let* ((frame (or frame (selected-frame))) (if (null increment)
(font (frame-parameter frame 'font)) (progn
(font (doom--font-name font frame))) (set-frame-font doom-font 'keep-size t)
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum)) (setf (alist-get 'font default-frame-alist)
increment))) (cond ((stringp doom-font) doom-font)
(unless (> new-size 0) ((fontp doom-font) (font-xlfd-name doom-font))
(error "Font is too small at %d" new-size)) ((signal 'wrong-type-argument (list '(fontp stringp)
(aset font xlfd-regexp-pixelsize-subnum (number-to-string new-size))) doom-font)))))
;; Set point size & width to "*", so frame width will adjust to new font size t)
(aset font xlfd-regexp-pointsize-subnum "*") (let* ((font (frame-parameter nil 'font))
(aset font xlfd-regexp-avgwidth-subnum "*") (font (doom--font-name font))
(setq font (x-compose-font-name font)) (increment (* increment doom-font-increment))
(unless (x-list-fonts font) (zoom-factor (or doom--font-scale 0)))
(error "Cannot change font size")) (let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
(set-frame-parameter frame 'font font))) 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 ;;;###autoload
(defun doom/increase-font-size (count) (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") (interactive "p")
(let ((zoom-factor (or (frame-parameter nil 'font-scale) 0)) (doom-adjust-font-size count))
(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)))
;;;###autoload ;;;###autoload
(defun doom/decrease-font-size (count) (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") (interactive "p")
(doom/increase-font-size (- count))) (doom-adjust-font-size (- count)))
;;;###autoload ;;;###autoload
(defun doom/reset-font-size () (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-mode-amount 0))
(text-scale-set 0) (text-scale-set 0)
(setq success t)) (setq success t))
(when-let (factor (frame-parameter nil 'font-scale)) (when (doom-adjust-font-size nil)
(set-frame-font doom-font t)
(set-frame-parameter nil 'font-scale nil)
(setq success t)) (setq success t))
(unless success (unless success
(user-error "The font hasn't been resized")) (user-error "The font hasn't been resized"))))
(run-hooks 'doom-change-font-size-hook)))
;;;###autoload ;;;###autoload
(define-minor-mode doom-big-font-mode (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 :global t
(unless doom-font (unless doom-font
(user-error "`doom-font' must be set to a valid font")) (user-error "`doom-font' must be set to a valid font"))
(let ((frame (selected-frame))) (if doom-big-font
(if doom-big-font (let ((font (if doom-big-font-mode doom-big-font doom-font)))
(progn (set-frame-font font 'keep-size t)
(set-frame-font (if doom-big-font-mode doom-big-font doom-font) (setf (alist-get 'font default-frame-alist)
t (doom--frame-list frame)) (cond ((stringp doom-font) font)
(run-hooks 'doom-change-font-size-hook)) ((fontp font) (font-xlfd-name font))
(set-frame-font doom-font t (doom--frame-list frame)) ((signal 'wrong-type-argument (list '(fontp stringp)
(when doom-big-font-mode font))))))
(doom-adjust-font-size doom-big-font-increment frame))))) (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 ;;;###autoload
(defun doom--format-print (output) (defun doom--format-print (output)
(unless (string-empty-p output) (unless (string-empty-p output)
(if (not noninteractive) (princ output)
(message "%s" output) (when (or noninteractive (not (eq standard-output t)))
(princ output)
(terpri)) ; newline (terpri)) ; newline
t)) t))
@ -213,8 +212,9 @@ into faces or ANSI codes depending on the type of sesssion we're in."
;;;###autoload ;;;###autoload
(defmacro print! (message &rest args) (defmacro print! (message &rest args)
"Uses `message' in interactive sessions and `princ' otherwise (prints to "Prints MESSAGE, formatted with ARGS, to stdout.
standard out).
Returns non-nil if the message is a non-empty string.
Can be colored using (color ...) blocks: Can be colored using (color ...) blocks:

View file

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

View file

@ -13,6 +13,13 @@
nil-value) nil-value)
plist))) 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 ;;;###autoload
(defun doom-package-recipe (package &optional prop nil-value) (defun doom-package-recipe (package &optional prop nil-value)
"Returns the `straight' recipe PACKAGE was registered with." "Returns the `straight' recipe PACKAGE was registered with."
@ -23,6 +30,14 @@
nil-value) nil-value)
plist))) 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 ;;;###autoload
(defun doom-package-build-recipe (package &optional prop nil-value) (defun doom-package-build-recipe (package &optional prop nil-value)
"Returns the `straight' recipe PACKAGE was installed with." "Returns the `straight' recipe PACKAGE was installed with."
@ -39,7 +54,7 @@
(car (gethash (symbol-name package) straight--build-cache))) (car (gethash (symbol-name package) straight--build-cache)))
;;;###autoload ;;;###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." "Return a list of dependencies for a package."
(let ((deps (nth 1 (gethash (symbol-name package) straight--build-cache)))) (let ((deps (nth 1 (gethash (symbol-name package) straight--build-cache))))
(if recursive (if recursive
@ -47,6 +62,7 @@
deps)) deps))
deps))) deps)))
;;;###autoload
(defun doom-package-depending-on (package &optional noerror) (defun doom-package-depending-on (package &optional noerror)
"Return a list of packages that depend on the package named NAME." "Return a list of packages that depend on the package named NAME."
(cl-check-type name symbol) (cl-check-type name symbol)
@ -155,6 +171,7 @@ was installed with."
((debug error) ((debug error)
(signal 'doom-package-error (signal 'doom-package-error
(list (doom-module-from-path file) (list (doom-module-from-path file)
file
e)))))) e))))))
;;;###autoload ;;;###autoload
@ -167,8 +184,7 @@ If ALL-P, gather packages unconditionally across all modules, including disabled
ones." ones."
(let ((doom-interactive-mode t) (let ((doom-interactive-mode t)
(doom-modules (doom-modules)) (doom-modules (doom-modules))
doom-packages doom-packages)
doom-disabled-packages)
(doom--read-module-packages-file (doom--read-module-packages-file
(doom-path doom-core-dir "packages.el") all-p t) (doom-path doom-core-dir "packages.el") all-p t)
(let ((private-packages (doom-path doom-private-dir "packages.el"))) (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)) (doom--read-module-packages-file private-packages all-p t))
(nreverse doom-packages))) (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 ;;; Main functions
@ -201,3 +278,48 @@ ones."
(message "Reloading packages") (message "Reloading packages")
(doom-initialize-packages t) (doom-initialize-packages t)
(message "Reloading packages...DONE")) (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 ;;;###autoload
(defun doom-plist-merge (from-plist to-plist) (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))) (let ((plist (copy-sequence from-plist)))
(while plist (while plist
(plist-put! to-plist (pop plist) (pop plist))) (plist-put! to-plist (pop plist) (pop plist)))
@ -83,11 +83,11 @@ BODY."
p)) p))
;;;###autoload ;;;###autoload
(defun doom-plist-delete (plist prop) (defun doom-plist-delete (plist &rest props)
"Delete PROP from a copy of PLIST." "Delete PROPS from a copy of PLIST."
(let (p) (let (p)
(while plist (while plist
(if (not (eq prop (car plist))) (if (not (memq (car plist) props))
(plist-put! p (car plist) (nth 1 plist))) (plist-put! p (car plist) (nth 1 plist)))
(setq plist (cddr plist))) (setq plist (cddr plist)))
p)) p))

View file

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

View file

@ -96,9 +96,10 @@ following:
;; ;;
;;; Commands ;;; Commands
(defvar projectile-enable-caching)
;;;###autoload ;;;###autoload
(defun doom/open-scratch-buffer (&optional arg project-p) (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 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 If PROJECT-P is non-nil, open a persistent scratch buffer associated with the

View file

@ -47,10 +47,16 @@
"TODO" "TODO"
(setq file (expand-file-name (or file (doom-session-file)))) (setq file (expand-file-name (or file (doom-session-file))))
(message "Attempting to load %s" 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 (unless persp-mode
(persp-mode +1)) (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) ((and (require 'frameset nil t)
(require 'restart-emacs nil t)) (require 'restart-emacs nil t))
(restart-emacs--restore-frames-using-desktop file)) (restart-emacs--restore-frames-using-desktop file))
@ -125,4 +131,7 @@
(setq doom-autosave-session nil) (setq doom-autosave-session nil)
(doom/quicksave-session) (doom/quicksave-session)
(restart-emacs (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; -*- ;;; 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 ;;;###autoload
(defun doom-surrounded-p (pair &optional inline balanced) (defun doom-surrounded-p (pair &optional inline balanced)
"Returns t if point is surrounded by a brace delimiter: {[( "Returns t if point is surrounded by a brace delimiter: {[(
@ -28,31 +40,18 @@ lines, above and below, with only whitespace in between."
;;;###autoload ;;;###autoload
(defun doom-point-in-comment-p (&optional pos) (defun doom-point-in-comment-p (&optional pos)
"Return non-nil if POS is in a comment. "Return non-nil if POS is in a comment.
POS defaults to the current position." POS defaults to the current position."
;; REVIEW Should we cache `syntax-ppss'? (let ((pos (or pos (point))))
(let* ((pos (or pos (point))) (or (run-hook-with-args-until-success 'doom-point-in-comment-functions pos)
(ppss (syntax-ppss pos))) (sp-point-in-comment 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)))))))))
;;;###autoload ;;;###autoload
(defun doom-point-in-string-p (&optional pos) (defun doom-point-in-string-p (&optional pos)
"Return non-nil if POS is in a string." "Return non-nil if POS is in a string."
;; REVIEW Should we cache `syntax-ppss'? ;; 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 ;;;###autoload
(defun doom-point-in-string-or-comment-p (&optional pos) (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) (or (doom-point-in-string-p pos)
(doom-point-in-comment-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 ;;; 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 ;;;###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 "Jump between the indentation column (first non-whitespace character) and the
beginning of the line. The opposite of beginning of the line. The opposite of
`doom/forward-to-last-non-comment-or-eol'." `doom/forward-to-last-non-comment-or-eol'."
(interactive) (interactive "d")
(let ((pt (point))) (let ((pt (or point (point))))
(cl-destructuring-bind (bol . bot) (cl-destructuring-bind (bol bot _eot _eol)
(save-excursion (doom--bol-bot-eot-eol pt)
(beginning-of-visual-line)
(cons (point)
(progn (skip-chars-forward " \t\r")
(point))))
(cond ((> pt bot) (cond ((> pt bot)
(goto-char bot)) (goto-char bot))
((= pt bol) ((= pt bol)
(goto-char (min doom--last-backward-pt bot)) (or (and doom--last-backward-pt
(setq doom--last-backward-pt most-positive-fixnum)) (= (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) ((<= pt bot)
(setq doom--last-backward-pt pt) (setq doom--last-backward-pt pt)
(goto-char bol)))))) (goto-char bol))))))
(defvar doom--last-forward-pt -1) (defvar doom--last-forward-pt nil)
;;;###autoload ;;;###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 "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'." 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) (interactive)
(let ((eol (if (not visual-line-mode) (let ((empty-line-p (save-excursion (beginning-of-line)
(line-end-position) (looking-at-p "[ \t]*$"))))
(save-excursion (end-of-visual-line) (point))))) (funcall (if (fboundp 'evil-delete)
(if (or (and (< (point) eol) #'evil-delete
(sp-point-in-comment)) #'delete-region)
(not (sp-point-in-comment eol))) (point-at-bol) (point))
(if (= (point) eol) (unless empty-line-p
(progn (indent-according-to-mode))))
(goto-char doom--last-forward-pt)
(setq doom--last-forward-pt -1)) ;;;###autoload
(setq doom--last-forward-pt (point)) (defun doom/delete-backward-word (arg)
(goto-char eol)) "Like `backward-kill-word', but doesn't affect the kill-ring."
(let* ((bol (save-excursion (beginning-of-visual-line) (point))) (interactive "p")
(boc (or (save-excursion (let (kill-ring)
(if (not comment-use-syntax) (backward-kill-word arg)))
(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))))))
;;;###autoload ;;;###autoload
(defun doom/dumb-indent () (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
(- tab-width movement))))))))) (- 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 ;;;###autoload
(defun doom/retab (arg &optional beg end) (defun doom/retab (arg &optional beg end)
"Converts tabs-to-spaces or spaces-to-tabs within BEG and END (defaults to "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-"))) `(let ((fn (gensym "doom--customize-themes-h-")))
(fset (fset
fn (lambda () fn (lambda ()
(dolist (theme (doom-enlist (or ,theme 'user))) (let (custom--inhibit-theme-enable)
(when (or (eq theme 'user) (dolist (theme (doom-enlist (or ,theme 'user)))
(custom-theme-enabled-p theme)) (when (or (eq theme 'user)
(apply #'custom-theme-set-faces 'user (custom-theme-enabled-p theme))
(mapcan #'doom--custom-theme-set-face (apply #'custom-theme-set-faces theme
(list ,@specs))))))) (mapcan #'doom--custom-theme-set-face
(list ,@specs))))))))
(when (or doom-init-theme-p (null doom-theme)) (when (or doom-init-theme-p (null doom-theme))
(funcall fn)) (funcall fn))
(add-hook 'doom-load-theme-hook fn 'append))) (add-hook 'doom-load-theme-hook fn 'append)))

View file

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

View file

@ -1,418 +1,244 @@
;;; core/cli/autoloads.el -*- lexical-binding: t; -*- ;;; core/cli/autoloads.el -*- lexical-binding: t; -*-
(defvar doom-autoload-excluded-packages '("gh") (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 everyone in the universe and their dog, causing errors that make babies cry. No
one wants that.") 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 ;; externs
(defvar autoload-timestamps) (defvar autoload-timestamps)
(defvar generated-autoload-load-name) (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))
;; (defun doom-cli-reload-core-autoloads (&optional file)
;;; Commands (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) () (defun doom-cli-reload-package-autoloads (&optional file)
"Regenerates Doom's autoloads files. (print! (start "(Re)generating package autoloads..."))
(print-group!
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el, (doom-initialize-packages)
modules/*/*/autoload.el and modules/*/*/autoload/*.el, and generates and (let ((file (or file doom-package-autoload-file)))
byte-compiles `doom-autoload-file', as well as `doom-package-autoload-file' (cl-check-type file string)
(created from the concatenated autoloads files of all installed packages). (and (print! (start "Generating package autoloads..."))
(doom-cli--write-autoloads
It also caches `load-path', `Info-directory-list', `doom-disabled-packages', file
`package-activated-list' and `auto-mode-alist'." (doom-cli--generate-var-cache doom-autoload-cached-vars)
(straight-check-all) (doom-cli--generate-autoloads
(doom-cli-reload-autoloads nil 'force)) (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 ;;; Helpers
(defun doom--cli-delete-autoloads-file (file) (defun doom-cli--write-autoloads (file &rest forms)
"Delete FILE (an autoloads file) and accompanying *.elc file, if any." (make-directory (file-name-directory file) 'parents)
(cl-check-type file string) (condition-case-unless-debug e
(when (file-exists-p file) (with-temp-file file
(when-let (buf (find-buffer-visiting file)) (let ((standard-output (current-buffer))
(with-current-buffer buf (print-quoted t)
(set-buffer-modified-p nil)) (print-level nil)
(kill-buffer buf)) (print-length nil))
(delete-file file) (insert ";; -*- lexical-binding: t; -*-\n"
(ignore-errors (delete-file (byte-compile-dest-file file))) ";; This file is autogenerated by Doom, DO NOT EDIT IT!!\n")
t)) (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 () (defun doom-cli--byte-compile-file (file)
(message "Restart or reload Doom Emacs for changes to take effect:\n") (condition-case-unless-debug e
(message " M-x doom/restart-and-restore") (let ((byte-compile-warnings (if doom-debug-mode byte-compile-warnings))
(message " M-x doom/restart") (byte-compile-dynamic t)
(message " M-x doom/reload")) (byte-compile-dynamic-docstrings t))
(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
(when (byte-compile-file file) (when (byte-compile-file file)
(prog1 (load file 'noerror 'nomessage 'nosuffix) (unless doom-interactive-mode
(when noninteractive (add-hook 'doom-cli-post-success-execute-hook #'doom-cli--warn-refresh-session-h))
(add-hook 'doom-cli-post-success-execute-hook #'doom--cli-warn-refresh-session-h)))) (load (byte-compile-dest-file file) nil t)))
((debug error) (error
(let ((backup-file (concat file ".bk"))) (delete-file (byte-compile-dest-file file))
(print! (warn "Copied backup to %s") (relpath backup-file)) (signal 'doom-autoload-error (list file e)))))
(copy-file file backup-file 'overwrite))
(doom--cli-delete-autoloads-file file)
(signal 'doom-autoload-error (list file e))))))
(defun doom-cli-reload-autoloads (&optional file force-p) (defun doom-cli--warn-refresh-session-h ()
"Reloads FILE (an autoload file), if it needs reloading. (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 (defun doom-cli--generate-var-cache (vars)
it is nil, it will try to reload both. If FORCE-P (universal argument) do it `((setq ,@(cl-loop for var in vars
even if it doesn't need reloading!" append `(,var ',(symbol-value var))))))
(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--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))))
;; (defun doom-cli--generate-autoloads-autodefs (file buffer module &optional module-enabled-p)
;;; Doom autoloads (with-temp-buffer
(insert-file-contents file)
(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)
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t) (while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
(let* ((sexp (sexp-at-point)) (let* ((standard-output buffer)
(alt-sexp (match-string 1)) (form (read (current-buffer)))
(type (car sexp)) (altform (match-string 1))
(name (doom-unquote (cadr sexp))) (definer (car-safe form))
(origin (doom-module-from-path path))) (symbol (doom-unquote (cadr form))))
(cond (cond ((and (not module-enabled-p) altform)
((and (not member-p) (print (read altform)))
alt-sexp) ((memq definer '(defun defmacro cl-defun cl-defmacro))
(push (read alt-sexp) forms)) (if module-enabled-p
(print (make-autoload form file))
((memq type '(defun defmacro cl-defun cl-defmacro)) (cl-destructuring-bind (_ _ arglist &rest body) form
(cl-destructuring-bind (_ _name arglist &rest body) sexp (print
(appendq! (if altform
forms (read altform)
(list (if member-p (append
(make-autoload sexp path) (list (pcase definer
(let ((docstring (`defun 'defmacro)
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s" (`cl-defun `cl-defmacro)
origin (_ type))
(if (stringp (car body)) symbol arglist
(pop body) (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
"No documentation.")))) module
(condition-case-unless-debug e (if (stringp (car body))
(if alt-sexp (pop body)
(read alt-sexp) "No documentation.")))
(append (cl-loop for arg in arglist
(list (pcase type if (and (symbolp arg)
(`defun 'defmacro) (not (keywordp arg))
(`cl-defun `cl-defmacro) (not (memq arg cl--lambda-list-keywords)))
(_ type)) collect arg into syms
name arglist docstring) else if (listp arg)
(cl-loop for arg in arglist collect (car arg) into syms
if (and (symbolp arg) finally return (if syms `((ignore ,@syms)))))))))
(not (keywordp arg)) (print `(put ',symbol 'doom-module ',module)))
(not (memq arg cl--lambda-list-keywords))) ((eq definer 'defalias)
collect arg into syms (cl-destructuring-bind (_ _ target &optional docstring) form
else if (listp arg) (unless module-enabled-p
collect (car arg) into syms (setq target #'ignore
finally return (if syms `((ignore ,@syms)))))) docstring
('error (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
(print! "- Ignoring autodef %s (%s)" name e) module docstring)))
nil)))) (print `(put ',symbol 'doom-module ',module))
`(put ',name 'doom-module ',origin))))) (print `(defalias ',symbol #',(doom-unquote target) ,docstring))))
(module-enabled-p (print form)))))))
((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))
(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'. ;; The following bindings are in `package-generate-autoloads'.
;; Presumably for a good reason, so I just copied them ;; Presumably for a good reason, so I just copied them
(noninteractive t)
(backup-inhibited t) (backup-inhibited t)
(version-control 'never) (version-control 'never)
(case-fold-search nil) ; reduce magic case-fold-search ; reduce magic
(autoload-timestamps nil) 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 (defun doom-cli--generate-autoloads (files &optional scan)
;; 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."
(require 'autoload) (require 'autoload)
(print! (start "Checking package autoloads file")) (let (autoloads)
(print-group! (dolist (file
(if (and (not force-p) (cl-remove-if-not #'file-readable-p files)
(file-exists-p doom-package-autoload-file) (nreverse (delq nil autoloads)))
(not (file-newer-than-file-p package-user-dir doom-package-autoload-file)) (with-temp-buffer
(not (cl-loop for dir in (straight--directory-files (straight--build-dir)) (print! (debug "- Scanning %s") (relpath file doom-emacs-dir))
if (cl-find-if (if scan
(lambda (dir) (doom-cli--generate-autoloads-buffer file)
(file-newer-than-file-p dir doom-package-autoload-file)) (insert-file-contents file))
(doom-glob (straight--build-dir dir) "*.el")) (save-excursion
return t)) (let ((filestr (prin1-to-string file)))
(not (cl-loop with doom-modules = (doom-modules) (while (re-search-forward "\\_<load-file-name\\_>" nil t)
for key being the hash-keys of doom-modules ;; `load-file-name' is meaningless in a concatenated
for path = (doom-module-path (car key) (cdr key) "packages.el") ;; mega-autoloads file, so we replace references to it with the
if (file-newer-than-file-p path doom-package-autoload-file) ;; file they came from.
return t))) (let ((ppss (save-excursion (syntax-ppss))))
(ignore (or (nth 3 ppss)
(print! (success "Skipping package autoloads, they are up-to-date")) (nth 4 ppss)
(doom-load-autoloads-file doom-package-autoload-file)) (replace-match filestr t t))))))
(let (;; The following bindings are in `package-generate-autoloads'. (let ((load-file-name file)
;; Presumably for a good reason, so I just copied them (load-path
(noninteractive t) (append (list doom-private-dir)
(backup-inhibited t) doom-modules-dirs
(version-control 'never) load-path)))
(case-fold-search nil) ; reduce magic (condition-case _
(autoload-timestamps nil)) (while t
(push (doom-cli--filter-form (read (current-buffer))
(if (doom--cli-delete-autoloads-file doom-package-autoload-file) scan)
(print! (success "Deleted old %s") (filename doom-package-autoload-file)) autoloads))
(make-directory (file-name-directory doom-autoload-file) t)) (end-of-file)))))))
(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))

View file

@ -27,6 +27,7 @@ and your private config files, respectively. To recompile your packages, use
(let ((filename (file-name-nondirectory path))) (let ((filename (file-name-nondirectory path)))
(or (string-prefix-p "." filename) (or (string-prefix-p "." filename)
(string-prefix-p "test-" filename) (string-prefix-p "test-" filename)
(string-suffix-p ".example.el" filename)
(not (equal (file-name-extension path) "el")) (not (equal (file-name-extension path) "el"))
(member filename (list "packages.el" "doctor.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 ;; 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. ;; fully loaded. Which usually aren't so in an noninteractive session.
(let ((doom-interactive-mode 'byte-compile)) (let ((doom-interactive-mode 'byte-compile))
(doom-initialize 'force) (doom-initialize)
(doom-initialize-packages)
(doom-initialize-core)) (doom-initialize-core))
;; ;;
@ -122,9 +124,9 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
(cl-return nil)) (cl-return nil))
(print! (print!
(info (if recompile-p (start (if recompile-p
"Recompiling stale elc files..." "Recompiling stale elc files..."
"Byte-compiling your config (may take a while)..."))) "Byte-compiling your config (may take a while)...")))
(print-group! (print-group!
(require 'use-package) (require 'use-package)
(condition-case e (condition-case e
@ -199,4 +201,5 @@ module. This does not include your byte-compiled, third party packages.'"
finally do finally do
(print! (if success (print! (if success
(success "All elc files deleted") (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/")) (`darwin "~/Library/Fonts/"))
(require 'all-the-icons nil t)) (require 'all-the-icons nil t))
(with-temp-buffer (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) (dolist (font all-the-icons-font-names)
(if (save-excursion (re-search-backward font nil t)) (if (save-excursion (re-search-backward font nil t))
(success! "Found font %s" font) (success! "Found font %s" font)

View file

@ -3,9 +3,9 @@
(defcli! env (defcli! env
((clear-p ["-c" "--clear"] "Clear and delete your envvar file") ((clear-p ["-c" "--clear"] "Clear and delete your envvar file")
(outputfile ["-o" PATH] (outputfile ["-o" PATH]
"Generate the envvar file at PATH. Note that envvar files that aren't in "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 `doom-env-file' won't be loaded automatically at startup. You will need to load
load them manually from your private config with the `doom-load-envvars-file' them manually from your private config with the `doom-load-envvars-file'
function.")) function."))
"Creates or regenerates your envvars file. "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 will be launched from the correct environment (e.g. on MacOS or through certain
app launchers on Linux). app launchers on Linux).
This file is automatically regenerated when you run this command or 'doom This file is automatically regenerated when you run this command or 'doom sync'.
refresh'. However, 'doom refresh' will only regenerate this file if it exists. However, 'doom sync' will only regenerate this file if it exists.
Why this over exec-path-from-shell? 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/) I'd rather it inherit your shell environment /correctly/ (and /completely/)
or not at all. It frontloads the debugging process rather than hiding it 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)))) (let ((env-file (expand-file-name (or outputfile doom-env-file))))
(cond (clear-p (cond (clear-p
(unless (file-exists-p env-file) (unless (file-exists-p env-file)
@ -57,18 +57,20 @@ Why this over exec-path-from-shell?
;; Helpers ;; Helpers
(defvar doom-env-ignored-vars (defvar doom-env-ignored-vars
'("^PWD$" '("^DBUS_SESSION_BUS_ADDRESS$"
"^PS1$"
"^R?PROMPT$"
"^DBUS_SESSION_BUS_ADDRESS$"
"^GPG_AGENT_INFO$" "^GPG_AGENT_INFO$"
"^GPG_TTY$"
"^HOME$"
"^PS1$"
"^PWD$"
"^R?PROMPT$"
"^SSH_AGENT_PID$" "^SSH_AGENT_PID$"
"^SSH_AUTH_SOCK$" "^SSH_AUTH_SOCK$"
;; Doom envvars
"^INSECURE$"
"^DEBUG$"
"^YES$"
"^TERM$" "^TERM$"
;; Doom envvars
"^DEBUG$"
"^INSECURE$"
"^YES$"
"^__") "^__")
"Environment variables to not save in `doom-env-file'. "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)) (goto-char (point-min))
(insert (insert
(concat (concat
"# -*- mode: dotenv -*-\n" "# -*- mode: sh -*-\n"
(format "# Generated from a %s shell environent\n" shell-file-name) (format "# Generated from a %s shell environent\n" shell-file-name)
"# ---------------------------------------------------------------------------\n" "# ---------------------------------------------------------------------------\n"
"# This file was auto-generated by `doom env'. It contains a list of environment\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" "#\n"
(if (file-equal-p env-file doom-env-file) (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" (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" "# doom env -o ~/.doom.d/myenv\n#\n"
"# And load it with (doom-load-envvars-file \"~/.doom.d/myenv\").\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" (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 ;; user's interactive shell, therefore we just dump
;; `process-environment' to a file. ;; `process-environment' to a file.
(dolist (env process-environment) (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) doom-env-ignored-vars)
(print! (info "Ignoring %s") env) (print! (info "Ignoring %s") env)
(insert env "\n"))) (insert env "\n")))

View file

@ -27,7 +27,9 @@
until (memq arg cl--lambda-list-keywords) until (memq arg cl--lambda-list-keywords)
collect (format "[%s]" (upcase (symbol-name arg))))) 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) (defun doom--cli-print-desc (cli &optional short)
(print! "%s" (print! "%s"
@ -43,7 +45,6 @@
(print! (bold "Options:")) (print! (bold "Options:"))
(print-group! (print-group!
(cl-loop for opt in optlist (cl-loop for opt in optlist
for flags = (doom-cli-option-flags opt)
for desc = (doom-cli-option-desc opt) for desc = (doom-cli-option-desc opt)
for args = (doom-cli-option-args opt) for args = (doom-cli-option-args opt)
for flagstr = (string-join (doom-cli-option-flags 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')") (noenv-p ["--no-env"] "Don't generate an envvars file (see 'doom help env')")
(noinstall-p ["--no-install"] "Don't auto-install packages") (noinstall-p ["--no-install"] "Don't auto-install packages")
(nofonts-p ["--no-fonts"] "Don't install (or prompt to install) all-the-icons fonts") (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. "Installs and sets up Doom Emacs for the first time.
This command does the following: This command does the following:
@ -46,24 +46,20 @@ DOOMDIR environment variable. e.g.
(print! (success "Done!"))))) (print! (success "Done!")))))
'(("init.el" . '(("init.el" .
(lambda () (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" . ("config.el" .
(lambda () (lambda ()
(insert! ";;; %sconfig.el -*- lexical-binding: t; -*-\n\n" (insert-file-contents
";; Place your private configuration here\n" (doom-path doom-core-dir "templates/config.example.el"))))
((relpath doom-private-dir)))))
("packages.el" . ("packages.el" .
(lambda () (lambda ()
(insert! ";; -*- no-byte-compile: t; -*-\n;;; %spackages.el\n\n" (insert-file-contents
";;; Examples:\n" (doom-path doom-core-dir "templates/packages.example.el")))))))
";; (package! some-package)\n"
";; (package! another-package :recipe (:host github :repo \"username/repo\"))\n"
";; (package! builtin-package :disable t)\n"
((relpath doom-private-dir))))))))
;; In case no init.el was present the first time `doom-initialize-modules' was ;; In case no init.el was present the first time `doom-initialize-modules' was
;; called in core.el (e.g. on first install) ;; called in core.el (e.g. on first install)
(doom-initialize 'force) (doom-initialize 'force 'noerror)
(doom-initialize-modules) (doom-initialize-modules)
;; Ask if user would like an envvar file generated ;; 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) (if (file-exists-p doom-env-file)
(print! (info "Envvar file already exists, skipping")) (print! (info "Envvar file already exists, skipping"))
(when (or doom-auto-accept (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)))) (doom-cli-reload-env-file 'force-p))))
;; Install Doom packages ;; Install Doom packages
@ -82,16 +78,24 @@ DOOMDIR environment variable. e.g.
(doom-cli-packages-install)) (doom-cli-packages-install))
(print! "Regenerating autoloads files") (print! "Regenerating autoloads files")
(doom-cli-reload-autoloads nil 'force-p) (doom-cli-reload-autoloads)
(if nofonts-p (cond (nofonts-p)
(print! (warn "Not installing fonts, as requested")) (IS-WINDOWS
(when (or doom-auto-accept (print! (warn "Doom cannot install all-the-icons' fonts on Windows!\n"))
(y-or-n-p "Download and install all-the-icon's fonts?")) (print-group!
(require 'all-the-icons) (print!
(let ((window-system (cond (IS-MAC 'ns) (concat "You'll have to do so manually:\n\n"
(IS-LINUX 'x)))) " 1. Launch Doom Emacs\n"
(all-the-icons-install-fonts 'yes)))) " 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") (when (file-exists-p "~/.emacs")
(print! (warn "A ~/.emacs file was detected. This conflicts with Doom and should be deleted!"))) (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; -*- ;; -*- no-byte-compile: t; -*-
;;; core/cli/packages.el ;;; core/cli/packages.el
(defcli! (update u) () (defcli! (update u)
((discard-p ["--discard"] "All local changes to packages are discarded"))
"Updates packages. "Updates packages.
This works by fetching all installed package repos and checking the distance 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 This excludes packages whose `package!' declaration contains a non-nil :freeze
or :ignore property." or :ignore property."
(straight-check-all) (straight-check-all)
(doom-cli-reload-core-autoloads) (let ((doom-auto-discard discard-p))
(when (doom-cli-packages-update) (doom-cli-reload-core-autoloads)
(doom-cli-reload-package-autoloads 'force-p)) (when (doom-cli-packages-update)
t) (doom-cli-reload-package-autoloads))
t))
(defcli! (build b) (defcli! (build b)
((rebuild-p ["-r"] "Only rebuild packages that need rebuilding")) ((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 their elisp files are byte-compiled. This is especially necessary if you upgrade
Emacs (as byte-code is generally not forward-compatible)." Emacs (as byte-code is generally not forward-compatible)."
(when (doom-cli-packages-build (not rebuild-p)) (when (doom-cli-packages-build (not rebuild-p))
(doom-cli-reload-package-autoloads 'force-p)) (doom-cli-reload-package-autoloads))
t) t)
(defcli! (purge p) (defcli! (purge p)
@ -46,7 +48,7 @@ list remains lean."
(not norepos-p) (not norepos-p)
(not nobuilds-p) (not nobuilds-p)
regraft-p) regraft-p)
(doom-cli-reload-package-autoloads 'force-p)) (doom-cli-reload-package-autoloads))
t) t)
;; (defcli! rollback () ; TODO doom rollback ;; (defcli! rollback () ; TODO doom rollback
@ -57,138 +59,186 @@ list remains lean."
;; ;;
;;; Library ;;; 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 () (defun doom-cli-packages-install ()
"Installs missing packages. "Installs missing packages.
This function will install any primary package (i.e. a package with a `package!' This function will install any primary package (i.e. a package with a `package!'
declaration) or dependency thereof that hasn't already been." declaration) or dependency thereof that hasn't already been."
(print! (start "Installing & building packages...")) (straight--transaction-finalize)
(print-group! (print! (start "Installing packages..."))
(let ((n 0)) (let ((pinned (doom-package-pinned-list)))
(dolist (package (hash-table-keys straight--recipe-cache)) (print-group!
(straight--with-plist (gethash package straight--recipe-cache) (if-let (built
(local-repo) (doom-with-package-recipes (doom-package-recipe-list)
(let ((existed-p (file-directory-p (straight--repos-dir package)))) (recipe package type local-repo)
(condition-case-unless-debug e (condition-case-unless-debug e
(and (straight-use-package (intern package) nil nil (make-string (1- (or doom-format-indent 1)) 32)) (straight-use-package (intern package))
(not existed-p) (error
(file-directory-p (straight--repos-dir package)) (signal 'doom-package-error
(cl-incf n)) (list package e (straight--process-get-output)))))))
(error (print! (success "Installed %d packages")
(signal 'doom-package-error (length built))
(list e (straight--process-get-output)))))))) (print! (info "No packages need to be installed"))
(if (= n 0) nil))))
(ignore (print! (success "No packages need to be installed")))
(print! (success "Installed & built %d packages") n)
t))))
(defun doom-cli-packages-build (&optional force-p) (defun doom-cli-packages-build (&optional force-p)
"(Re)build all packages." "(Re)build all packages."
(straight--transaction-finalize)
(print! (start "(Re)building %spackages...") (if force-p "all " "")) (print! (start "(Re)building %spackages...") (if force-p "all " ""))
(print-group! (print-group!
(let ((n 0)) (let ((straight-check-for-modifications
(if force-p (when (file-directory-p (straight--modified-dir))
(let ((straight--packages-to-rebuild :all) '(find-when-checking)))
(straight--packages-not-to-rebuild (make-hash-table :test #'equal))) (straight--allow-find
(dolist (package (hash-table-keys straight--recipe-cache)) (and straight-check-for-modifications
(straight-use-package (executable-find straight-find-executable)
(intern package) nil (lambda (_) (cl-incf n) nil) t))
(make-string (1- (or doom-format-indent 1)) 32)))) (straight--packages-not-to-rebuild
(dolist (recipe (hash-table-values straight--recipe-cache)) (or straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
(straight--with-plist recipe (package local-repo no-build) (straight--packages-to-rebuild
(unless (or no-build (null local-repo)) (or (if force-p :all straight--packages-to-rebuild)
;; REVIEW We do these modification checks manually because (make-hash-table :test #'equal)))
;; Straight's checks seem to miss stale elc files. Need (recipes (doom-package-recipe-list)))
;; more tests to confirm this. (unless force-p
(when (or (ignore-errors (straight--make-build-cache-available))
(gethash package straight--packages-to-rebuild)) (if-let (built
(gethash package straight--cached-package-modifications) (doom-with-package-recipes recipes (package local-repo)
(not (file-directory-p (straight--build-dir package))) (unless force-p
(cl-loop for file ;; Ensure packages with outdated files/bytecode are rebuilt
in (doom-files-in (straight--build-dir package) (let ((build-dir (straight--build-dir package))
:match "\\.el$" (repo-dir (straight--repos-dir local-repo)))
:full t) (and (or (file-newer-than-file-p repo-dir build-dir)
for elc-file = (byte-compile-dest-file file) (file-exists-p (straight--modified-dir (or local-repo package)))
if (and (file-exists-p elc-file) ;; Doesn't make sense to compare el and elc files
(file-newer-than-file-p file elc-file)) ;; when the former isn't a symlink to their source.
return t)) (when straight-use-symlinks
(let ((straight-use-package-pre-build-functions (cl-loop for file
straight-use-package-pre-build-functions)) in (doom-files-in build-dir :match "\\.el$" :full t)
(add-hook 'straight-use-package-pre-build-functions for elc-file = (byte-compile-dest-file file)
(lambda (&rest _) (cl-incf n))) if (and (file-exists-p elc-file)
(let ((straight--packages-to-rebuild :all) (file-newer-than-file-p file elc-file))
(straight--packages-not-to-rebuild (make-hash-table :test #'equal))) return t)))
(straight-use-package (puthash package t straight--packages-to-rebuild))))
(intern package) nil nil (straight-use-package (intern package))))
(make-string (or doom-format-indent 0) 32))) (print! (success "Rebuilt %d package(s)") (length built))
(straight--byte-compile-package recipe) (print! (success "No packages need rebuilding"))
(dolist (dep (straight--get-dependencies package)) nil))))
(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))))
(defun doom-cli-packages-update () (defun doom-cli-packages-update ()
"Updates packages." "Updates packages."
(straight--transaction-finalize)
(print! (start "Updating packages (this may take a while)...")) (print! (start "Updating packages (this may take a while)..."))
(let ((straight--packages-to-rebuild (make-hash-table :test #'equal)) (let* ((repo-dir (straight--repos-dir))
(total (hash-table-count straight--repo-cache)) (pinned (doom-package-pinned-list))
(i 1) (packages-to-rebuild (make-hash-table :test 'equal))
errors) (repos-to-rebuild (make-hash-table :test 'equal))
(print-group! (recipes (doom-package-recipe-list))
(dolist (recipe (hash-table-values straight--repo-cache)) (total (length recipes))
(straight--with-plist recipe (package type local-repo) (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 (condition-case-unless-debug e
(let* ((default-directory (straight--repos-dir local-repo)) (let ((ref (straight-vc-get-commit type local-repo))
(commit (straight-vc-get-commit type local-repo))) (target-ref (cdr (assoc local-repo pinned)))
(if (not (straight-vc-fetch-from-remote recipe)) output)
(print! (warn "(%d/%d) Failed to fetch %s" i total package)) (or (cond
(let ((output (straight--process-get-output))) ((not (stringp target-ref))
(straight-merge-package package) (print! (start "\033[K(%d/%d) Fetching %s...%s") i total package esc)
(let ((newcommit (straight-vc-get-commit type local-repo))) (when (straight-vc-fetch-from-remote recipe)
(if (string= commit newcommit) (setq output (straight--process-get-output))
(print! (info "(%d/%d) %s is up-to-date") i total package) (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 (ignore-errors
(delete-directory (straight--build-dir package) 'recursive)) (delete-directory repo 'recursive))
(puthash package t straight--packages-to-rebuild) (print-group!
(print! (success "(%d/%d) %s updated (%s -> %s)") i total package (straight-use-package (intern package) nil 'no-build))
(substring commit 0 7) (prog1 (file-directory-p repo)
(substring newcommit 0 7)) (or (not (eq type 'git))
(unless (string-empty-p output) (setq output (doom--commit-log-between ref target-ref)))))))
(print-group! (progn
(print! (info "%s") output) (print! (warn "\033[K(%d/%d) Failed to fetch %s")
(when (eq type 'git) i total local-repo)
(straight--call "git" "log" "--oneline" newcommit (concat "^" commit)) (unless (string-empty-p output)
(print-group! (print-group! (print! (info "%s" output))))
(print! "%s" (straight--process-get-output)))))))))) (cl-return)))
(cl-incf i)) (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 (user-error
(signal 'user-error (error-message-string e))) (signal 'user-error (error-message-string e)))
(error (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-group!
(print! (error "%s" e)) (print! (error "%s") e)
(print-group! (print! (info "%s" (straight--process-get-output))))) (print-group! (print! (info "%s" (straight--process-get-output)))))
(push package errors))))) (push package errors))))))
(when errors (princ "\033[K")
(print! (error "There were %d errors, the offending packages are: %s") (when errors
(length errors) (string-join errors ", "))) (print! (error "Encountered %d error(s), the offending packages: %s")
(if (hash-table-empty-p straight--packages-to-rebuild) (length errors) (string-join errors ", ")))
(ignore (if (hash-table-empty-p packages-to-rebuild)
(print! (success "All %d packages are up-to-date") (ignore (print! (success "All %d packages are up-to-date") total))
(hash-table-count straight--repo-cache))) (let ((default-directory (straight--build-dir)))
(let ((count (hash-table-count straight--packages-to-rebuild)) (mapc (doom-rpartial #'delete-directory 'recursive)
(packages (hash-table-keys straight--packages-to-rebuild))) (hash-table-keys packages-to-rebuild)))
(sort packages #'string-lessp) (print! (success "Updated %d package(s)")
(doom--finalize-straight) (hash-table-count packages-to-rebuild))
(doom-cli-packages-build) (doom-cli-packages-build)
(print! (success "Updated %d package(s)") count)) t)))
t))))
;;; PURGE (for the emperor) ;;; PURGE (for the emperor)
@ -204,34 +254,44 @@ declaration) or dependency thereof that hasn't already been."
(if (not builds) (if (not builds)
(progn (print! (info "No builds to purge")) (progn (print! (info "No builds to purge"))
0) 0)
(length (print! (start "Purging straight builds..." (length builds)))
(delq nil (mapcar #'doom--cli-packages-purge-build 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))) (let ((default-directory (straight--repos-dir repo)))
(if (not (file-directory-p ".git")) (unless (file-directory-p ".git")
(ignore (print! (warn "repos/%s is not a git repo, skipping" repo))) (print! (warn "\033[Krepos/%s is not a git repo, skipping" repo))
(let ((before-size (doom-directory-size default-directory))) (cl-return))
(straight--call "git" "reset" "--hard") (unless (file-in-directory-p default-directory straight-base-dir)
(straight--call "git" "clean" "-ffd") (print! (warn "\033[KSkipping repos/%s because it is local" repo))
(if (not (car (straight--call "git" "replace" "--graft" "HEAD"))) (cl-return))
(print! (info "repos/%s is already compact" repo)) (let ((before-size (doom-directory-size default-directory)))
(straight--call "git" "gc") (straight--call "git" "reset" "--hard")
(print! (success "Regrafted repos/%s (from %0.1fKB to %0.1fKB)") (straight--call "git" "clean" "-ffd")
repo before-size (doom-directory-size default-directory)) (if (not (car (straight--call "git" "replace" "--graft" "HEAD")))
(print-group! (print! "%s" (straight--process-get-output))))) (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))) t)))
(defun doom--cli-packages-regraft-repos (repos) (defun doom--cli-packages-regraft-repos (repos)
(if (not repos) (if (not repos)
(progn (print! (info "No repos to regraft")) (progn (print! (info "No repos to regraft"))
0) 0)
(print! (start "Regrafting %d repos..." (length repos)))
(let ((before-size (doom-directory-size (straight--repos-dir)))) (let ((before-size (doom-directory-size (straight--repos-dir))))
(prog1 (print-group! (delq nil (mapcar #'doom--cli-packages-regraft-repo repos))) (print-group!
(let ((after-size (doom-directory-size (straight--repos-dir)))) (prog1 (delq nil (mapcar #'doom--cli-packages-regraft-repo repos))
(print! (success "Finished regrafting. Size before: %0.1fKB and after: %0.1fKB (%0.1fKB)") (princ "\033[K")
before-size after-size (let ((after-size (doom-directory-size (straight--repos-dir))))
(- after-size before-size))))))) (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) (defun doom--cli-packages-purge-repo (repo)
(let ((repo-dir (straight--repos-dir repo))) (let ((repo-dir (straight--repos-dir repo)))
@ -247,22 +307,29 @@ declaration) or dependency thereof that hasn't already been."
(if (not repos) (if (not repos)
(progn (print! (info "No repos to purge")) (progn (print! (info "No repos to purge"))
0) 0)
(length (print! (start "Purging straight repositories..."))
(delq nil (mapcar #'doom--cli-packages-purge-repo repos))))) (print-group!
(length
(delq nil (mapcar #'doom--cli-packages-purge-repo repos))))))
(defun doom--cli-packages-purge-elpa () (defun doom--cli-packages-purge-elpa ()
(unless (bound-and-true-p package--initialized) (require 'core-packages)
(package-initialize)) (let ((dirs (doom-files-in package-user-dir :type t :depth 0)))
(let ((packages (cl-loop for (package desc) in package-alist (if (not dirs)
for dir = (package-desc-dir desc)
if (file-in-directory-p dir package-user-dir)
collect (cons package dir))))
(if (not package-alist)
(progn (print! (info "No ELPA packages to purge")) (progn (print! (info "No ELPA packages to purge"))
0) 0)
(mapc (doom-rpartial #'delete-directory 'recursive) (print! (start "Purging ELPA packages..."))
(mapcar #'cdr packages)) (dolist (path dirs (length dirs))
(length packages)))) (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) (defun doom-cli-packages-purge (&optional elpa-p builds-p repos-p regraft-repos-p)
"Auto-removes orphaned packages and repos. "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 BUILDS-P, include straight package builds.
If REPOS-P, include straight repos. If REPOS-P, include straight repos.
If ELPA-P, include packages installed with package.el (M-x package-install)." 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) (cl-destructuring-bind (&optional builds-to-purge repos-to-purge repos-to-regraft)
(let ((rdirs (straight--directory-files (straight--repos-dir) nil nil 'sort)) (let ((rdirs (straight--directory-files (straight--repos-dir) nil nil 'sort))
(bdirs (straight--directory-files (straight--build-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")) (print! (info "Skipping regrafting"))
(and (doom--cli-packages-regraft-repos repos-to-regraft) (and (doom--cli-packages-regraft-repos repos-to-regraft)
(setq success t))) (setq success t)))
(when success success))))
(doom--finalize-straight)
t)))))

View file

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

View file

@ -1,7 +1,8 @@
;;; core/cli/upgrade.el -*- lexical-binding: t; -*- ;;; core/cli/upgrade.el -*- lexical-binding: t; -*-
(defcli! (upgrade up) (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. "Updates Doom and packages.
This requires that ~/.emacs.d is a git repo, and is the equivalent of the 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 cd ~/.emacs.d
git pull --rebase git pull --rebase
bin/doom clean bin/doom clean
bin/doom refresh bin/doom sync
bin/doom update" bin/doom update"
:bare t :bare t
(when (doom-cli-upgrade doom-auto-accept force-p) (let ((doom-auto-discard force-p))
(require 'core-packages) (if (delq
(doom-initialize) nil (list
(doom-initialize-packages) (unless packages-only-p
(when (doom-cli-packages-update) (doom-cli-upgrade doom-auto-accept doom-auto-discard))
(doom-cli-reload-package-autoloads 'force)))) (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) (cl-destructuring-bind (success . stdout)
(doom-call-process "git" "status" "--porcelain" "-uno") (doom-call-process "git" "status" "--porcelain" "-uno")
(if (= 0 success) (if (= 0 success)
(string-match-p "[^ \t\n]" (buffer-string)) (split-string stdout "\n" t)
(error "Failed to check working tree in %s" dir)))) (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?"))) "Couldn't detect what branch you're on. Is Doom detached?")))
;; We assume that a dirty .emacs.d is intentional and abort ;; 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) (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)) (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...")) (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" "reset" "--hard" (format "origin/%s" branch))
(doom-call-process "git" "clean" "-ffd"))) (doom-call-process "git" "clean" "-ffd")))
(doom-call-process "git" "remote" "remove" doom-repo-remote) (doom-call-process "git" "remote" "remove" doom-repo-remote)
(unwind-protect (unwind-protect
(progn (let (result)
(or (zerop (car (doom-call-process "git" "remote" "add" doom-repo-remote doom-repo-url))) (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)) (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")) (error "Failed to fetch from upstream"))
(let ((this-rev (vc-git--rev-parse "HEAD")) (let ((this-rev (vc-git--rev-parse "HEAD"))
@ -99,13 +106,11 @@ following shell commands:
(print! (start "Upgrading Doom Emacs...")) (print! (start "Upgrading Doom Emacs..."))
(print-group! (print-group!
(doom-clean-byte-compiled-files) (doom-clean-byte-compiled-files)
(unless (and (zerop (car (doom-call-process "git" "reset" "--hard" target-remote))) (if (and (zerop (car (doom-call-process "git" "reset" "--hard" target-remote)))
(equal (vc-git--rev-parse "HEAD") new-rev)) (equal (vc-git--rev-parse "HEAD") new-rev))
(print! (info "%s") (cdr result))
(error "Failed to check out %s" (substring new-rev 0 10))) (error "Failed to check out %s" (substring new-rev 0 10)))
(print! (success "Finished upgrading Doom Emacs"))) (print! (success "Finished upgrading Doom Emacs")))
(doom-cli-execute "refresh" (if auto-accept-p '("-y"))) t)))))
t)
(print! (success "Done! Restart Emacs for changes to take effect."))))))
(ignore-errors (ignore-errors
(doom-call-process "git" "remote" "remove" doom-repo-remote)))))) (doom-call-process "git" "remote" "remove" doom-repo-remote))))))

View file

@ -1,14 +1,5 @@
;;; -*- lexical-binding: t; no-byte-compile: t; -*- ;;; -*- 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 ;;; Variables
@ -17,6 +8,9 @@
commands like `doom-cli-packages-install', `doom-cli-packages-update' and commands like `doom-cli-packages-install', `doom-cli-packages-update' and
`doom-packages-autoremove'.") `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-p nil)
(defvar doom--cli-commands (make-hash-table :test 'equal)) (defvar doom--cli-commands (make-hash-table :test 'equal))
(defvar doom--cli-groups (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 :plist plist
:fn :fn
(lambda (--alist--) (lambda (--alist--)
(ignore --alist--)
(let ,(cl-loop for opt in speclist (let ,(cl-loop for opt in speclist
for optsym = (if (listp opt) (car opt) opt) for optsym = (if (listp opt) (car opt) opt)
unless (memq optsym cl--lambda-list-keywords) unless (memq optsym cl--lambda-list-keywords)
collect (list optsym `(cdr (assq ',optsym --alist--)))) collect (list optsym `(cdr (assq ',optsym --alist--))))
,@(unless (plist-get plist :bare) ,@(unless (plist-get plist :bare)
'((unless doom-init-p '((unless doom-init-p
(doom-initialize 'force) (doom-initialize 'force 'noerror)
(doom-initialize-modules)))) (doom-initialize-modules))))
,@body))) ,@body)))
doom--cli-commands) doom--cli-commands)
@ -209,15 +204,127 @@ BODY will be run when this dispatcher is called."
,@body)) ,@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 ;;; CLI Commands
(load! "cli/help") (load! "cli/help")
(load! "cli/install") (load! "cli/install")
(defcli! (refresh re) (defcligroup! "Maintenance"
((if-necessary-p ["-n" "--if-necessary"] "Only regenerate autoloads files if necessary")) "For managing your config and packages"
"Ensure Doom is properly set up. (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 This is the equivalent of running autoremove, install, autoloads, then
recompile. Run this whenever you: 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 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 installed, autoloads files are up-to-date and no byte-compiled files have gone
stale." stale."
(print! (green "Initiating a refresh of Doom Emacs...\n")) :bare t
(let (success) (let (success)
(when (file-exists-p doom-env-file) ;; Ensures that no pre-existing state pollutes the generation of the new
(doom-cli-reload-env-file 'force)) ;; autoloads files.
(doom-cli-reload-core-autoloads (not if-necessary-p)) (dolist (file (list doom-autoload-file doom-package-autoload-file))
(unwind-protect (delete-file file)
(progn (delete-file (byte-compile-dest-file file)))
(and (doom-cli-packages-install)
(setq success t)) (doom-initialize 'force 'noerror)
(and (doom-cli-packages-build) (doom-initialize-modules)
(setq success t))
(and (doom-cli-packages-purge nil 'builds-p nil) (print! (start "Synchronizing your config with Doom Emacs..."))
(setq success t))) (print-group!
(doom-cli-reload-package-autoloads (or success (not if-necessary-p))) (when (and (not inhibit-envvar-p)
(doom-cli-byte-compile nil 'recompile)) (file-exists-p doom-env-file))
t)) (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" (defcligroup! "Diagnostics"
"For troubleshooting and diagnostics" "For troubleshooting and diagnostics"
@ -253,13 +372,6 @@ stale."
(load! "cli/debug") (load! "cli/debug")
(load! "cli/test")) (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" (defcligroup! "Compilation"
"For compiling Doom and your config" "For compiling Doom and your config"
(load! "cli/byte-compile")) (load! "cli/byte-compile"))

View file

@ -12,11 +12,14 @@ successfully sets indent_style/indent_size.")
(defvar-local doom-large-file-p nil) (defvar-local doom-large-file-p nil)
(put 'doom-large-file-p 'permanent-local t) (put 'doom-large-file-p 'permanent-local t)
(defvar doom-large-file-size 1 (defvar doom-large-file-size-alist '(("." . 1.0))
"The threshold above which Doom enables emergency optimizations. "An alist mapping regexps (like `auto-mode-alist') to filesize thresholds.
This threshold is in MB. See `doom--optimize-for-large-files-a' for If a file is opened and discovered to be larger than the threshold, Doom
implementation details.") 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 (defvar doom-large-file-excluded-modes
'(so-long-mode special-mode archive-mode tar-mode jka-compr '(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) (defadvice! doom--optimize-for-large-files-a (orig-fn &rest args)
"Set `doom-large-file-p' if the file is too large. "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 `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 runtime costs (or disable themselves) to ensure the buffer is as fast as
possible." possible."
@ -39,19 +42,24 @@ possible."
(if (setq doom-large-file-p (if (setq doom-large-file-p
(and buffer-file-name (and buffer-file-name
(not doom-large-file-p) (not doom-large-file-p)
(file-readable-p buffer-file-name) (file-exists-p buffer-file-name)
(> (nth 7 (file-attributes buffer-file-name)) (ignore-errors
(* 1024 1024 doom-large-file-size)))) (> (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) (prog1 (apply orig-fn args)
(if (memq major-mode doom-large-file-excluded-modes) (if (memq major-mode doom-large-file-excluded-modes)
(setq doom-large-file-p nil) (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..."))) (message "Large file detected! Cutting a few corners to improve performance...")))
(apply orig-fn args))) (apply orig-fn args)))
;; Resolve symlinks when opening files, so that any operations are conducted ;; Resolve symlinks when opening files, so that any operations are conducted
;; from the file's true directory (like `find-file'). ;; 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 ;; 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. ;; 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)) (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, ;; 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). ;; pb{copy,paste}, wl-copy, termux-clipboard-get, or getclip (cygwin).
(add-hook! 'tty-setup-hook (unless IS-WINDOWS
(defun doom-init-clipboard-in-tty-emacs-h () (add-hook! 'tty-setup-hook
(and (not (getenv "SSH_CONNECTION")) (defun doom-init-clipboard-in-tty-emacs-h ()
(require 'xclip nil t) (and (not (getenv "SSH_CONNECTION"))
(xclip-mode +1)))) (require 'xclip nil t)
(xclip-mode +1)))))
;; ;;
@ -140,6 +146,7 @@ possible."
(push '("/LICENSE\\'" . text-mode) auto-mode-alist) (push '("/LICENSE\\'" . text-mode) auto-mode-alist)
(push '("\\.log\\'" . 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))) (not (file-remote-p file)))
(file-truename file) (file-truename file)
file)) file))
(setq recentf-filename-handlers '(doom--recent-file-truename abbreviate-file-name)) (setq recentf-filename-handlers
'(substring-no-properties
(setq recentf-save-file (concat doom-cache-dir "recentf") doom--recent-file-truename
abbreviate-file-name)
recentf-save-file (concat doom-cache-dir "recentf")
recentf-auto-cleanup 'never recentf-auto-cleanup 'never
recentf-max-menu-items 0 recentf-max-menu-items 0
recentf-max-saved-items 200 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))))
(add-hook! '(doom-switch-window-hook write-file-functions) (add-hook! '(doom-switch-window-hook write-file-functions)
(defun doom--recentf-touch-buffer-h () (defun doom--recentf-touch-buffer-h ()
@ -250,6 +254,11 @@ possible."
:after-while #'save-place-find-file-hook :after-while #'save-place-find-file-hook
(if buffer-file-name (ignore-errors (recenter)))) (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) (defadvice! doom--dont-prettify-saveplace-cache-a (orig-fn)
"`save-place-alist-to-file' uses `pp' to prettify the contents of its cache. "`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 `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 (use-package! server
:when (display-graphic-p) :when (display-graphic-p)
:after-call pre-command-hook after-find-file focus-out-hook :after-call pre-command-hook after-find-file focus-out-hook
:defer 1
:init :init
(when-let (name (getenv "EMACS_SERVER_NAME")) (when-let (name (getenv "EMACS_SERVER_NAME"))
(setq server-name 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 :around #'dtrt-indent-mode
(let ((dtrt-indent-run-after-smie dtrt-indent-run-after-smie)) (let ((dtrt-indent-run-after-smie dtrt-indent-run-after-smie))
(cl-letf* ((old-smie-config-guess (symbol-function 'smie-config-guess)) (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) ((symbol-function 'smie-config-guess)
(lambda () (lambda ()
(condition-case e (funcall old-smie-config-guess) (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 ;; a better *help* buffer
:commands helpful--read-symbol :commands helpful--read-symbol
:init :init
(define-key! (global-set-key [remap describe-function] #'helpful-callable)
[remap describe-function] #'helpful-callable (global-set-key [remap describe-command] #'helpful-command)
[remap describe-command] #'helpful-command (global-set-key [remap describe-variable] #'helpful-variable)
[remap describe-variable] #'helpful-variable (global-set-key [remap describe-key] #'helpful-key)
[remap describe-key] #'helpful-key (global-set-key [remap describe-symbol] #'helpful-symbol)
[remap describe-symbol] #'doom/describe-symbol)
(defun doom-use-helpful-a (orig-fn &rest args) (defun doom-use-helpful-a (orig-fn &rest args)
"Force ORIG-FN to use helpful instead of the old describe-* commands." "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) (require 'smartparens-config)
;; Overlays are too distracting and not terribly helpful. show-parens does ;; 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 (setq sp-highlight-pair-overlay nil
sp-highlight-wrap-overlay nil sp-highlight-wrap-overlay nil
sp-highlight-wrap-tag-overlay nil) sp-highlight-wrap-tag-overlay nil)
;; But if someone does want overlays enabled, evil users will be stricken with (with-eval-after-load 'evil
;; an off-by-one issue where smartparens assumes you're outside the pair when ;; But if someone does want overlays enabled, evil users will be stricken
;; you're really at the last character in insert mode. We must correct this ;; with an off-by-one issue where smartparens assumes you're outside the
;; vile injustice. ;; pair when you're really at the last character in insert mode. We must
(setq sp-show-pair-from-inside t) ;; correct this vile injustice.
;; ...and stay highlighted until we've truly escaped the pair! (setq sp-show-pair-from-inside t)
(setq sp-cancel-autoskip-on-backward-movement nil) ;; ...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 ;; 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. ;; better compromise between performance and accuracy.
(setq sp-max-prefix-length 50) (setq sp-max-prefix-length 25)
;; This speeds up smartparens. No pair has any business being longer than 4 ;; No pair has any business being longer than 4 characters; if they must, set
;; characters; if they must, the modes that need it set it buffer-locally. ;; it buffer-locally. It's less work for smartparens.
(setq sp-max-pair-length 4) (setq sp-max-pair-length 4)
;; This isn't always smart enough to determine when we're in a string or not. ;; This isn't always smart enough to determine when we're in a string or not.
;; See https://github.com/Fuco1/smartparens/issues/783. ;; 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 ;; Silence some harmless but annoying echo-area spam
(dolist (key '(:unmatched-expression :no-matching-tag)) (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 (add-hook! 'minibuffer-setup-hook
(defun doom-init-smartparens-in-minibuffer-maybe-h () (defun doom-init-smartparens-in-minibuffer-maybe-h ()
"Enable `smartparens-mode' in the minibuffer, during `eval-expression' or "Enable `smartparens-mode' in the minibuffer, during `eval-expression',
`evil-ex'." `pp-eval-expression' or `evil-ex'."
(when (memq this-command '(eval-expression evil-ex)) (when (memq this-command '(eval-expression pp-eval-expression evil-ex))
(smartparens-mode)))) (smartparens-mode))))
;; You're likely writing lisp in the minibuffer, therefore, disable these ;; 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) (delq! 'buffer-read-only so-long-variable-overrides 'assq)
;; ...but at least reduce the level of syntax highlighting ;; ...but at least reduce the level of syntax highlighting
(add-to-list 'so-long-variable-overrides '(font-lock-maximum-decoration . 1)) (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 ;; But disable everything else that may be unnecessary/expensive for large
;; or wide buffers. ;; or wide buffers.
(appendq! so-long-minor-modes (appendq! so-long-minor-modes
@ -494,14 +513,26 @@ files, so we replace calls to `pp' with the much faster `prin1'."
auto-composition-mode auto-composition-mode
undo-tree-mode undo-tree-mode
highlight-indent-guides-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 (use-package! undo-tree
;; Branching & persistent undo ;; Branching & persistent undo
:after-call doom-switch-buffer-hook after-find-file :after-call doom-switch-buffer-hook after-find-file
:config :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 ;; Increase undo-limits by a factor of ten to avoid emacs prematurely
;; truncating the undo history and corrupting the tree. See ;; truncating the undo history and corrupting the tree. See
;; https://github.com/syl20bnr/spacemacs/issues/12110 ;; 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)) (stringp (car item))
(setcar item (substring-no-properties (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)) (global-undo-tree-mode +1))
(use-package! ws-butler (use-package! ws-butler
;; a less intrusive `delete-trailing-whitespaces' on save ;; a less intrusive `delete-trailing-whitespaces' on save
:after-call after-find-file :after-call after-find-file
:config :config (ws-butler-global-mode +1))
(appendq! ws-butler-global-exempt-modes
'(special-mode comint-mode term-mode eshell-mode))
(ws-butler-global-mode))
(provide 'core-editor) (provide 'core-editor)
;;; core-editor.el ends here ;;; 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 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 function which does the same as FUN, except that the last N arguments are fixed
at the values with which this function was called." at the values with which this function was called."
(declare (pure t) (side-effect-free t))
(lambda (&rest pre-args) (lambda (&rest pre-args)
(apply fn (append pre-args args)))) (apply fn (append pre-args args))))
@ -101,14 +102,18 @@ at the values with which this function was called."
;;; Sugars ;;; Sugars
(defmacro λ! (&rest body) (defmacro λ! (&rest body)
"Expands to (lambda () (interactive) ,@body)." "Expands to (lambda () (interactive) ,@body).
(declare (doc-string 1)) 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)) `(lambda () (interactive) ,@body))
(defalias 'lambda! 'λ!) (defalias 'lambda! 'λ!)
(defun λ!! (command &optional arg) (defun λ!! (command &optional arg)
"Expands to a command that interactively calls COMMAND with prefix ARG." "Expands to a command that interactively calls COMMAND with prefix ARG.
(declare (doc-string 1)) A factory for quickly producing interactive, prefixed commands for keybinds or
aliases."
(declare (doc-string 1) (pure t) (side-effect-free t))
(lambda () (interactive) (lambda () (interactive)
(let ((current-prefix-arg arg)) (let ((current-prefix-arg arg))
(call-interactively command)))) (call-interactively command))))
@ -128,8 +133,62 @@ at the values with which this function was called."
(when-let (path (file!)) (when-let (path (file!))
(directory-file-name (file-name-directory path)))) (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) (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 (macroexp-progn
(cl-loop for (var val) on settings by 'cddr (cl-loop for (var val) on settings by 'cddr
collect `(funcall (or (get ',var 'custom-set) #'set) collect `(funcall (or (get ',var 'custom-set) #'set)
@ -150,10 +209,6 @@ This is a variadic `cl-pushnew'."
"Append LISTS to SYM in place." "Append LISTS to SYM in place."
`(setq ,sym (append ,sym ,@lists))) `(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) (defmacro delq! (elt list &optional fetcher)
"`delq' ELT from LIST in-place. "`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) elt)
,list))) ,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) (defmacro add-load-path! (&rest dirs)
"Add DIRS to `load-path', relative to the current file. "Add DIRS to `load-path', relative to the current file.
The current file is the file from which `add-to-load-path!' is used." 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: 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), 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 3. The function(s) to be added: this can be one function, a quoted list
modes, a quoted hook variable or a quoted list of hook variables. If thereof, a list of `defun's, or body forms (implicitly wrapped in a
unquoted, '-hook' will be appended to each symbol. lambda).
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).
\(fn HOOKS [:append :local] FUNCTIONS)" \(fn HOOKS [:append :local] FUNCTIONS)"
(declare (indent (lambda (indent-point state) (declare (indent (lambda (indent-point state)
@ -408,10 +473,27 @@ DOCSTRING and BODY are as in `defun'.
where-alist)) where-alist))
`(progn `(progn
(defun ,symbol ,arglist ,docstring ,@body) (defun ,symbol ,arglist ,docstring ,@body)
,(when where-alist (dolist (targets (list ,@(nreverse where-alist)))
`(dolist (targets (list ,@(nreverse where-alist))) (dolist (target (cdr targets))
(dolist (target (cdr targets)) (advice-add target (car targets) #',symbol))))))
(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) (provide 'core-lib)
;;; core-lib.el ends here ;;; core-lib.el ends here

View file

@ -13,8 +13,8 @@
(defconst doom-obsolete-modules (defconst doom-obsolete-modules
'((:feature (version-control (:emacs vc) (:ui vc-gutter)) '((:feature (version-control (:emacs vc) (:ui vc-gutter))
(spellcheck (:tools flyspell)) (spellcheck (:checkers spell))
(syntax-checker (:tools flycheck)) (syntax-checker (:checkers syntax))
(evil (:editor evil)) (evil (:editor evil))
(snippets (:editor snippets)) (snippets (:editor snippets))
(file-templates (:editor file-templates)) (file-templates (:editor file-templates))
@ -24,7 +24,9 @@
(debugger (:tools debugger))) (debugger (:tools debugger)))
(:tools (rotate-text (:editor rotate-text)) (:tools (rotate-text (:editor rotate-text))
(vterm (:term vterm)) (vterm (:term vterm))
(password-store (:tools pass))) (password-store (:tools pass))
(flycheck (:checkers syntax))
(flyspell (:checkers spell)))
(:emacs (electric-indent (:emacs electric)) (:emacs (electric-indent (:emacs electric))
(hideshow (:editor fold)) (hideshow (:editor fold))
(eshell (:term eshell)) (eshell (:term eshell))
@ -40,7 +42,7 @@
Each entry is a three-level tree. For example: Each entry is a three-level tree. For example:
(:feature (version-control (:emacs vc) (:ui vc-gutter)) (:feature (version-control (:emacs vc) (:ui vc-gutter))
(spellcheck (:tools flyspell)) (spellcheck (:checkers spell))
(syntax-checker (:tools flycheck))) (syntax-checker (:tools flycheck)))
This marks :feature version-control, :feature spellcheck and :feature This marks :feature version-control, :feature spellcheck and :feature
@ -76,6 +78,7 @@ non-nil."
(when (or force-p (not doom-init-modules-p)) (when (or force-p (not doom-init-modules-p))
(setq doom-init-modules-p t (setq doom-init-modules-p t
doom-modules nil) doom-modules nil)
(load custom-file 'noerror 'nomessage)
(when (load! "init" doom-private-dir t) (when (load! "init" doom-private-dir t)
(when doom-modules (when doom-modules
(maphash (lambda (key plist) (maphash (lambda (key plist)
@ -101,11 +104,10 @@ non-nil."
(defun doom-module-p (category module &optional flag) (defun doom-module-p (category module &optional flag)
"Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')." "Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')."
(declare (pure t) (side-effect-free t)) (declare (pure t) (side-effect-free t))
(let ((plist (gethash (cons category module) doom-modules))) (when-let (plist (gethash (cons category module) doom-modules))
(and plist (or (null flag)
(or (null flag) (and (memq flag (plist-get plist :flags))
(memq flag (plist-get plist :flags))) t))))
t)))
(defun doom-module-get (category module &optional property) (defun doom-module-get (category module &optional property)
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set." "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)) (cdr doom--current-module))
doom--current-module) 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) (let* ((file-name-handler-alist nil)
(path (file-truename (or path (file!))))) (path (file-truename (or path (file!)))))
(save-match-data (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) (defmacro doom! (&rest modules)
"Bootstraps DOOM Emacs and its 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 The bootstrap process involves making sure the essential directories exist, core
packages are installed, `doom-autoload-file' is loaded, `doom-packages-file' packages are installed, `doom-autoload-file' is loaded, `doom-packages-file'
cache exists (and is loaded) and, finally, loads your private init.el (which cache exists (and is loaded) and, finally, loads your private init.el (which
should contain your `doom!' block). 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: The overall load order of Doom is as follows:
~/.emacs.d/init.el ~/.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' 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 for a list of all recognized module trees. Order defines precedence (from most
to least)." to least)."
`(let ((modules ',modules)) `(let ((modules
(unless (keywordp (car modules)) ,@(if (keywordp (car modules))
(setq modules (eval modules t))) (list (list 'quote modules))
modules)))
(unless doom-modules (unless doom-modules
(setq doom-modules (setq doom-modules
(make-hash-table :test 'equal (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) :config (default +flag1 -flag2)
CATEGORY and MODULE can be omitted When this macro is used from inside a module 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))) (and (cond (flag (memq flag (doom-module-get category module :flags)))
(module (doom-module-p category module)) (module (doom-module-p category module))
(doom--current-flags (memq category doom--current-flags)) (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))))) (memq category (doom-module-get (car module) (cdr module) :flags)))))
t)) 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 ;; DEPRECATED
(defmacro def-package! (&rest args) (defmacro def-package! (&rest args)
(make-obsolete 'def-package! 'use-package! "2.0.9") (message "`def-package!' was renamed to `use-package!'; use that instead.")
(message "`def-package!' is renamed and is now deprecated; use `use-package!' instead")
`(use-package! ,@args)) `(use-package! ,@args))
(make-obsolete 'def-package! 'use-package! "2.0.9")
(defmacro def-package-hook! (&rest args) (defmacro def-package-hook! (&rest args)
(make-obsolete 'def-package-hook! 'use-package-hook! "2.0.9") (message "`def-package-hook!' was renamed to `use-package-hook!'; use that instead.")
(message "`def-package-hook!' is renamed and is now deprecated; use `use-package-hook!' instead")
`(use-package-hook! ,@args)) `(use-package-hook! ,@args))
(make-obsolete 'def-package-hook! 'use-package-hook! "2.0.9")
(provide 'core-modules) (provide 'core-modules)
;;; core-modules.el ends here ;;; core-modules.el ends here

View file

@ -21,7 +21,7 @@
;; ;;
;; + `bin/doom install`: a wizard that guides you through setting up Doom and ;; + `bin/doom install`: a wizard that guides you through setting up Doom and
;; your private config for the first time. ;; 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 ;; condition. It ensures all unneeded packages are removed, all needed ones
;; are installed, and all metadata associated with them is generated. ;; are installed, and all metadata associated with them is generated.
;; + `bin/doom upgrade`: upgrades Doom Emacs and your packages to the latest ;; + `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's name as a symbol, and whose CDR is the plist supplied to its
`package!' declaration. Set by `doom-initialize-packages'.") `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 "A list of packages that must be installed (and will be auto-installed if
missing) and shouldn't be deleted.") 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 ;; 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. ;; shouldn't be using it, but it may be convenient for quick package testing.
(setq package--init-file-ensured t (setq package-enable-at-startup nil
package-enable-at-startup nil
package-user-dir (concat doom-local-dir "elpa/") package-user-dir (concat doom-local-dir "elpa/")
package-gnupghome-dir (expand-file-name "gpg" package-user-dir) package-gnupghome-dir (expand-file-name "gpg" package-user-dir)
;; I omit Marmalade because its packages are manually submitted rather ;; 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/")) ("melpa" . ,(concat proto "://melpa.org/packages/"))
("org" . ,(concat proto "://orgmode.org/elpa/"))))) ("org" . ,(concat proto "://orgmode.org/elpa/")))))
(advice-add #'package--ensure-init-file :override #'ignore)
;; Don't save `package-selected-packages' to `custom-file' ;; Don't save `package-selected-packages' to `custom-file'
(defadvice! doom--package-inhibit-custom-file-a (&optional value) (defadvice! doom--package-inhibit-custom-file-a (&optional value)
:override #'package--save-selected-packages :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 ;; certain things to work (like magit and org), but we can deal with that
;; when we cross that bridge. ;; when we cross that bridge.
straight-vc-git-default-clone-depth 1 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 ;; Prefix declarations are unneeded bulk added to our autoloads file. Best
;; we just don't have to deal with them at all. ;; 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 () (defadvice! doom--read-pinned-packages-a (orig-fn &rest args)
(mapc #'funcall (delq nil (mapcar #'cdr straight--transaction-alist))) "Read from `doom-pinned-packages' on top of straight's lockfiles."
(setq straight--transaction-alist nil)) :around #'straight--lockfile-read-all
(append (apply orig-fn args)
;;; Getting straight to behave in batch mode (doom-package-pinned-list)))
(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))))))
;; ;;
@ -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 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." necessary package metadata is initialized and available for them."
(unless doom-init-packages-p (unless doom-init-packages-p
(setq force-p t)) (setq force-p t))
(when (or force-p (not (bound-and-true-p package--initialized))) (when (or force-p (not (bound-and-true-p package--initialized)))
(doom-log "Initializing package.el") (doom-log "Initializing package.el")
(require 'package) (require 'package)
@ -198,63 +143,69 @@ necessary package metadata is initialized and available for them."
(when (or force-p (not doom-packages)) (when (or force-p (not doom-packages))
(doom-log "Initializing straight") (doom-log "Initializing straight")
(setq doom-init-packages-p t) (setq doom-init-packages-p t)
(unless (fboundp 'straight--reset-caches) (doom-ensure-straight)
(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))
(mapc #'straight-use-package doom-core-packages) (mapc #'straight-use-package doom-core-packages)
(doom-log "Initializing doom-packages") (doom-log "Initializing doom-packages")
(setq doom-disabled-packages nil (setq doom-disabled-packages nil
doom-pinned-packages nil
doom-packages (doom-package-list)) doom-packages (doom-package-list))
(cl-loop for (pkg . plist) in doom-packages (dolist (package doom-packages)
for ignored = (plist-get plist :ignore) (let ((name (car package)))
for disabled = (plist-get plist :disable) (with-plist! (cdr package) (recipe modules disable ignore pin)
if disabled (if ignore
do (cl-pushnew pkg doom-disabled-packages) (doom-log "Ignoring package %S" name)
else if (not ignored) (if (not disable)
do (with-demoted-errors "Package error: %s" (with-demoted-errors "Package error: %s"
(straight-register-package (when recipe
(if-let (recipe (plist-get plist :recipe)) (straight-override-recipe (cons name recipe)))
(let ((plist (straight-recipes-retrieve pkg))) (straight-register-package name))
`(,pkg ,@(doom-plist-merge recipe (cdr plist)))) (doom-log "Disabling package %S" name)
pkg)))) (cl-pushnew name doom-disabled-packages)
(unless doom-interactive-mode ;; Warn about disabled core packages
(add-hook 'kill-emacs-hook #'doom--finalize-straight)))) (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 () (defun doom-ensure-straight ()
"Ensure `straight' is installed and was compiled with this version of Emacs." "Ensure `straight' is installed and was compiled with this version of Emacs."
(defvar bootstrap-version) (unless (fboundp 'straight--reset-caches)
(let* (;; Force straight to install into ~/.emacs.d/.local/straight instead of (defvar bootstrap-version)
;; ~/.emacs.d/straight by pretending `doom-local-dir' is our .emacs.d. (let* (;; Force straight to install into ~/.emacs.d/.local/straight instead of
(user-emacs-directory straight-base-dir) ;; ~/.emacs.d/straight by pretending `doom-local-dir' is our .emacs.d.
(bootstrap-file (doom-path straight-base-dir "straight/repos/straight.el/straight.el")) (user-emacs-directory straight-base-dir)
(bootstrap-version 5)) (bootstrap-file (doom-path straight-base-dir "straight/repos/straight.el/straight.el"))
(make-directory (doom-path straight-base-dir "straight/build") 'parents) (bootstrap-version 5))
(unless (featurep 'straight) (make-directory (doom-path straight-base-dir "straight/build") 'parents)
(unless (or (require 'straight nil t) (or (require 'straight nil t)
(file-readable-p bootstrap-file)) (file-readable-p bootstrap-file)
(with-current-buffer (with-current-buffer
(url-retrieve-synchronously (url-retrieve-synchronously
(format "https://raw.githubusercontent.com/raxod502/straight.el/%s/install.el" (format "https://raw.githubusercontent.com/raxod502/straight.el/%s/install.el"
straight-repository-branch) straight-repository-branch)
'silent 'inhibit-cookies) 'silent 'inhibit-cookies)
(goto-char (point-max)) (goto-char (point-max))
(eval-print-last-sexp))) (eval-print-last-sexp)))
(load bootstrap-file nil t)))) (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 ;;; Module package macros
(cl-defmacro package! (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). "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 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: Accepts the following properties:
:recipe RECIPE :recipe RECIPE
Takes a MELPA-style recipe (see `quelpa-recipe' in `quelpa' for an example); Specifies a straight.el recipe to allow you to acquire packages from external
for packages to be installed from external sources. sources. See https://github.com/raxod502/straight.el#the-recipe-format for
details on this recipe.
:disable BOOL :disable BOOL
Do not install or update this package AND disable all of its `use-package!' Do not install or update this package AND disable all of its `use-package!'
blocks. and `after!' blocks.
:ignore FORM :ignore FORM
Do not install this package. Do not install this package.
:freeze FORM :pin STR|nil
Do not update this package if FORM is non-nil. Pin this package to commit hash STR. Setting this to nil will unpin this
:built-in BOOL package if previously pinned.
Same as :ignore if the package is a built-in Emacs package. If set to :built-in BOOL|'prefer
'prefer, will use built-in package if it is present. 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 Returns t if package is successfully registered, and nil if it was disabled
elsewhere." elsewhere."
(declare (indent defun)) (declare (indent defun))
(when (and recipe (keywordp (car-safe recipe))) (when (and recipe (keywordp (car-safe recipe)))
(plist-put! plist :recipe `(quote ,recipe))) (plist-put! plist :recipe `(quote ,recipe)))
;; :built-in t is basically an alias for :ignore (locate-library NAME)
(when built-in (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))) (setq built-in `(locate-library ,(symbol-name name) nil doom--initial-load-path)))
(plist-delete! plist :built-in) (plist-delete! plist :built-in)
(plist-put! plist :ignore built-in)) (plist-put! plist :ignore built-in))
`(let* ((name ',name) `(let* ((name ',name)
(plist (cdr (assq name doom-packages)))) (plist (cdr (assq name doom-packages))))
;; Record what module this declaration was found in
(let ((module-list (plist-get plist :modules)) (let ((module-list (plist-get plist :modules))
(module ',(doom-module-from-path))) (module ',(doom-module-from-path)))
(unless (member module module-list) (unless (member module module-list)
@ -298,27 +256,31 @@ elsewhere."
(append module-list (append module-list
(list module) (list module)
nil)))) nil))))
;; Merge given plist with pre-existing one
(doplist! ((prop val) (list ,@plist) plist) (doplist! ((prop val) (list ,@plist) plist)
(unless (null val) (unless (null val)
(plist-put! plist prop val))) (plist-put! plist prop val)))
;; Some basic key validation; error if you're not using a valid key ;; Some basic key validation; error if you're not using a valid key
(condition-case e (condition-case e
(cl-destructuring-bind (when-let (recipe (plist-get plist :recipe))
(&key _local-repo _files _flavor _no-build (cl-destructuring-bind
_type _repo _host _branch _remote _nonrecursive _fork _depth) (&key local-repo _files _flavor
(plist-get plist :recipe)) _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 (error
(signal 'doom-package-error (signal 'doom-package-error
(cons ,(symbol-name name) (cons ,(symbol-name name)
(error-message-string e))))) (error-message-string e)))))
;; This is the only side-effect of this macro!
(setf (alist-get name doom-packages) plist) (setf (alist-get name doom-packages) plist)
(if (not (plist-get plist :disable)) t (with-no-warnings
(doom-log "Disabling package %S" name) (not (plist-get plist :disable)))))
(cl-pushnew name doom-disabled-packages)
nil)))
(defmacro disable-packages! (&rest packages) (defmacro disable-packages! (&rest packages)
"A convenience macro for disabling packages in bulk. "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 (cl-loop for p in packages
collect `(package! ,p :disable t)))) 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) (provide 'core-packages)
;;; core-packages.el ends here ;;; core-packages.el ends here

View file

@ -31,15 +31,11 @@ Emacs.")
:init :init
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache") (setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
projectile-enable-caching doom-interactive-mode 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-files '(".DS_Store" "Icon " "TAGS")
projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o") projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o")
projectile-ignored-projects '("~/" "/tmp")
projectile-kill-buffers-filter 'kill-only-files projectile-kill-buffers-filter 'kill-only-files
projectile-files-cache-expire 604800 ; expire after a week projectile-known-projects-file (concat doom-cache-dir "projectile.projects")
projectile-sort-order 'recentf projectile-ignored-projects '("~/" "/tmp"))
projectile-use-git-grep t) ; use git-grep for text searches
(global-set-key [remap evil-jump-to-tag] #'projectile-find-tag) (global-set-key [remap evil-jump-to-tag] #'projectile-find-tag)
(global-set-key [remap find-tag] #'projectile-find-tag) (global-set-key [remap find-tag] #'projectile-find-tag)
@ -47,6 +43,21 @@ Emacs.")
:config :config
(projectile-mode +1) (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 ;; In the interest of performance, we reduce the number of project root marker
;; files/directories projectile searches for when resolving the project root. ;; files/directories projectile searches for when resolving the project root.
(setq projectile-project-root-files-bottom-up (setq projectile-project-root-files-bottom-up
@ -54,20 +65,14 @@ Emacs.")
".git") ; Git VCS root dir ".git") ; Git VCS root dir
(when (executable-find "hg") (when (executable-find "hg")
'(".hg")) ; Mercurial VCS root dir '(".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") (when (executable-find "bzr")
'(".bzr")) ; Bazaar VCS root dir '(".bzr"))) ; Bazaar VCS root dir
(when (executable-find "darcs")
'("_darcs"))) ; Darcs VCS root dir
;; This will be filled by other modules. We build this list manually so ;; 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 ;; projectile doesn't perform so many file checks every time it resolves
;; a project's root -- particularly when a file has no project. ;; a project's root -- particularly when a file has no project.
projectile-project-root-files '("TAGS") projectile-project-root-files '()
projectile-project-root-files-top-down-recurring '(".svn" "Makefile")) 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) (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 ;; 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 ;; that is significantly faster than git ls-files or find, and it respects
;; .gitignore. This is recommended in the projectile docs. ;; .gitignore. This is recommended in the projectile docs.
((executable-find doom-projectile-fd-binary) ((executable-find doom-projectile-fd-binary)
(setq projectile-git-command (concat (setq projectile-generic-command
doom-projectile-fd-binary (format "%s . --color=never --type f -0 -H -E .git"
" . --color=never --type f -0 -H -E .git") doom-projectile-fd-binary)
projectile-generic-command projectile-git-command projectile-git-command projectile-generic-command
projectile-git-submodule-command nil
;; ensure Windows users get fd's benefits ;; ensure Windows users get fd's benefits
projectile-indexing-method 'alien)) projectile-indexing-method 'alien))
@ -138,25 +144,16 @@ c) are not valid projectile projects."
(concat "rg -0 --files --color=never --hidden" (concat "rg -0 --files --color=never --hidden"
(cl-loop for dir in projectile-globally-ignored-directories (cl-loop for dir in projectile-globally-ignored-directories
concat (format " --glob '!%s'" dir))) concat (format " --glob '!%s'" dir)))
projectile-git-command projectile-generic-command
projectile-git-submodule-command nil
;; ensure Windows users get rg's benefits ;; ensure Windows users get rg's benefits
projectile-indexing-method 'alien) projectile-indexing-method 'alien))
;; fix breakage on windows in git projects
(unless (executable-find "tr")
(setq projectile-git-submodule-command nil)))
((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))) (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) (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 "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', 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 ;; Projectile root-searching functions can cause an infinite loop on TRAMP
;; connections, so disable them. ;; connections, so disable them.
;; TODO Is this still necessary? ;; 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." "Don't traverse the file system if on a remote connection."
:around #'projectile-locate-dominating-file :before-while #'projectile-locate-dominating-file
(when (and (stringp file) (and (stringp file)
(not (file-remote-p file nil t))) (not (file-remote-p file nil t)))))
(funcall orig-fn file name))))
;; ;;
@ -195,16 +191,15 @@ state are passed in.")
on-load on-load
on-enter on-enter
on-exit) on-exit)
"Define a project minor-mode named NAME (a symbol) and declare where and how "Define a project minor mode named NAME and where/how it is activated.
it is activated. Project modes allow you to configure 'sub-modes' for
major-modes that are specific to a folder, project structure, framework or Project modes allow you to configure 'sub-modes' for major-modes that are
whatever arbitrary context you define. These project modes can have their own specific to a folder, project structure, framework or whatever arbitrary context
settings, keymaps, hooks, snippets, etc. you define. These project modes can have their own settings, keymaps, hooks,
snippets, etc.
This creates NAME-hook and NAME-map as well. 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 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. 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 (setq hscroll-margin 2
hscroll-step 1 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-margin 0
scroll-preserve-screen-position t scroll-preserve-screen-position t
;; Reduce cursor lag by a tiny bit by not auto-adjusting `window-vscroll' ;; 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) (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. "Switch to `doom-fallback-buffer' if on last real buffer.
Advice for `kill-current-buffer'. If in a dedicated window, delete it. If there 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 are no real buffers left OR if all remaining buffers are visible in other
windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
`kill-current-buffer'." `kill-current-buffer'."
:around #'kill-current-buffer :before-until #'kill-current-buffer
(let ((buf (current-buffer))) (let ((buf (current-buffer)))
(cond ((window-dedicated-p) (cond ((window-dedicated-p)
(delete-window)) (delete-window)
t)
((eq buf (doom-fallback-buffer)) ((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) ((doom-real-buffer-p buf)
(if (and buffer-file-name (if (and buffer-file-name
(buffer-modified-p buf) (buffer-modified-p buf)
@ -247,8 +254,8 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
(switch-to-buffer (doom-fallback-buffer))) (switch-to-buffer (doom-fallback-buffer)))
(unless (delq (selected-window) (get-buffer-window-list buf nil t)) (unless (delq (selected-window) (get-buffer-window-list buf nil t))
(kill-buffer buf))) (kill-buffer buf)))
(run-hooks 'buffer-list-update-hook))) (run-hooks 'buffer-list-update-hook))
((funcall orig-fn))))) t))))
;; ;;
@ -270,40 +277,46 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
(setq frame-title-format '("%b Doom Emacs") (setq frame-title-format '("%b Doom Emacs")
icon-title-format frame-title-format) 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 (setq window-resize-pixelwise t
frame-resize-pixelwise t) frame-resize-pixelwise t)
(unless EMACS27+ ; We already do this in early-init.el (unless (assq 'menu-bar-lines default-frame-alist)
;; Disable tool and scrollbars; Doom encourages keyboard-centric workflows, so ;; We do this in early-init.el too, but in case the user is on Emacs 26 we do
;; these are just clutter (the scrollbar also impacts Emacs' performance). ;; it here too: disable tool and scrollbars, as Doom encourages
(push '(menu-bar-lines . 0) default-frame-alist) ;; keyboard-centric workflows, so these are just clutter (the scrollbar also
(push '(tool-bar-lines . 0) default-frame-alist) ;; impacts performance).
(push '(vertical-scroll-bars) default-frame-alist)) (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 (when IS-MAC
;; Curse Lion and its sudden but inevitable fullscreen mode! ;; Curse Lion and its sudden but inevitable fullscreen mode!
;; NOTE Meaningless to railwaycat's emacs-mac build ;; NOTE Meaningless to railwaycat's emacs-mac build
(setq ns-use-native-fullscreen nil (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)
;; Sets ns-transparent-titlebar and ns-appearance frame parameters as is ;; Visit files opened outside of Emacs in existing frame, not a new one
;; appropriate for the loaded theme. (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) (and (or (daemonp)
(display-graphic-p)) (display-graphic-p))
(require 'ns-auto-titlebar nil t) (require 'ns-auto-titlebar nil t)
(ns-auto-titlebar-mode +1)) (ns-auto-titlebar-mode +1))
(add-hook! 'after-make-frame-functions ;; HACK On MacOS, disabling the menu bar makes MacOS treat Emacs as a
(defun doom-init-menu-bar-in-gui-frames-h (frame) ;; non-application window -- which means it doesn't automatically capture
"On MacOS, the menu bar isn't part of the frame. Disabling it makes MacOS ;; focus when it is started, among other things. We enable menu-bar-lines
treat Emacs as a non-application window." ;; there, but we still want it disabled in terminal frames because there
(when (display-graphic-p frame) ;; it activates an ugly menu bar.
(set-frame-parameter frame 'menu-bar-lines 1))))) (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, ;; The native border "consumes" a pixel of the fringe on righter-most splits,
;; `window-divider' does not. Available since Emacs 25.1. ;; `window-divider' does not. Available since Emacs 25.1.
@ -317,13 +330,15 @@ treat Emacs as a non-application window."
;; always avoid GUI ;; always avoid GUI
(setq use-dialog-box nil) (setq use-dialog-box nil)
;; Don't display floating tooltips; display their contents in the echo-area. ;; Don't display floating tooltips; display their contents in the echo-area,
(if (bound-and-true-p tooltip-mode) (tooltip-mode -1)) ;; because native tooltips are ugly.
;; native linux tooltips are ugly (when (bound-and-true-p tooltip-mode)
(tooltip-mode -1))
;; ...especially on linux
(when IS-LINUX (when IS-LINUX
(setq x-gtk-use-system-tooltips nil)) (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 (setq split-width-threshold 160
split-height-threshold nil) split-height-threshold nil)
@ -332,7 +347,7 @@ treat Emacs as a non-application window."
;;; Minibuffer ;;; Minibuffer
;; Allow for minibuffer-ception. Sometimes we need another minibuffer command ;; 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) (setq enable-recursive-minibuffers t)
;; Show current key-sequence in minibuffer, like vim does. Any feedback after ;; 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 ;; But don't let the minibuffer grow beyond this size
max-mini-window-height 0.15) 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 ;; Typing yes/no is obnoxious when y/n will do
(fset #'yes-or-no-p #'y-or-n-p) (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 (setq hl-line-sticky-flag nil
global-hl-line-sticky-flag nil) global-hl-line-sticky-flag nil)
;; Disable `hl-line' in evil-visual mode (temporarily). `hl-line' can make the ;; Temporarily disable `hl-line' when selection is active, since it doesn't
;; selection region harder to see while in evil visual mode. ;; serve much purpose when the selection is so much more visible.
(after! evil (defvar doom-buffer-hl-line-mode nil)
(defvar doom-buffer-hl-line-mode nil)
(add-hook! 'evil-visual-state-entry-hook (add-hook! '(evil-visual-state-entry-hook activate-mark-hook)
(defun doom-disable-hl-line-h () (defun doom-disable-hl-line-h ()
(when hl-line-mode (when hl-line-mode
(setq-local doom-buffer-hl-line-mode t) (setq-local doom-buffer-hl-line-mode t)
(hl-line-mode -1)))) (hl-line-mode -1))))
(add-hook! 'evil-visual-state-exit-hook
(defun doom-enable-hl-line-maybe-h () (add-hook! '(evil-visual-state-exit-hook deactivate-mark-hook)
(when doom-buffer-hl-line-mode (defun doom-enable-hl-line-maybe-h ()
(hl-line-mode +1)))))) (when doom-buffer-hl-line-mode
(hl-line-mode +1)))))
(use-package! winner (use-package! winner
@ -464,15 +475,23 @@ treat Emacs as a non-application window."
all-the-icons-wicon all-the-icons-wicon
all-the-icons-material all-the-icons-material
all-the-icons-alltheicon) all-the-icons-alltheicon)
:init :config
(defadvice! doom--disable-all-the-icons-in-tty-a (orig-fn &rest args) (cond ((daemonp)
"Return a blank string in tty Emacs, which doesn't support multiple fonts." (defadvice! doom--disable-all-the-icons-in-tty-a (orig-fn &rest args)
:around '(all-the-icons-octicon all-the-icons-material "Return a blank string in tty Emacs, which doesn't support multiple fonts."
all-the-icons-faicon all-the-icons-fileicon :around '(all-the-icons-octicon all-the-icons-material
all-the-icons-wicon all-the-icons-alltheicon) all-the-icons-faicon all-the-icons-fileicon
(if (display-multi-font-p) all-the-icons-wicon all-the-icons-alltheicon)
(apply orig-fn args) (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 ;;;###package hide-mode-line-mode
(add-hook! '(completion-list-mode-hook Man-mode-hook) (add-hook! '(completion-list-mode-hook Man-mode-hook)
@ -499,15 +518,19 @@ treat Emacs as a non-application window."
;; ;;
;;; Line numbers ;;; Line numbers
;; Explicitly define a width to reduce computation
(setq-default display-line-numbers-width 3) (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) (add-hook! '(prog-mode-hook text-mode-hook conf-mode-hook)
#'display-line-numbers-mode) #'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 ;;; 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 () (defun doom-init-fonts-h ()
"Loads `doom-font'." "Loads `doom-font'."
(cond (doom-font (cond
(cl-pushnew (doom-font
(cons 'font (cl-pushnew
(cond ((stringp doom-font) doom-font) ;; Avoiding `set-frame-font' because it does a lot of extra, expensive
((fontp doom-font) (font-xlfd-name doom-font)) ;; work we can avoid by setting the font frame parameter instead.
((signal 'wrong-type-argument (list '(fontp stringp) (cons 'font
doom-font))))) (cond ((stringp doom-font) doom-font)
default-frame-alist ((fontp doom-font) (font-xlfd-name doom-font))
:key #'car :test #'eq)) ((signal 'wrong-type-argument (list '(fontp stringp)
((display-graphic-p) doom-font)))))
(setq doom-font (face-attribute 'default :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) (defun doom-init-extra-fonts-h (&optional frame)
"Loads `doom-variable-pitch-font',`doom-serif-font' and `doom-unicode-font'." "Loads `doom-variable-pitch-font',`doom-serif-font' and `doom-unicode-font'."
(condition-case e (condition-case e
(with-selected-frame (or frame (selected-frame)) (with-selected-frame (or frame (selected-frame))
(when doom-font
(set-face-attribute 'fixed-pitch nil :font doom-font))
(when doom-serif-font (when doom-serif-font
(set-face-attribute 'fixed-pitch-serif nil :font doom-serif-font)) (set-face-attribute 'fixed-pitch-serif nil :font doom-serif-font))
(when doom-variable-pitch-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 ;;; 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) (unless (fboundp 'define-fringe-bitmap)
(fset 'define-fringe-bitmap #'ignore)) (fset 'define-fringe-bitmap #'ignore))

View file

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

View file

@ -2,39 +2,46 @@
;;; core/packages.el ;;; core/packages.el
;; core.el ;; core.el
(package! dotenv-mode) (package! auto-minor-mode :pin "17cfa1b548")
(package! auto-minor-mode) (package! gcmh :pin "8867533a73")
;; core-ui.el ;; core-ui.el
(package! all-the-icons) (package! all-the-icons :pin "1416f37984")
(package! hide-mode-line) (package! hide-mode-line :pin "88888825b5")
(package! highlight-numbers) (package! highlight-numbers :pin "8b4744c7f4")
(package! rainbow-delimiters) (package! rainbow-delimiters :pin "5125f4e476")
(package! restart-emacs) (package! restart-emacs :pin "9aa90d3df9")
;; core-editor.el ;; core-editor.el
(package! better-jumper) (package! better-jumper :pin "6d240032ca")
(package! dtrt-indent) (package! dtrt-indent :pin "48221c928b")
(package! helpful) (package! helpful :pin "c54e9ddbd6")
(package! ns-auto-titlebar :ignore (not IS-MAC)) (when IS-MAC
(package! pcre2el) (package! ns-auto-titlebar :pin "1efc30d385"))
(package! smartparens) (package! pcre2el :pin "0b5b2a2c17")
(package! smartparens :pin "be8d5c9a63")
(package! so-long (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 ;; 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 ;; I've created my own mirror for it because git.savannah.gnu.org runs
;; potato. ;; on a potato.
:recipe (:host github :repo "hlissner/emacs-so-long")) :recipe (:host github :repo "hlissner/emacs-so-long")
(package! undo-tree :pin "ed666b0716")
;; Version 0.6.5 is on ELPA which lacks a fix we need, so we install 0.6.6 (package! undo-tree :pin "5b6df03781")
;; from emacsmirror/undo-tree instead. (package! ws-butler
:recipe (:host github :repo "emacsmirror/undo-tree")) ;; Use my fork of ws-butler, which has a few choice improvements and
(package! ws-butler) ;; optimizations (the original has been abandoned).
(package! xclip) :recipe (:host github :repo "hlissner/ws-butler")
:pin "e4430d3778")
(unless IS-WINDOWS
(package! xclip :pin "d022cf947d"))
;; core-projects.el ;; core-projects.el
(package! projectile) (package! projectile :pin "341150c0e7")
;; core-keybinds.el ;; core-keybinds.el
(package! general) (package! general :pin "f6e928622d")
(package! which-key) (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. give you clues about what is wrong.
3. Use `bin/doom upgrade` to update Doom. Doing it any other way may require 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 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). 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 (eval-and-compile
(setq doom-interactive-mode 'test) (setq doom-interactive-mode 'test)
(doom-initialize 'force) (doom-initialize 'force 'noerror)
(require 'buttercup) (require 'buttercup)
(setq split-width-threshold 0 (setq split-width-threshold 0
split-height-threshold 0 split-height-threshold 0

View file

@ -101,12 +101,6 @@
(expect (appendq! list '(d e f)) (expect (appendq! list '(d e f))
:to-equal '(a b c 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!" (describe "delq!"
(it "delete's a symbol from a list" (it "delete's a symbol from a list"
(let ((list '(a b c))) (let ((list '(a b c)))

View file

@ -13,15 +13,15 @@
(setq doom-init-p nil)) (setq doom-init-p nil))
(it "initializes once" (it "initializes once"
(expect (doom-initialize)) (expect (doom-initialize nil 'noerror))
(expect (not (doom-initialize))) (expect (not (doom-initialize nil 'noerror)))
(expect (not (doom-initialize))) (expect (not (doom-initialize nil 'noerror)))
(expect doom-init-p)) (expect doom-init-p))
(it "initializes multiple times, if forced" (it "initializes multiple times, if forced"
(expect (doom-initialize)) (expect (doom-initialize nil 'noerror))
(expect (not (doom-initialize))) (expect (not (doom-initialize nil 'noerror)))
(expect (doom-initialize 'force))) (expect (doom-initialize 'force 'noerror)))
(describe "package initialization" (describe "package initialization"
(before-each (before-each
@ -29,18 +29,18 @@
(it "initializes packages if core autoload file doesn't exist" (it "initializes packages if core autoload file doesn't exist"
(let ((doom-autoload-file "doesnotexist")) (let ((doom-autoload-file "doesnotexist"))
(doom-initialize)) (expect (doom-initialize nil 'noerror))
(expect 'doom-initialize-packages :to-have-been-called)) (expect 'doom-initialize-packages :to-have-been-called))
(it "doesn't initialize packages if core autoload file was loaded" (it "doesn't initialize packages if core autoload file was loaded"
(let ((doom-interactive-mode t)) (let ((doom-interactive-mode t))
(spy-on 'doom-load-autoloads-file :and-return-value 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-load-autoloads-file :to-have-been-called-with doom-package-autoload-file)
(expect 'doom-initialize-packages :to-have-been-called))) (expect 'doom-initialize-packages :to-have-been-called)))
(it "initializes packages when forced" (it "initializes packages when forced"
(doom-initialize 'force) (doom-initialize 'force 'noerror)
(expect 'doom-initialize-packages :to-have-been-called))) (expect 'doom-initialize-packages :to-have-been-called)))
(describe "autoloads files" (describe "autoloads files"
@ -49,15 +49,14 @@
(spy-on 'warn :and-return-value t)) (spy-on 'warn :and-return-value t))
(it "loads autoloads files" (it "loads autoloads files"
(ignore-errors (doom-initialize)) (ignore-errors (doom-initialize nil 'noerror))
(expect 'doom-load-autoloads-file (expect 'doom-load-autoloads-file
:to-have-been-called-with doom-autoload-file) :to-have-been-called-with doom-autoload-file)
(expect 'doom-load-autoloads-file (expect 'doom-load-autoloads-file
:to-have-been-called-with doom-package-autoload-file)) :to-have-been-called-with doom-package-autoload-file))
(it "throws doom-autoload-error in interactive session where autoload files don't exist" (it "throws doom-autoload-error when autoload files don't exist"
(let ((doom-interactive-mode t) (let ((doom-autoload-file "doesnotexist")
(doom-autoload-file "doesnotexist")
(doom-package-autoload-file "doesnotexist")) (doom-package-autoload-file "doesnotexist"))
(expect (doom-initialize) :to-throw 'doom-autoload-error))))) (expect (doom-initialize) :to-throw 'doom-autoload-error)))))
@ -117,7 +116,7 @@
(it "returns the new value for `process-environment'" (it "returns the new value for `process-environment'"
(expect (doom-load-envvars-file doom-env-file) (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" (it "alters environment variables"
(dolist (key '("A" "B" "C")) (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. It is integrated into Helpful, in Doom.
* Table of Contents :TOC_3: * 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]] - [[#core-lib][core-lib]]
- [[#add-hook][add-hook!]] - [[#add-hook][add-hook!]]
- [[#add-transient-hook][add-transient-hook!]] - [[#add-transient-hook][add-transient-hook!]]
- [[#after][after!]] - [[#after][after!]]
- [[#appendq][appendq!]]
- [[#custom-set-faces][custom-set-faces!]] - [[#custom-set-faces][custom-set-faces!]]
- [[#custom-theme-set-faces][custom-theme-set-faces!]] - [[#custom-theme-set-faces][custom-theme-set-faces!]]
- [[#defer-feature][defer-feature!]] - [[#defer-feature][defer-feature!]]
@ -19,21 +20,24 @@ It is integrated into Helpful, in Doom.
- [[#file-exists-p][file-exists-p!]] - [[#file-exists-p][file-exists-p!]]
- [[#lambda][lambda!]] - [[#lambda][lambda!]]
- [[#lambda-1][lambda!!]] - [[#lambda-1][lambda!!]]
- [[#letenv][letenv!]]
- [[#load][load!]] - [[#load][load!]]
- [[#map][map!]] - [[#map][map!]]
- [[#package][package!]] - [[#package][package!]]
- [[#pushnew][pushnew!]] - [[#pushnew][pushnew!]]
- [[#prependq][prependq!]]
- [[#quiet][quiet!]] - [[#quiet][quiet!]]
- [[#remove-hook][remove-hook!]] - [[#remove-hook][remove-hook!]]
- [[#setq][setq!]]
- [[#setq-hook][setq-hook!]] - [[#setq-hook][setq-hook!]]
- [[#unsetq-hook][unsetq-hook!]] - [[#unsetq-hook][unsetq-hook!]]
- [[#use-package][use-package!]] - [[#use-package][use-package!]]
- [[#interesting-snippets][Interesting snippets]] - [[#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]] - [[#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]] - [[#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 ** core-lib
*** add-hook! *** add-hook!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
@ -90,6 +94,26 @@ It is integrated into Helpful, in Doom.
(after! rustic ...) (after! rustic ...)
(after! python ...) (after! python ...)
#+END_SRC #+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! *** custom-set-faces!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
@ -214,8 +238,47 @@ It is integrated into Helpful, in Doom.
#+RESULTS: #+RESULTS:
: /home/hlissner/.emacs.d/LICENSE : /home/hlissner/.emacs.d/LICENSE
*** TODO lambda! *** lambda!
*** TODO 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! *** load!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
;;; Lets say we're in ~/.doom.d/config.el ;;; 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) (map! :map lua-mode-map "SPC m b" nil)
;; bind multiple keys ;; bind multiple keys
(global-set-key "C-x x" #'do-something) (global-set-key (kbd "C-x x") #'do-something)
(global-set-key "C-x y" #'do-something-else) (global-set-key (kbd "C-x y") #'do-something-else)
(global-set-key "C-x z" #'do-another-thing) (global-set-key (kbd "C-x z") #'do-another-thing)
(map! "C-x x" #'do-something (map! "C-x x" #'do-something
"C-x y" #'do-something-else "C-x y" #'do-something-else
"C-x z" #'do-another-thing) "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! *** package!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
;; To install a package that can be found on ELPA or any of the sources ;; 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! evil)
(package! js2-mode) (package! js2-mode)
(package! rainbow-delimiters) (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: ;; you can tell the package manager not to clone the repo recursively:
(package! ansible :recipe (:nonrecursive t)) (package! ansible :recipe (:nonrecursive t))
;; To install a particular branch, commit or tag: ;; To pin a package to a specific commit:
(package! evil (package! evil :pin "e7bc39de2f9")
;; if :host and :fetcher aren't specified, the package manager will fall back ;; ...or branch:
;; to evil's default source provided by their (M)ELPA recipes:
:recipe (:commit "e7bc39de2f961505e8e112da8c1b315ae8afce52"))
(package! evil :recipe (:branch "stable")) (package! evil :recipe (:branch "stable"))
;; To unpin a pinned package:
(package! evil :recipe (:tag "1.2.9")) (package! evil :pin nil)
;; If you share your config between two computers, and don't want bin/doom ;; 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 ;; refresh to delete packages used only on one system, use :ignore
(package! evil :ignore (not (equal system-name "my-desktop"))) (package! evil :ignore (not (equal system-name "my-desktop")))
#+END_SRC #+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! *** quiet!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
;; Enters recentf-mode without extra output ;; 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) ;; Removing arbitrary forms (must be exactly the same as the definition)
(remove-hook! (one-mode second-mode) (setq v 5) (setq a 2)) (remove-hook! (one-mode second-mode) (setq v 5) (setq a 2))
#+END_SRC #+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! *** setq-hook!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
;; Set multiple variables after a hook ;; 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) :defer-incrementally t)
#+END_SRC #+END_SRC
* Interesting snippets * Interesting snippets
** Persist Emacs' initial frame size across sessions ** Center Emacs' initial frame with a fixed size
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(let ((display-height (display-pixel-height)) (let ((display-height (display-pixel-height))
(display-width (display-pixel-width))) (display-width (display-pixel-width)))
(add-to-list 'initial-frame-alist (pushnew! initial-frame-alist
`((left . ,(/ new-frame-width 2)) `(left . ,(/ display-width 2))
(top . ,(/ new-frame-height 2)) `(top . ,(/ display-height 2))
(width . ,(/ display-width 2)) `(width . ,display-width)
(height . ,(/ display-height 2))))) `(height . ,display-height)))
#+END_SRC #+END_SRC
** Persist Emacs' initial frame position, dimensions and/or full-screen state across sessions ** Persist Emacs' initial frame position, dimensions and/or full-screen state across sessions

View file

@ -1,14 +1,14 @@
#+TITLE: Contributing #+TITLE: Contributing
#+STARTUP: nofold #+STARTUP: nofold
I can't say Doom Emacs is a one man show anymore. It wouldn't have gotten this Doom Emacs is an active and ongoing project, maintained mostly by a single
far without the help of folks like you! Still, I struggle to maintain it all; person, but includes the efforts of 200 contributors and growing. There is no
especially the modules I do not use. If Doom has been useful to you, consider shortage of things that need doing; bugs that need stomping, features that need
pitching in and helping me out. 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 You are welcome to [[https://discord.gg/qvGgnVx][join us on our Discord server]], otherwise read on to learn how
documentation, or just spreading the good word. To ensure no toes get stepped on to contribute to our fine corner of the interwebs.
or wires crossed, this guide was created to help you help us.
* Table of Contents :TOC_3: * Table of Contents :TOC_3:
- [[#where-can-i-help][Where can I help?]] - [[#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-documentation][Contributing documentation]]
- [[#contributing-to-dooms-manual][Contributing to Doom's manual]] - [[#contributing-to-dooms-manual][Contributing to Doom's manual]]
- [[#contributing-module-documentation][Contributing module documentation]] - [[#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]] - [[#other-ways-to-support-doom-emacs][Other ways to support Doom Emacs]]
- [[#special-thanks][Special thanks]] - [[#special-thanks][Special thanks]]
* Where can I help? * 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, + 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 + 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. 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) + 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. 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]]. + 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 + 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. redirect your efforts.
+ The [[https://github.com/hlissner/doom-emacs/projects/2][plugins under review board]] lists third party plugins being considered (or + 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 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. cause) perhaps you can address them at the source.
* TODO Reporting issues * TODO Reporting issues
So you've found a problem. Before you fire off that bug report, there are a few You've found a problem and you're ready to fire off that bug report. Hold up!
things you should try first: 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 An effective bug report is informative. Please try to provide:
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.
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]]. + A backtrace of all mentioned errors.
Please make sure of the following before you submit: + 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 ** 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 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 Other ways to support Doom Emacs
* TODO Special thanks * TODO Special thanks

View file

@ -20,11 +20,6 @@
- [[#should-i-fork-doom-to-customize-it][Should I fork Doom to customize it?]] - [[#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-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-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-theme][How do I change the theme?]]
- [[#how-do-i-change-the-fonts][How do I change the fonts?]] - [[#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)?]] - [[#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-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-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-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-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?]] - [[#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~?]] - [[#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-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]] - [[#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]] - [[#defaults][Defaults]]
- [[#why-ivy-over-helm][Why Ivy over Helm?]] - [[#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)?]] - [[#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]] - [[#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]] - [[#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...]] - [[#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]] - [[#contributing][Contributing]]
* General * General
** Why is it called Doom? ** Why is it called Doom?
An homage to idsoftware's classic game, whose open sourced code was my first It's an homage to idsoftware's classic game, whose open sourced code was
exposure to programming. Henrik's (Doom's maintainer) first exposure to programming.
Also, if you're obsessed enough with a text editor that you write a community And if you're obsessed enough with a text editor that you write a community
config for it, you're doomed from the get go. config for it, you're doomed from the start.
** Does Doom work on Windows? ** Does Doom work on Windows?
Windows support is weak and will generally lag behind Linux/MacOS support, so Windows support is weak and generally lags behind Linux/MacOS support, so your
your mileage will vary. However, many have reported success installing Doom mileage will vary. However, some have reported success using Doom Emacs on
Emacs on Windows (using WSL, WSL2 or scope/chocolatey). You'll find install Windows (using WSL, WSL2 or scoop/chocolatey). You'll find install instructions
instructions for Windows in the [[file:getting_started.org::On Windows][Getting Starting guide]]. 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? ** Is Doom only for vimmers?
Henrik is a dyed-in-the-wool vimmer with more than a decade of vim muscle No, but it is Doom's primary audience. Its maintainer is a dyed-in-the-wool
memory. Vim's is the only paradigm he truly knows, so vimmers will always be his vimmer with almost two decades of vim muscle memory, and he came to Emacs to
primary audience. find a better vim.
That's not to say Doom won't work without evil, only that it is less polished in Although Doom is less polished without evil, its growing non-evil user base is
that respect. Our growing non-evil userbase are slowly improving the situation slowly improving the situation. We welcome suggestions and PRs to help
however. We welcome suggestions and PRs to help accommodate a non-evil workflow. 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. [[file:../modules/editor/evil/README.org][:editor evil]] module's documentation.
** I am a beginner. Can I use Doom? ** 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. you into Doom.
+ *Doom manages its packages outside of Emacs.* Spacemacs installs (and checks + *Doom manages its packages outside of Emacs.* Spacemacs installs (and checks
for packages) on startup or on demand. Doom leaves package management to be for packages) on startup or on demand. Doom leaves package management to be
done externally, through the ~bin/doom~ script. This allows package management done externally, through the ~bin/doom~ script. This allows for package
can be scripted on the command line and enables a number of startup management to be scripted on the command line and enables a number of startup
optimizations we wouldn't have otherwise. optimizations we wouldn't have otherwise.
** Why such a complicated package management system? ** 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 1. *Scriptability:* package management should be shell-scriptable, so updating
can be automated. 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 are out-of-date through official channels, have changed hands, have a
superior fork, or aren't available in ELPA repos. superior fork, or aren't available in ELPA repos.
3. *Performance:* lazy-loading the package management system is a tremendous 3. *Performance:* lazy-loading the package management system is a tremendous
boon to start up speed. Initializing package.el and quelpa (and/or checking boon to start up speed. Initializing package.el and straight (and/or checking
that your packages are installed) every time you start up is expensive. that your packages are installed) each time you start up is expensive.
4. *Organization:* an Emacs configuration grows so quickly, in complexity and 4. *Organization:* an Emacs configuration grows so quickly, in complexity and
size. A clear separation of concerns (configuration of packages from their size. A clear separation of concerns (configuration of packages from their
installation) is more organized. installation) is more organized.
5. *Reproducibility:* /This goal hasn't been implemented yet/, but all our work 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 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 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. reproducible.
** How does Doom start up so quickly? ** 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 ... ;; ... your emacs config here ...
#+END_SRC #+END_SRC
However, it is important to reset it eventually (as late as possible). Not doing However, it is important to reset it eventually. Not doing so will cause garbage
so will cause garbage collection freezes during long-term interactive use. collection freezes during long-term interactive use. Conversely, a
Conversely, a ~gc-cons-threshold~ that is too small will cause stuttering. We ~gc-cons-threshold~ that is too small will cause stuttering. We use 16mb as our
use 16mb as our default. default.
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(add-hook 'emacs-startup-hook (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) (add-hook 'minibuffer-exit-hook #'doom-restore-garbage-collection-h)
#+END_SRC #+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 *** Unset ~file-name-handler-alist~ temporarily
Emacs consults this variable every time a file is read or library loaded, or 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 when certain functions in the file API are used (like ~expand-file-name~ or
~file-truename~). ~file-truename~).
They do so to check if a special handler is needed to read it, but none of these Emacs does to check if a special handler is needed to read that file, but none
handlers are necessary for the initialization work we do at startup, so it is of them are (typically) necessary at startup, so we disable them (temporarily!):
generally safe to disable it (temporarily!):
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(defvar doom--file-name-handler-alist file-name-handler-alist) (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))) (setq file-name-handler-alist doom--file-name-handler-alist)))
#+END_SRC #+END_SRC
It is important to restore this variable, otherwise you won't be able to use Don't forget to restore ~file-name-handler-alist~, otherwise TRAMP won't work
TRAMP and Emacs will be unable to read compressed/encrypted files. and compressed/encrypted files won't open.
*** 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).
*** Concatenate package autoloads *** Concatenate package autoloads
When you install a package, a PACKAGE-autoloads.el file is generated. This file 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 contains a map of autoloaded functions and snippets declared by the package.
(that's what those ~;;;###autoload~ comments are for in packages). They tell They tell Emacs where to find them when they are eventually called. In your
Emacs where to find them, when they are eventually called. In your conventional conventional Emacs config, every one of these autoloads files are loaded
Emacs config, every single one of these autoloads files are loaded immediately immediately at startup (when ~package-initialize~ is called).
at startup.
Since you'll commonly have hundreds of packages, loading hundreds of autoloads 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 file can hurt startup times, especially without an SSD. We get around this by
files into one giant one (in =~/.emacs.d/.local/autoloads.pkg.el=) when you run concatenating these files into one giant one when you run ~doom sync~.
~doom refresh~.
Emacs 27+ will introduce a ~package-quickstart~ feature that will do this for Emacs 27+ introduces a ~package-quickstart~ command does this for you, and
you -- the =straight= package manager does this for you too -- but Doom Emacs =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
has its own specialized mechanism for doing this, and has tacked a number of own specialized mechanism]] for this, topped off with a few Doom-specific
Doom-specific optimizations on top of it. optimizations.
*** Lazy load package management system(s) *** Lazy load package management system(s)
Initializing package.el or straight.el at startup is expensive. We can save some 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 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 load them only when we're doing package management, e.g. when we run ~doom
~doom refresh~). 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~, autoloads files; caches expensive variables like caches ~load-path~,
~Info-directory-list~ and ~auto-mode-alist~; and preforms all your package ~Info-directory-list~ and ~auto-mode-alist~; and preforms all your package
management activities there -- far away from your interactive sessions. management activities there -- far away from your interactive sessions.
How exactly Doom accomplishes all this is a little complex, so instead, here is How exactly Doom accomplishes all this is a long story, so here is a boiled-down
a boiled-down version you can use in your own configs (for package.el, not version you can use in your own configs (for package.el, not straight.el):
straight.el):
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(defvar cache-file "~/.emacs.d/cache/autoloads") (defvar cache-file "~/.emacs.d/cache/autoloads")
@ -273,26 +260,12 @@ straight.el):
(package-initialize) (package-initialize)
(with-temp-buffer (with-temp-buffer
(cl-pushnew doom-core-dir load-path :test #'string=) (cl-pushnew doom-core-dir load-path :test #'string=)
(dolist (spec package-alist) (dolist (desc (delq nil (mapcar #'cdr package-alist)))
(when-let (desc (cdr spec)) (let ((load-file-name (concat (package--autoloads-file-name desc) ".el")))
(let ((file (concat (package--autoloads-file-name desc) ".el"))) (when (file-readable-p load-file-name)
(when (file-readable-p file) (condition-case _
;; Ensure that the contents of this autoloads file believes they (while t (insert (read (current-buffer))))
;; haven't been moved: (end-of-file)))))
(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")))))
(prin1 `(setq load-path ',load-path (prin1 `(setq load-path ',load-path
auto-mode-alist ',auto-mode-alist auto-mode-alist ',auto-mode-alist
Info-directory-list ',Info-directory-list) Info-directory-list ',Info-directory-list)
@ -304,10 +277,9 @@ straight.el):
#+END_SRC #+END_SRC
You'll need to delete ~cache-files~ any time you install, remove, or update a 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 new package. You could advise ~package-install~ and ~package-delete~ to call
~package-delete~ to call ~initialize~ when they succeed. Or, you could make ~initialize~ when they succeed, or make ~initialize~ interactive and call it
~initialize~ interactive and call it manually when you determine it's necessary. manually when necessary. Up to you!
Up to you!
Note: package.el is sneaky, and will initialize itself if you're not careful. Note: package.el is sneaky, and will initialize itself if you're not careful.
*Not on my watch, criminal scum!* *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 *** Lazy load more than everything
~use-package~ can defer your packages. Using it is a no-brainer, but Doom goes a ~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 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 + 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 + 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)). 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 + The =evil-easymotion= package binds many keys, none of which are available
package for them to all take effect, so instead, =gs= is bound to a command until you load the package. Instead of loading it at startup, =gs= is bound to
that loads the package and then invisibly populates =gs=, then simulates the a command that loads the package, populates =gs=, then simulates the =gs= key
=gs= keypress as though those new keys had always been there. press as though those new keys had always been there.
+ A number of packages are "incrementally" loaded. This is a Doom feature where, + Doom loads some packages "incrementally". i.e. after a few seconds of idle
after a few seconds of idle time post-startup, Doom will load packages time post-startup, Doom loads packages piecemeal (one dependency at a time)
piecemeal while Emacs. It will quickly abort if it detects input, as to make while Emacs. It aborts if it detects input, as to make the process as subtle
the process as subtle as possible. as possible.
For example, instead of loading =org= (a giant package), it will load these For example, instead of loading =org= (a giant package), it will load these
dependencies, one at a time, before finally loading =org=: 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 This ensures packages load as quickly as possible when you first load an org
file. 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 *** 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 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 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."]] + [[http://nullprogram.com/blog/2016/12/22/]["Some Performance Advantages of Lexical Scope."]]
** Why is startup time important? Why not use the daemon? ** 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 The central motivation 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 experience) was to have a viable alternative to vim for quick, one-shot editing
editing in the terminal (without ~-Q~). This also facilitates: in the terminal (without ~-Q~).
- Running multiple, independent instances of Emacs (e.g. on a per-project basis, or Besides that, it happens to facilitate:
for nix-shell users, or to isolate one instance for IRC from an instance for
writing code, etc). - 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 - Quicker restarting of Emacs, to reload package settings or recover from
disastrous errors which can leave Emacs in a broken state. 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 - 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 What's more, I believe a daemon shouldn't be necessary to get a sane startup
second program just to make the first run comfortably. time out of Emacs.
** How do I use Doom alongside other Emacs configs? ** 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 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]]. 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 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 =~/.config/doom= by default), but the =--doomdir PATH= switch (or ~DOOMDIR~
variable) will allow you to use a different location: environment variable) will allow you to use a different location:
#+BEGIN_SRC bash #+BEGIN_SRC bash
# First install Doom somewhere # 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 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 =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 you ~doom!~ block, which should have been created in your =init.el= when you
first ran ~doom install~. 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. 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? ** How do I enable or disable a Doom module?
You'll find your ~doom!~ block in =~/.doom.d/init.el=. This block contains a Comment or uncomment the module in your ~doom!~ block, found in
list of modules you want enabled and what order to load them in. Disable modules =$DOOMDIR/init.el=.
by commenting them out with semicolons. To enable them, remove those leading
semicolons:
#+BEGIN_SRC emacs-lisp Remember to run ~bin/doom sync~ afterwards, on the command line, to sync your
(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
module list with Doom. module list with Doom.
You can find a comprehensive list of modules in the [[file:index.org::*Module list][Module Index]]. 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 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.
** How do I change the theme? ** How do I change the theme?
There are two ways to load a theme. Both assume the theme is installed and 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 #+BEGIN_SRC emacs-lisp
;;; in ~/.doom.d/config.el ;;; add to ~/.doom.d/config.el
(setq doom-theme 'doom-tomorrow-night) (setq doom-theme 'doom-tomorrow-night)
;; or ;; or
(load-theme 'doom-tomorrow-night t) (load-theme 'doom-tomorrow-night t)
#+END_SRC #+END_SRC
#+begin_quote
At the moment, the only difference between the two is that ~doom-theme~ is 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 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 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 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 can easily change how Doom uses ~doom-theme~, but I can't (easily) control how
you use the ~load-theme~ function. you use the ~load-theme~ function.
#+end_quote
*** Installing a third party theme *** 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 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: install it, then load it:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
;; in ~/.doom.d/packages.el ;;; add to ~/.doom.d/packages.el
(package! solarized) (package! solarized-theme)
;; in ~/.doom.d/config.el ;;; add to ~/.doom.d/config.el
(setq doom-theme 'solarized-dark) (setq doom-theme 'solarized-dark)
#+END_SRC #+END_SRC
Don't forget to run ~doom refresh~ afterwards to ensure the package is Don't forget to run ~doom sync~ after adding that ~package!~ statement to ensure
installed. the package is installed.
** How do I change the fonts? ** How do I change the fonts?
Doom exposes five (optional) variables for controlling fonts in Doom, they are: 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-unicode-font~
+ ~doom-big-font~ (used for ~doom-big-font-mode~) + ~doom-big-font~ (used for ~doom-big-font-mode~)
Each of these will accept either a =font-spec=, font string (="Input Mono-12"=), They all accept either a =font-spec=, font string (="Input Mono-12"=), or [[https://wiki.archlinux.org/index.php/X_Logical_Font_Description][xlfd
or [[https://wiki.archlinux.org/index.php/X_Logical_Font_Description][xlfd font string]]. font string]].
e.g. e.g.
#+BEGIN_SRC emacs-lisp #+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) (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-variable-pitch-font (font-spec :family "Fira Sans") ; inherits `doom-font''s :size
doom-unicode-font (font-spec :family "Input Mono Narrow" :size 12) 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. e.g.
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
;; in ~/.doom.d/config.el ;;; add to ~/.doom.d/config.el
(setq doom-leader-key "," (setq doom-leader-key ","
doom-localleader-key "\\") doom-localleader-key "\\")
#+END_SRC #+END_SRC
@ -705,13 +565,9 @@ e.g.
** 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)?
Doom uses the ~display-line-numbers~ package, which is built into Emacs 26+. 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 *** Disabling line numbers entirely
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
;;; add to ~/.doom.d/config.el
(setq display-line-numbers-type nil) (setq display-line-numbers-type nil)
;; or ;; or
(remove-hook! '(prog-mode-hook text-mode-hook conf-mode-hook) (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) *** Switching to relative line numbers (permanently)
To change the style of line numbers, change the value of the To change the style of line numbers, change the value of the
~display-line-numbers-type~ variable. It accepts =t= (normal line numbers), ~display-line-numbers-type~ variable. It accepts the following values:
='relative= (relative line numbers), ='visual= (relative line numbers in screen
space) and =nil= (no line numbers).
You'll find more precise documentation on the variable through =SPC h v #+begin_example
display-line-numbers-type= or =C-h v display-line-numbers-type=. t normal line numbers
'relative relative line numbers
'visual relative line numbers in screen space
nil no line numbers
#+end_example
#+begin_quote For example:
The ~'visual~ option is unavailable in Emacs 25.
#+end_quote #+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) *** Switching the style of line numbers (temporarily)
Use ~M-x doom/toggle-line-numbers~ (bound to =SPC t l= by default) to cycle 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 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). 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? ** Can Doom be customized without restarting Emacs?
Short answer: You can, but you shouldn't. 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= - 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 operator for evil users) or ~eval-last-sexp~ (bound to =C-x C-e=). Changes
take effect immediately. take effect immediately.
- On-the-fly evaluation won't work for all changes. For instance, changing your - On-the-fly evaluation won't work for all changes. e.g. Changing your ~doom!~
~doom!~ block (i.e. the list of modules for Doom to enable) will always block (i.e. the list of modules for Doom to enable).
require a restart (and ~bin/doom refresh~).
Doom provides ~M-x doom/reload~ for your convenience, which will run ~doom But rather than running ~doom sync~ and restarting Emacs, Doom provides ~M-x
refresh~, restart the Doom initialization process, and re-evaluate your doom/reload~ for your convenience (bound to =SPC h r r= and =C-h r r=). This
personal config, but this won't clear pre-existing state. That may or may not runs ~doom sync~, restarts the Doom initialization process and re-evaluates
be a problem, this hasn't be thoroughly tested and Doom cannot anticipate your personal config. However, this won't clear pre-existing state; Doom won't
complications arising from your private config. unload modules/packages that have already been loaded and it can't anticipate
complications arising from a private config that isn't idempotent.
If you intend to use ~doom/reload~, you must design your config to be - Some ~bin/doom~ commands are available as elisp commands. e.g. ~doom/reload~
idempotent. for ~doom sync~, ~doom/upgrade~ for ~doom upgrade~ ~doom//s~, ~doom//update~, etc. Feel free to use them, but
- 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
consider them highly experimental and subject to change without notice. consider them highly experimental and subject to change without notice.
- You can quickly restart Emacs and restore the last session with - You can quickly restart Emacs and restore the last session with
~doom/restart-and-restore~ (bound to =SPC q r=). ~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 + ~doom doctor~ :: Diagnose common issues in your environment and list missing
external dependencies for your enabled modules. 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. packages are removed, and metadata properly generated.
+ ~doom install~ :: Install any missing packages. + ~doom install~ :: Install any missing packages.
+ ~doom update~ :: Update all packages that Doom's (enabled) modules use. + ~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 #+BEGIN_SRC bash
git pull git pull
doom refresh doom sync
doom update doom update
#+END_SRC #+END_SRC
** When to run ~doom refresh~ ** When to run ~doom sync~
As a rule of thumb you should run ~doom refresh~ whenever you: As a rule of thumb you should run ~doom sync~ whenever you:
+ Update Doom with ~git pull~ instead of ~doom upgrade~, + Update Doom with ~git pull~ instead of ~doom upgrade~,
+ Change your ~doom!~ block in =$DOOMDIR/init.el=, + 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 + Install an Emacs package or dependency outside of Emacs (i.e. through your OS
package manager). package manager).
If anything is misbehaving, it's a good idea to run ~doom refresh~ first. ~doom If anything is misbehaving, it's a good idea to run ~doom sync~ first. ~doom
refresh~ is responsible for regenerating your autoloads file (which tells Doom sync~ is responsible for regenerating your autoloads file (which tells Doom
where to find lazy-loaded functions and libraries), installing missing packages, where to find lazy-loaded functions and libraries), installing missing packages,
and uninstall orphaned (unneeded) packages. and uninstall orphaned (unneeded) packages.
@ -835,9 +710,32 @@ doom --yes update
YES=1 doom update YES=1 doom update
#+END_SRC #+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 * Defaults
** Why Ivy over Helm? ** 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 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 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: Otherwise, it is trivial to install expand-region and binds keys to it yourself:
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
;; in ~/.doom.d/packages.el ;;; add to ~/.doom.d/packages.el
(package! expand-region) (package! expand-region)
;; in ~/.doom.d/config.el ;;; add to ~/.doom.d/config.el
(map! :nv "C-=" #'er/contract-region (map! :nv "C-=" #'er/contract-region
:nv "C-+" #'er/expand-region) :nv "C-+" #'er/expand-region)
#+END_SRC #+END_SRC
** Why not use exec-path-from-shell instead of ~doom env~? ** 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 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 your shell environment. This can be slow depending on the user's shell
shell configuration. A single program (like pyenv or nvm) or config framework configuration. A single program (like pyenv or nvm) or config framework (like
(like oh-my-zsh) could undo all of Doom's startup optimizations in one fell oh-my-zsh) could undo Doom's startup optimizations in one fell swoop.
swoop.
2. ~exec-path-from-shell~ only scrapes /some/ state from your shell. You have to 2. ~exec-path-from-shell~ takes a whitelist approach and captures only ~PATH~
be proactive in order to get it to capture all the envvars relevant to your and ~MANPATH~ by default. You must be proactive in order to capture all the
development environment. envvars relevant to your development environment and tools.
I'd rather it inherit your shell environment /correctly/ (and /completely/) ~doom env~ takes the blacklist approach and captures all of your shell
or not at all. It frontloads the debugging process rather than hiding it environment. This front loads the debugging process, which is nicer than dealing
until it you least want to deal with it. with it later, while you're getting work done.
That said, if you still want ~exec-path-from-shell~, it is trivial to install That said, if you still want ~exec-path-from-shell~, it is trivial to install
yourself: yourself:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
;; in ~/.doom.d/packages.el ;;; add to ~/.doom.d/packages.el
(package! exec-path-from-shell) (package! exec-path-from-shell)
;; in ~/.doom.d/config.el ;;; add to ~/.doom.d/config.el
(require 'exec-path-from-shell) (require 'exec-path-from-shell)
(when (display-graphic-p) (when (display-graphic-p)
(exec-path-from-shell-initialize)) (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 Don't be that guy who PRs 99 whitespace adjustments around his one-line
contribution. Don't automate this aggressive behavior by attaching contribution. Don't automate this aggressive behavior by attaching
~delete-trailing-whitespace~ (or ~whitespace-cleanup~) to ~before-save-hook~. If ~delete-trailing-whitespace~ (or ~whitespace-cleanup~) to ~before-save-hook~. If
you have rambunctious colleagues peppering trailing whitespace into your project, you have rambunctious colleagues peppering trailing whitespace into your
you need to have a talk (with wiffle bats, preferably) rather than play this project, you need to have a talk (with wiffle bats, preferably) rather than play
passive-aggressive game of whack-a-mole. a passive-aggressive game of whack-a-mole.
Here at Doom Inc we believe that operations that mutate entire files should Here at Doom Inc we believe that operations that mutate entire files should not
never be automated. Rather, they should be invoked deliberately -- by someone be automated. Rather, they should be invoked deliberately, when and where it is
that is aware of the potential consequences. This is where =ws-butler= comes in. needed, by someone that is aware of the potential consequences. This is where
It only cleans up whitespace /on the lines you've touched/ *and* it leaves =ws-butler= comes in. It only cleans up whitespace /on the lines you've touched/
behind virtual whitespace (which is never written to the file, but remains there *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). 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 In any case, if you had used =ws-butler= from the beginning, trailing whitespace
and newlines would never be a problem! 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 ** ~void-variable~ and ~void-function~ errors on startup
The most common culprit for these types of errors are: 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!~ 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 =~/.doom.d/packages.el=. Or if you modify =~/.emacs.d/.local= by hand, for
whatever reason. 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. should use it.
2. Emacs byte-code isn't forward compatible. If you've recently switched to a 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. 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. 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. place to ask about it.
** There's artefacting on my icon fonts in GUI Emacs ([[https://github.com/hlissner/doom-emacs/issues/956][#956]]) ** 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. 1. Make sure you don't have both =~/.doom.d= and =~/.config/doom= directories.
Doom will ignore the former if the latter exists. Doom will ignore the former if the latter exists.
2. Remember to run ~doom refresh~ when it is necessary. To get to know when, 2. Remember to run ~doom sync~ when it is necessary. To get to know when,
exactly, you should run this command, run ~doom help refresh~. 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 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. 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), support it),
3. Install Emacs via the =emacs-mac= homebrew formula. 3. Install Emacs via the =emacs-mac= homebrew formula.
** Doom crashes when... ** Doom crashes when...
Here are a few common causes for random crashes: 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]]). 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 * TODO Contributing

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,20 @@
#+TITLE: Doom Emacs Documentation #+TITLE: Doom Emacs Documentation
#+STARTUP: nofold #+STARTUP: nofold
Doom Emacs is a configuration for [[https://www.gnu.org/software/emacs/][GNU Emacs]] written by a stubborn, Doom is a configuration framework for [[https://www.gnu.org/software/emacs/][GNU Emacs 26.3+]] tailored for Emacs
shell-dwelling, and melodramatic ex-vimmer. It is designed to be a foundation bankruptcy veterans who want less framework in their frameworks and the
for your own Emacs configuration or a resource for enthusiasts to learn more performance of a hand rolled config (or better). It can be a foundation for your
about our favorite OS. 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 #+begin_quote
Github fails to render org links to sub-sections, so it is recommended that you The documentation is designed to be viewed within Doom Emacs. Access it by
view the documentation from within Doom Emacs by pressing =<help> d h= (=<help>= pressing =SPC h d h= (or =C-h d h= for non-evil users), or search it with =SPC h
is =SPC h= for evil users and =C-h= for vanilla users) or searching it with d s= (or =C-h d s=).
=<help> d /=.
#+end_quote #+end_quote
* Table of Contents :TOC: * 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]] - [[#frequently-asked-questions][Frequently Asked Questions]]
- [[#contributing][Contributing]] - [[#contributing][Contributing]]
- [[#workflow-tips-tricks--tutorials][Workflow Tips, Tricks & Tutorials]] - [[#workflow-tips-tricks--tutorials][Workflow Tips, Tricks & Tutorials]]
- [[#module-appendix][Module Appendix]]
- [[#community-resources][Community Resources]] - [[#community-resources][Community Resources]]
- [[#asking-for-help][Asking for help]] - [[#asking-for-help][Asking for help]]
- [[#project-roadmap][Project roadmap]] - [[#project-roadmap][Project roadmap]]
- [[#tutorials--guides][Tutorials & guides]] - [[#tutorials--guides][Tutorials & guides]]
- [[#module-list][Module list]] - [[#projects-that-supportcompliment-doom][Projects that support/compliment Doom]]
- [[#app][:app]] - [[#similar-projects][Similar projects]]
- [[#completion][:completion]]
- [[#config][:config]]
- [[#editor][:editor]]
- [[#emacs][:emacs]]
- [[#email][:email]]
- [[#input][:input]]
- [[#lang][:lang]]
- [[#term][:term]]
- [[#tools][:tools]]
- [[#ui][:ui]]
* TODO Release Notes * TODO Release Notes
* Documentation * Documentation
** [[file:getting_started.org][Getting Started]] ** [[file:getting_started.org][Getting Started]]
- [[file:getting_started.org::*Install][Install]] - How to install Emacs, Doom and its plugins - [[file:getting_started.org::*Install][Install]]
- [[file:getting_started.org::*Update][Update]] - Keep Doom and its packages up-to-date - [[file:getting_started.org::*Update & Rollback][Update & Rollback]]
- [[file:getting_started.org::*Customize][Customize]] - A primer on customizing and reconfiguring Doom - [[file:getting_started.org::*Configure][Configure]]
- [[file:getting_started.org::*Troubleshoot][Troubleshoot]] - How to debug Emacs & Doom, find help or look up documentation - [[file:getting_started.org::*Migrate][Migrate]]
- [[file:getting_started.org::*Troubleshoot][Troubleshoot]]
** [[file:faq.org][Frequently Asked Questions]] ** [[file:faq.org][Frequently Asked Questions]]
- [[file:faq.org::*General][General]] - [[file:faq.org::*General][General]]
- [[file:faq.org::*Configuration][Configuration]] - [[file:faq.org::*Configuration][Configuration]]
- [[file:faq.org::*Package Management][Package Management]]
- [[file:faq.org::*Defaults][Defaults]] - [[file:faq.org::*Defaults][Defaults]]
- [[file:faq.org::Common Issues][Common Issues]] - [[file:faq.org::Common Issues][Common Issues]]
- [[file:faq.org::Contributing][Contributing]] - [[file:faq.org::Contributing][Contributing]]
** TODO [[file:contributing.org][Contributing]] ** TODO [[file:contributing.org][Contributing]]
- [[file:contributing.org::*Where can I help?][Where to get help]] - [[file:contributing.org::*Where can I help?][Where to get help?]]
- Writing an effective bug report - Reporting issues
- Suggesting features, keybinds or enhancements - Suggesting features, keybinds and enhancements
- Contributing code - Contributing code or documentation
- Contributing documentation
- Other ways to support Doom Emacs - Other ways to support Doom Emacs
- Special thanks - Special thanks
** TODO [[file:workflow.org][Workflow Tips, Tricks & Tutorials]] ** TODO [[file:workflow.org][Workflow Tips, Tricks & Tutorials]]
** [[file:modules.org][Module Appendix]]
* Community Resources * Community Resources
** Asking for help ** 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]] - [[https://github.com/hlissner/doom-emacs/issues][Our issue tracker]]
** Project roadmap ** Project roadmap
@ -79,11 +77,12 @@ is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
** Tutorials & guides ** Tutorials & guides
+ *Doom Emacs* + *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://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/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://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)]] - (video) [[https://www.youtube.com/watch?v=GK3fij-D1G8][Org-mode, literate programming in (Doom) Emacs]]
- [[https://www.youtube.com/watch?v=GK3fij-D1G8][Org-mode, literate programming in (Doom) Emacs]]
+ *Emacs & Emacs Lisp* + *Emacs & Emacs Lisp*
- [[https://www.gnu.org/software/emacs/manual/html_node/elisp/index.html][The Official Emacs manual]] - [[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 - 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 - http://steve-yegge.blogspot.com/2008/01/emergency-elisp.html
- Workflows for customizing Emacs and its packages (and its C/C++ modes): - Workflows for customizing Emacs and its packages (and its C/C++ modes):
- https://david.rothlis.net/emacs/customize_c.html - https://david.rothlis.net/emacs/customize_c.html
+ *Tools in Emacs* - *Tools in Emacs*
- [[https://www.emacswiki.org/emacs/Calc_Tutorials_by_Andrew_Hyatt][How to use M-x calc]] - [[https://www.emacswiki.org/emacs/Calc_Tutorials_by_Andrew_Hyatt][How to use M-x calc]]
+ *Vim & Evil* + *Vim & Evil*
- [[https://gist.github.com/dmsul/8bb08c686b70d5a68da0e2cb81cd857f][A crash course on modal editing and Ex commands]] - [[https://gist.github.com/dmsul/8bb08c686b70d5a68da0e2cb81cd857f][A crash course on modal editing and Ex commands]]
* Module list ** Projects that support/compliment Doom
** :app + [[https://github.com/plexus/chemacs][plexus/chemacs]]
Application modules are complex and opinionated modules that transform Emacs + [[https://github.com/r-darwish/topgrade][r-darwish/topgrade]]
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 ** Similar projects
+ [[file:../modules/app/irc/README.org][irc]] - how neckbeards socialize + [[https://github.com/purcell/emacs.d][purcell/emacs.d]]
+ rss =+org= - an RSS client in Emacs + [[https://github.com/seagle0128/.emacs.d][seagle0128/.emacs.d]]
+ twitter - A twitter client for Emacs + [[https://github.com/syl20bnr/spacemacs][syl20bnr/spacemacs]]
+ [[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

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 #+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: * Table of Contents :TOC:
- [[#day-1-in-doom-emacs][Day 1 in Doom Emacs]] - [[#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]] - [[#pipe-text-through-ex-commands-and-programs][Pipe text through ex commands and programs]]
- [[#transposingswapping-text][Transposing/swapping text]] - [[#transposingswapping-text][Transposing/swapping text]]
- [[#managing-your-projects][Managing your projects]] - [[#managing-your-projects][Managing your projects]]
- [[#reconfiguring-emacs-on-a-per-project-basis][Reconfiguring Emacs on a per-project basis]]
- [[#search--replace][Search & replace]] - [[#search--replace][Search & replace]]
- [[#project-wide-text-search][Project-wide text search]] - [[#project-wide-text-search][Project-wide text search]]
- [[#search--replace-1][Search & replace]] - [[#search--replace-1][Search & replace]]
@ -32,6 +41,8 @@ This page is a WIP.
- [[#using-emacs-for][Using Emacs for...]] - [[#using-emacs-for][Using Emacs for...]]
- [[#writing-fiction][Writing fiction]] - [[#writing-fiction][Writing fiction]]
- [[#writing-papers][Writing papers]] - [[#writing-papers][Writing papers]]
- [[#note-keeping][Note-keeping]]
- [[#a-personal-organizer][A Personal Organizer]]
- [[#composing-music][Composing music]] - [[#composing-music][Composing music]]
- [[#game-development][Game development]] - [[#game-development][Game development]]
- [[#web-development][Web development]] - [[#web-development][Web development]]
@ -48,6 +59,9 @@ This page is a WIP.
** TODO Pipe text through ex commands and programs ** TODO Pipe text through ex commands and programs
** TODO Transposing/swapping text ** TODO Transposing/swapping text
* TODO Managing your projects * TODO Managing your projects
** TODO Reconfiguring Emacs on a per-project basis
*** TODO .dir-locals.el
*** TODO editorconfig
* TODO Search & replace * TODO Search & replace
** TODO Project-wide text search ** TODO Project-wide text search
** TODO Search & replace ** TODO Search & replace
@ -66,6 +80,8 @@ This page is a WIP.
* TODO Using Emacs for... * TODO Using Emacs for...
** TODO Writing fiction ** TODO Writing fiction
** TODO Writing papers ** TODO Writing papers
** TODO Note-keeping
** TODO A Personal Organizer
** TODO Composing music ** TODO Composing music
** TODO Game development ** TODO Game development
** TODO Web development ** TODO Web development

View file

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

11
init.el
View file

@ -28,14 +28,13 @@
;;; License: MIT ;;; License: MIT
;; A big contributor to startup times is garbage collection. We up the gc ;; 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 ;; threshold to temporarily prevent it from running, then reset it later by
;; `doom-restore-garbage-collection-h'. Not resetting it will cause ;; enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes.
;; stuttering/freezes.
(setq gc-cons-threshold most-positive-fixnum) (setq gc-cons-threshold most-positive-fixnum)
;; In noninteractive sessions, prioritize non-byte-compiled source files to ;; 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 ;; 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) (setq load-prefer-newer noninteractive)
(let (file-name-handler-alist) (let (file-name-handler-alist)
@ -51,6 +50,4 @@
(if noninteractive (if noninteractive
(doom-initialize-packages) (doom-initialize-packages)
(doom-initialize-core) (doom-initialize-core)
(doom-initialize-modules) (doom-initialize-modules))
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler)))

View file

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

View file

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

View file

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

View file

@ -7,8 +7,11 @@
- [[#description][Description]] - [[#description][Description]]
- [[#module-flags][Module Flags]] - [[#module-flags][Module Flags]]
- [[#plugins][Plugins]] - [[#plugins][Plugins]]
- [[#dependencies][Dependencies]]
- [[#prerequisites][Prerequisites]] - [[#prerequisites][Prerequisites]]
- [[#macos][macOS]]
- [[#debian--ubuntu][Debian / Ubuntu]]
- [[#arch-linux][Arch Linux]]
- [[#nixos][NixOS]]
- [[#features][Features]] - [[#features][Features]]
- [[#an-irc-client-in-emacs][An IRC Client in Emacs]] - [[#an-irc-client-in-emacs][An IRC Client in Emacs]]
- [[#configuration][Configuration]] - [[#configuration][Configuration]]
@ -17,7 +20,7 @@
- [[#troubleshooting][Troubleshooting]] - [[#troubleshooting][Troubleshooting]]
* Description * 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 ** Module Flags
This module provides no flags. This module provides no flags.
@ -26,11 +29,27 @@ This module provides no flags.
+ [[https://github.com/jorgenschaefer/circe][circe]] + [[https://github.com/jorgenschaefer/circe][circe]]
+ [[https://github.com/eqyiel/circe-notifications][circe-notifications]] + [[https://github.com/eqyiel/circe-notifications][circe-notifications]]
* Dependencies
This module requires =gnutls-cli= or =openssl= for secure connections.
* Prerequisites * 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 * Features
** An IRC Client in Emacs ** 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 | | ~circe-reconnect~ | =SPC m R= | Reconnect the current server |
* Configuration * 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~. takes the same arguments as ~circe-network-options~.
#+BEGIN_SRC emacs-lisp :tangle no #+BEGIN_SRC emacs-lisp :tangle no
(set-irc-server! "chat.freenode.net" ;; if you omit =:host=, ~SERVER~ will be used instead.
`(:tls t (after! circe
:nick "doom" (set-irc-server! "chat.freenode.net"
:sasl-username "myusername" `(:tls t
:sasl-password "mypassword" :port 6697
:channels ("#emacs"))) :nick "doom"
:sasl-username "myusername"
:sasl-password "mypassword"
:channels ("#emacs"))))
#+END_SRC #+END_SRC
*It is a obviously a bad idea to store auth-details in plaintext,* so here are However, *it is a obviously a bad idea to store your password in plaintext,* so
some ways to avoid that: here are ways to avoid that:
** Pass: the unix password manager ** 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 [[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 #+BEGIN_SRC emacs-lisp :tangle no
(set-irc-server! "chat.freenode.net" (set-irc-server! "chat.freenode.net"
`(:tls t `(:tls t
:port 6697
:nick "doom" :nick "doom"
:sasl-username ,(+pass-get-user "irc/freenode.net") :sasl-username ,(+pass-get-user "irc/freenode.net")
:sasl-password ,(+pass-get-secret "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 listed in =+pass-user-fields= (by default =login=, =user==, =username== and
=email=)=). An example configuration looks like =email=)=). An example configuration looks like
#+BEGIN_SRC txt :tangle no #+begin_example
mysecretpassword mysecretpassword
username: myusername username: myusername
#+END_SRC #+end_example
** Emacs' auth-source API ** 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 ~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*") (defvar +irc--workspace-name "*IRC*")
(defun +irc-setup-wconf (&optional inhibit-workspace) (defun +irc-setup-wconf (&optional inhibit-workspace)
(unless inhibit-workspace (when (and (featurep! :ui workspaces)
(+workspace-switch +irc--workspace-name t)) (not inhibit-workspace))
(+workspace-switch +irc--workspace-name 'auto-create))
(let ((buffers (doom-buffers-in-mode 'circe-mode nil t))) (let ((buffers (doom-buffers-in-mode 'circe-mode nil t)))
(if buffers (if buffers
(ignore (switch-to-buffer (car 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 If INHIBIT-WORKSPACE (the universal argument) is non-nil, don't spawn a new
workspace for it." workspace for it."
(interactive "P") (interactive "P")
(cond ((and (featurep! :ui workspaces) (+irc-setup-wconf inhibit-workspace)
(+workspace-exists-p +irc--workspace-name)) (cond ((doom-buffers-in-mode 'circe-mode (doom-buffer-list) t)
(+workspace-switch +irc--workspace-name)) (message "Circe buffers are already open"))
((not (+irc-setup-wconf inhibit-workspace)) (circe-network-options
(user-error "Couldn't start up a workspace for IRC"))) (mapc #'circe (mapcar #'car circe-network-options)))
(if (doom-buffers-in-mode 'circe-mode (buffer-list) t) ((call-interactively #'circe))))
(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))))
;;;###autoload ;;;###autoload
(defun +irc/connect (&optional inhibit-workspace) (defun +irc/connect (&optional inhibit-workspace)
@ -52,16 +48,17 @@ workspace for it."
(defun +irc/quit () (defun +irc/quit ()
"Kill current circe session and workgroup." "Kill current circe session and workgroup."
(interactive) (interactive)
(if (y-or-n-p "Really kill IRC session?") (unless (y-or-n-p "Really kill IRC session?")
(let (circe-channel-killed-confirmation (user-error "Aborted"))
circe-server-killed-confirmation) (let (circe-channel-killed-confirmation
(when +irc--defer-timer circe-server-killed-confirmation)
(cancel-timer +irc--defer-timer)) (when +irc--defer-timer
(disable-circe-notifications) (cancel-timer +irc--defer-timer))
(mapc #'kill-buffer (doom-buffers-in-mode 'circe-mode (buffer-list) t)) (disable-circe-notifications)
(when (equal (+workspace-current-name) +irc--workspace-name) (mapc #'kill-buffer (doom-buffers-in-mode 'circe-mode (buffer-list) t))
(+workspace/delete +irc--workspace-name))) (when (featurep! :ui workspaces)
(message "Aborted"))) (when (equal (+workspace-current-name) +irc--workspace-name)
(+workspace/delete +irc--workspace-name)))))
;;;###autoload ;;;###autoload
(defun +irc/ivy-jump-to-channel (&optional this-server) (defun +irc/ivy-jump-to-channel (&optional this-server)
@ -93,7 +90,7 @@ argument) is non-nil only show channels in current server."
;;;###autoload ;;;###autoload
(defun +irc/tracking-next-buffer () (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) (interactive)
(when (derived-mode-p 'circe-mode) (when (derived-mode-p 'circe-mode)
(tracking-next-buffer))) (tracking-next-buffer)))
@ -106,13 +103,12 @@ argument) is non-nil only show channels in current server."
(defun +circe-buffer-p (buf) (defun +circe-buffer-p (buf)
"Return non-nil if BUF is a `circe-mode' buffer." "Return non-nil if BUF is a `circe-mode' buffer."
(with-current-buffer buf (with-current-buffer buf
(and (derived-mode-p 'circe-mode) (derived-mode-p 'circe-mode)))
(eq (safe-persp-name (get-current-persp))
+irc--workspace-name))))
;;;###autoload ;;;###autoload
(defun +irc--add-circe-buffer-to-persp-h () (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)) (let ((persp (get-current-persp))
(buf (current-buffer))) (buf (current-buffer)))
;; Add a new circe buffer to irc workspace when we're in another workspace ;; 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; -*- ;;; app/irc/autoload/settings.el -*- lexical-binding: t; -*-
;;;###autodef ;;;###autodef
(defun set-irc-server! (server letvars) (defun set-irc-server! (server plist)
"Registers an irc SERVER for circe. "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." See `circe-network-options' for details."
(after! circe (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 'doom-real-buffer-functions #'+circe-buffer-p)
(add-hook 'circe-channel-mode-hook #'turn-on-visual-line-mode) (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 #'+irc--add-circe-buffer-to-persp-h)
(add-hook 'circe-mode-hook #'turn-off-smartparens-mode)
(defadvice! +irc--circe-run-disconnect-hook-a (&rest _) (defadvice! +irc--circe-run-disconnect-hook-a (&rest _)
"Runs `+irc-disconnect-hook' after circe disconnects." "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) (define-key lui-mode-map "\C-u" #'lui-kill-to-beginning-of-line)
(setq lui-fill-type nil) (setq lui-fill-type nil)
(when (featurep! :tools flyspell) (when (featurep! :checkers spell)
(setq lui-flyspell-p t)) (setq lui-flyspell-p t))
(after! evil (after! evil

View file

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

View file

@ -49,4 +49,3 @@ https://mediatemple.net"
(set-popup-rules! (set-popup-rules!
'(("^\\*doom-regex\\*$" :size 4 :quit nil) '(("^\\*doom-regex\\*$" :size 4 :quit nil)
("^\\*doom-regex-groups" :side 'left :size 28 :select nil :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 ;; 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'. ;; 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 (defvar +rss-split-direction 'below
"What direction to pop up the entry buffer in elfeed.") "What direction to pop up the entry buffer in elfeed.")
@ -67,8 +63,11 @@ easier to scroll through.")
(use-package! elfeed-org (use-package! elfeed-org
:when (featurep! +org) :when (featurep! +org)
:after elfeed :after elfeed
:init
(setq rmh-elfeed-org-files (list "elfeed.org"))
:config :config
(let ((default-directory org-directory)) (and (let ((default-directory org-directory))
(setq rmh-elfeed-org-files (setq rmh-elfeed-org-files
(mapcar #'expand-file-name +rss-elfeed-files))) (cl-remove-if-not
(elfeed-org)) #'file-exists-p (mapcar #'expand-file-name rmh-elfeed-org-files))))
(elfeed-org)))

View file

@ -1,5 +1,5 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; app/rss/packages.el ;;; app/rss/packages.el
(package! elfeed) (package! elfeed :pin "3f0edb1737")
(package! elfeed-org) (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." "Open a visible link, username or hashtag in a `twittering-mode' buffer."
(interactive) (interactive)
(require 'avy) (require 'avy)
;; REVIEW Is this necessary anymore with `link-hint'
(let ((pt (avy-with +twitter/ace-link (let ((pt (avy-with +twitter/ace-link
(avy--process (avy--process
(+twitter--collect-links) (+twitter--collect-links)

View file

@ -1,5 +1,5 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; app/twitter/packages.el ;;; app/twitter/packages.el
(package! twittering-mode) (package! twittering-mode :pin "114891e8fd")
(package! avy) (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; -*-
;; (defvar ispell-dictionary "en_US")
;;; Packages
(after! ispell (after! ispell
(add-to-list 'ispell-extra-args "--dont-tex-check-comments")
;; Don't spellcheck org blocks ;; Don't spellcheck org blocks
(pushnew! ispell-skip-region-alist (pushnew! ispell-skip-region-alist
'(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:") '(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:")
@ -23,13 +20,13 @@
((executable-find "hunspell") 'hunspell)) ((executable-find "hunspell") 'hunspell))
(`aspell (`aspell
(setq ispell-program-name "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 (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)))) (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) :around '(ispell-word flyspell-auto-correct-word)
(let ((ispell-extra-args (remove "--run-together" ispell-extra-args))) (let ((ispell-extra-args (remove "--run-together" ispell-extra-args)))
(ispell-kill-ispell t) (ispell-kill-ispell t)
@ -49,12 +46,23 @@
;; messages for every word when checking the entire buffer ;; messages for every word when checking the entire buffer
flyspell-issue-message-flag nil) flyspell-issue-message-flag nil)
(add-hook 'text-mode-hook #'flyspell-mode) (add-hook! '(org-mode-hook
(when (featurep! +prog) markdown-mode-hook
(add-hook 'prog-mode-hook #'flyspell-prog-mode)) 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 (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. "Don't mark duplicates when style/grammar linters are present.
e.g. proselint and langtool." e.g. proselint and langtool."
(when (or (and (bound-and-true-p flycheck-mode) (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 ;; Ensure mode-local predicates declared with `set-flyspell-predicate!' are
;; used in their respective major modes. ;; 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 (let ((flyspell-correct
"RET" #'flyspell-correct-word-generic (general-predicate-dispatch nil
[return] #'flyspell-correct-word-generic (and (not (or mark-active (ignore-errors (evil-insert-state-p))))
[mouse-1] #'flyspell-correct-word-generic)) (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 (use-package! flyspell-correct
:commands flyspell-correct-word-generic flyspell-correct-previous-word-generic :commands flyspell-correct-at-point flyspell-correct-previous
:config :config
(cond ((and (featurep! :completion helm) (cond ((and (featurep! :completion helm)
(require 'flyspell-correct-helm nil t))) (require 'flyspell-correct-helm nil t)))
@ -82,3 +95,7 @@ e.g. proselint and langtool."
((require 'flyspell-correct-popup nil t) ((require 'flyspell-correct-popup nil t)
(setq flyspell-popup-correct-delay 0.8) (setq flyspell-popup-correct-delay 0.8)
(define-key popup-menu-keymap [escape] #'keyboard-quit)))) (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; -*- ;;; checkers/syntax/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.")
;; ;;
;;; Packages ;;; Flycheck
(use-package! flycheck (use-package! flycheck
:commands flycheck-list-errors flycheck-buffer :commands flycheck-list-errors flycheck-buffer
@ -24,11 +19,10 @@ errors.")
;; Don't commandeer input focus if the error message pops up (happens when ;; Don't commandeer input focus if the error message pops up (happens when
;; tooltips and childframes are disabled). ;; tooltips and childframes are disabled).
(after! flycheck (set-popup-rule! "^\\*Flycheck error messages\\*" :select nil)
(set-popup-rule! flycheck-error-message-buffer :select nil))
(add-hook! 'doom-escape-hook :append (add-hook! 'doom-escape-hook :append
(defun +flycheck-buffer-h () (defun +syntax-check-buffer-h ()
"Flycheck buffer on ESC in normal mode." "Flycheck buffer on ESC in normal mode."
(when flycheck-mode (when flycheck-mode
(ignore-errors (flycheck-buffer)) (ignore-errors (flycheck-buffer))
@ -47,7 +41,7 @@ errors.")
(use-package! flycheck-popup-tip (use-package! flycheck-popup-tip
:commands flycheck-popup-tip-show-popup flycheck-popup-tip-delete-popup :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 :config
(setq flycheck-popup-tip-error-prefix "") (setq flycheck-popup-tip-error-prefix "")
(after! evil (after! evil
@ -55,7 +49,7 @@ errors.")
;; the cursor's position or cause disruptive input delays. ;; the cursor's position or cause disruptive input delays.
(add-hook! '(evil-insert-state-entry-hook evil-replace-state-entry-hook) (add-hook! '(evil-insert-state-entry-hook evil-replace-state-entry-hook)
#'flycheck-popup-tip-delete-popup) #'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 :before-while #'flycheck-popup-tip-show-popup
(if evil-local-mode (if evil-local-mode
(eq evil-state 'normal) (eq evil-state 'normal)
@ -65,7 +59,7 @@ errors.")
(use-package! flycheck-posframe (use-package! flycheck-posframe
:when (featurep! +childframe) :when (featurep! +childframe)
:defer t :defer t
:init (add-hook 'flycheck-mode-hook #'+flycheck-init-popups-h) :init (add-hook 'flycheck-mode-hook #'+syntax-init-popups-h)
:config :config
(setq flycheck-posframe-warning-prefix "" (setq flycheck-posframe-warning-prefix ""
flycheck-posframe-info-prefix "··· " flycheck-posframe-info-prefix "··· "
@ -79,3 +73,7 @@ errors.")
(add-hook! 'flycheck-posframe-inhibit-functions (add-hook! 'flycheck-posframe-inhibit-functions
#'evil-insert-state-p #'evil-insert-state-p
#'evil-replace-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 ** Module Flags
+ =+childframe= Enables displaying completion candidates in a child frame, + =+childframe= Enables displaying completion candidates in a child frame,
rather than an overlay or tooltip (among with other UI enhancements). *This 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 + =+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 ** Plugins
+ [[https://github.com/company-mode/company-mode][company-mode]] + [[https://github.com/company-mode/company-mode][company-mode]]

View file

@ -20,7 +20,8 @@
:config :config
(when (featurep! :editor evil) (when (featurep! :editor evil)
(add-hook 'company-mode-hook #'evil-normalize-keymaps) (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 ;; 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 ;; by C-x C-n, will switch from `company-yasnippet' to
;; `company-dabbrev-code'. ;; `company-dabbrev-code'.
@ -70,47 +71,42 @@
company-box-max-candidates 50 company-box-max-candidates 50
company-box-icons-alist 'company-box-icons-all-the-icons company-box-icons-alist 'company-box-icons-all-the-icons
company-box-icons-functions company-box-icons-functions
'(+company-box-icons--yasnippet-fn (cons #'+company-box-icons--elisp-fn
company-box-icons--lsp (delq 'company-box-icons--elisp
+company-box-icons--elisp-fn company-box-icons-functions))
company-box-icons--acphp)
company-box-icons-all-the-icons company-box-icons-all-the-icons
`((Unknown . ,(all-the-icons-material "find_in_page" :height 0.8 :face 'all-the-icons-purple)) (let ((all-the-icons-scale-factor 0.8))
(Text . ,(all-the-icons-material "text_fields" :height 0.8 :face 'all-the-icons-green)) `((Unknown . ,(all-the-icons-material "find_in_page" :face 'all-the-icons-purple))
(Method . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) (Text . ,(all-the-icons-material "text_fields" :face 'all-the-icons-green))
(Function . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) (Method . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Constructor . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) (Function . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Field . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) (Constructor . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Variable . ,(all-the-icons-material "adjust" :height 0.8 :face 'all-the-icons-blue)) (Field . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Class . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red)) (Variable . ,(all-the-icons-material "adjust" :face 'all-the-icons-blue))
(Interface . ,(all-the-icons-material "settings_input_component" :height 0.8 :face 'all-the-icons-red)) (Class . ,(all-the-icons-material "class" :face 'all-the-icons-red))
(Module . ,(all-the-icons-material "view_module" :height 0.8 :face 'all-the-icons-red)) (Interface . ,(all-the-icons-material "settings_input_component" :face 'all-the-icons-red))
(Property . ,(all-the-icons-material "settings" :height 0.8 :face 'all-the-icons-red)) (Module . ,(all-the-icons-material "view_module" :face 'all-the-icons-red))
(Unit . ,(all-the-icons-material "straighten" :height 0.8 :face 'all-the-icons-red)) (Property . ,(all-the-icons-material "settings" :face 'all-the-icons-red))
(Value . ,(all-the-icons-material "filter_1" :height 0.8 :face 'all-the-icons-red)) (Unit . ,(all-the-icons-material "straighten" :face 'all-the-icons-red))
(Enum . ,(all-the-icons-material "plus_one" :height 0.8 :face 'all-the-icons-red)) (Value . ,(all-the-icons-material "filter_1" :face 'all-the-icons-red))
(Keyword . ,(all-the-icons-material "filter_center_focus" :height 0.8 :face 'all-the-icons-red)) (Enum . ,(all-the-icons-material "plus_one" :face 'all-the-icons-red))
(Snippet . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-red)) (Keyword . ,(all-the-icons-material "filter_center_focus" :face 'all-the-icons-red))
(Color . ,(all-the-icons-material "color_lens" :height 0.8 :face 'all-the-icons-red)) (Snippet . ,(all-the-icons-material "short_text" :face 'all-the-icons-red))
(File . ,(all-the-icons-material "insert_drive_file" :height 0.8 :face 'all-the-icons-red)) (Color . ,(all-the-icons-material "color_lens" :face 'all-the-icons-red))
(Reference . ,(all-the-icons-material "collections_bookmark" :height 0.8 :face 'all-the-icons-red)) (File . ,(all-the-icons-material "insert_drive_file" :face 'all-the-icons-red))
(Folder . ,(all-the-icons-material "folder" :height 0.8 :face 'all-the-icons-red)) (Reference . ,(all-the-icons-material "collections_bookmark" :face 'all-the-icons-red))
(EnumMember . ,(all-the-icons-material "people" :height 0.8 :face 'all-the-icons-red)) (Folder . ,(all-the-icons-material "folder" :face 'all-the-icons-red))
(Constant . ,(all-the-icons-material "pause_circle_filled" :height 0.8 :face 'all-the-icons-red)) (EnumMember . ,(all-the-icons-material "people" :face 'all-the-icons-red))
(Struct . ,(all-the-icons-material "streetview" :height 0.8 :face 'all-the-icons-red)) (Constant . ,(all-the-icons-material "pause_circle_filled" :face 'all-the-icons-red))
(Event . ,(all-the-icons-material "event" :height 0.8 :face 'all-the-icons-red)) (Struct . ,(all-the-icons-material "streetview" :face 'all-the-icons-red))
(Operator . ,(all-the-icons-material "control_point" :height 0.8 :face 'all-the-icons-red)) (Event . ,(all-the-icons-material "event" :face 'all-the-icons-red))
(TypeParameter . ,(all-the-icons-material "class" :height 0.8 :face 'all-the-icons-red)) (Operator . ,(all-the-icons-material "control_point" :face 'all-the-icons-red))
;; (Template . ,(company-box-icons-image "Template.png")))) (TypeParameter . ,(all-the-icons-material "class" :face 'all-the-icons-red))
(Yasnippet . ,(all-the-icons-material "short_text" :height 0.8 :face 'all-the-icons-green)) (Template . ,(all-the-icons-material "short_text" :face 'all-the-icons-green))
(ElispFunction . ,(all-the-icons-material "functions" :height 0.8 :face 'all-the-icons-red)) (ElispFunction . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(ElispVariable . ,(all-the-icons-material "check_circle" :height 0.8 :face 'all-the-icons-blue)) (ElispVariable . ,(all-the-icons-material "check_circle" :face 'all-the-icons-blue))
(ElispFeature . ,(all-the-icons-material "stars" :height 0.8 :face 'all-the-icons-orange)) (ElispFeature . ,(all-the-icons-material "stars" :face 'all-the-icons-orange))
(ElispFace . ,(all-the-icons-material "format_paint" :height 0.8 :face 'all-the-icons-pink)))) (ElispFace . ,(all-the-icons-material "format_paint" :face 'all-the-icons-pink)))))
(defun +company-box-icons--yasnippet-fn (candidate)
(when (get-text-property 0 'yas-annotation candidate)
'Yasnippet))
(defun +company-box-icons--elisp-fn (candidate) (defun +company-box-icons--elisp-fn (candidate)
(when (derived-mode-p 'emacs-lisp-mode) (when (derived-mode-p 'emacs-lisp-mode)
@ -118,7 +114,15 @@
(cond ((fboundp sym) 'ElispFunction) (cond ((fboundp sym) 'ElispFunction)
((boundp sym) 'ElispVariable) ((boundp sym) 'ElispVariable)
((featurep sym) 'ElispFeature) ((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 (use-package! company-dict

View file

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

View file

@ -38,7 +38,7 @@ workspace."
;;; Project search ;;; Project search
;;;###autoload ;;;###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. "Conduct a file search using ripgrep.
:query STRING :query STRING
@ -51,46 +51,21 @@ workspace."
(declare (indent defun)) (declare (indent defun))
(unless (executable-find "rg") (unless (executable-find "rg")
(user-error "Couldn't find ripgrep in your PATH")) (user-error "Couldn't find ripgrep in your PATH"))
(require 'helm-ag) (require 'helm-rg)
(helm-ag--init-state) (let ((this-command 'helm-rg)
(let* ((project-root (or (doom-project-root) default-directory)) (helm-rg-default-directory (or in (doom-project-root) default-directory))
(directory (or in project-root)) (helm-rg-default-extra-args
(default-directory directory) (delq nil (append (list (when all-files "-z -uu")
(helm-ag--default-directory directory) (unless recursive "--maxdepth 1"))
(helm-ag--default-target (list directory)) args))))
(query (or query (setq deactivate-mark t)
(when (use-region-p) (helm-rg (or query
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning))) (when (use-region-p)
(end (or (bound-and-true-p evil-visual-end) (region-end)))) (let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
(when (> (abs (- end beg)) 1) (end (or (bound-and-true-p evil-visual-end) (region-end))))
(rxt-quote-pcre (buffer-substring-no-properties beg end))))) (when (> (abs (- end beg)) 1)
"")) (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))))
;;;###autoload ;;;###autoload
(defun +helm/project-search (&optional arg initial-query directory) (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) (setq +helm--posframe-buffer buffer)
:position (point) :position (point)
:poshandler +helm-posframe-handler :poshandler +helm-posframe-handler
:respect-header-line helm-echo-input-in-header-line
:width :width
(max (cl-typecase .width (max (cl-typecase .width
(integer .width) (integer .width)

View file

@ -57,8 +57,6 @@ be negative.")
helm-mode-line-string nil helm-mode-line-string nil
helm-ff-auto-update-initial-value nil helm-ff-auto-update-initial-value nil
helm-find-files-doc-header 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 ;; Default helm window sizes
helm-display-buffer-default-width nil helm-display-buffer-default-width nil
helm-display-buffer-default-height 0.25 helm-display-buffer-default-height 0.25
@ -73,11 +71,13 @@ be negative.")
:init :init
(when (featurep! +childframe) (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)) (setq helm-display-function #'+helm-posframe-display-fn))
(let ((fuzzy (featurep! +fuzzy))) (let ((fuzzy (featurep! +fuzzy)))
(setq helm-M-x-fuzzy-match fuzzy (setq helm-M-x-fuzzy-match fuzzy
helm-ag-fuzzy-match fuzzy
helm-apropos-fuzzy-match fuzzy helm-apropos-fuzzy-match fuzzy
helm-apropos-fuzzy-match fuzzy helm-apropos-fuzzy-match fuzzy
helm-bookmark-show-location 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 ;; 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 ;; the package via ELPA. Force them to use +helm/* instead, because they work
;; out of the box. ;; out of the box.
(advice-add #'helm-projectile-rg :override #'+helm/rg) (advice-add #'helm-projectile-rg :override #'+helm/project-search)
(advice-add #'helm-projectile-ag :override #'+helm/ag) (advice-add #'helm-projectile-ag :override #'+helm/project-search)
(advice-add #'helm-projectile-grep :override #'+helm/grep) (advice-add #'helm-projectile-grep :override #'+helm/project-search)
;; Hide the modeline ;; Hide the modeline
(defun +helm--hide-mode-line (&rest _) (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-display-mode-line :override #'+helm--hide-mode-line)
(advice-add #'helm-ag-show-status-default-mode-line :override #'ignore) (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 ;; Use helpful instead of describe-* to display documentation
(dolist (fn '(helm-describe-variable helm-describe-function)) (dolist (fn '(helm-describe-variable helm-describe-function))
(advice-add fn :around #'doom-use-helpful-a))) (advice-add fn :around #'doom-use-helpful-a)))
@ -125,14 +128,16 @@ be negative.")
:config (helm-flx-mode +1)) :config (helm-flx-mode +1))
(after! helm-ag (after! helm-rg
(map! :map helm-ag-edit-map :n "RET" #'compile-goto-error) (setq helm-rg-display-buffer-normal-method #'pop-to-buffer)
(define-key helm-ag-edit-map [remap quit-window] #'helm-ag--edit-abort) (set-popup-rule! "^helm-rg-" :ttl nil :select t :size 0.45)
(set-popup-rule! "^\\*helm-ag-edit" :size 0.35 :ttl 0 :quit nil) (map! :map helm-rg-map
;; Recenter after jumping to match "C-c C-e" #'helm-rg--bounce)
(advice-add #'helm-ag--find-file-action :after-while #'doom-recenter-a) (map! :map helm-rg--bounce-mode-map
;; And record position before jumping "q" #'kill-current-buffer
(advice-add #'helm-ag--find-file-action :around #'doom-set-jump-maybe-a)) "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 ;;;###package helm-bookmark
@ -176,6 +181,7 @@ be negative.")
(set-keymap-parent helm-projectile-find-file-map helm-map)) (set-keymap-parent helm-projectile-find-file-map helm-map))
(setq ivy-height 20) ; for `swiper-isearch'
(after! swiper-helm (after! swiper-helm
(setq swiper-helm-display-function (setq swiper-helm-display-function
(lambda (buf &optional _resume) (pop-to-buffer buf))) (lambda (buf &optional _resume) (pop-to-buffer buf)))

View file

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

View file

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

View file

@ -14,7 +14,7 @@
- [[#arch-linux][Arch Linux]] - [[#arch-linux][Arch Linux]]
- [[#opensuse][openSUSE]] - [[#opensuse][openSUSE]]
- [[#features][Features]] - [[#features][Features]]
- [[#jump-to-file-project-navigation][Jump-to-file project navigation]] - [[#jump-to-navigation][Jump-to navigation]]
- [[#project-search--replace][Project search & replace]] - [[#project-search--replace][Project search & replace]]
- [[#in-buffer-searching][In-buffer searching]] - [[#in-buffer-searching][In-buffer searching]]
- [[#ivy-integration-for-various-completing-commands][Ivy integration for various completing commands]] - [[#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 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: 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 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~ Command-T, this module provides similar functionality by bringing ~projectile~
and ~ivy~ together. 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 p f=, =SPC SPC= | Jump to file in project |
| =SPC f f=, =SPC .= | Jump to file from current directory | | =SPC f f=, =SPC .= | Jump to file from current directory |
| =SPC s i= | Jump to symbol in file |
** Project search & replace ** Project search & replace
This module provides interactive text search and replace using ripgrep. This module provides interactive text search and replace using ripgrep.
| Keybind | Description | | Keybind | Description |
|-----------+---------------------------------| |-----------+--------------------------|
| =SPC s b= | Search the current buffer | | =SPC s p= | Search project |
| =SPC s p= | Search project | | =SPC s P= | Search another project |
| =SPC s d= | Search this directory | | =SPC s d= | Search this directory |
| =SPC p t= | List all TODO/FIXMEs in project | | =SPC s D= | Search another directory |
https://assets.doomemacs.org/completion/ivy/search.png https://assets.doomemacs.org/completion/ivy/search.png
The universal argument (=SPC u= for evil users; =C-u= otherwise) changes the Prefixing these keys with the universal argument (=SPC u= for evil users; =C-u=
behavior of these commands, instructing the underlying search engine to include otherwise) changes the behavior of these commands, instructing the underlying
ignored files. search engine to include ignored files.
This module also provides Ex Commands for evil users: 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][!] [QUERY]~ | Search project (if ~!~, include hidden files) |
| ~:pg[rep]d[!] [QUERY]~ | Search from current directory (if ~!~, don't search recursively) | | ~: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 The optional `!` is equivalent to the universal argument for the previous
previous commands. commands.
----- -----
While in a search these extra keybindings are available to you: These keybindings are available while a search is active:
| Keybind | Description | | 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-c C-e= | Open a writable buffer of your search results |
| =C-SPC= | Preview the current candidate | | =C-SPC= | Preview the current candidate |
| =M-RET= | Open the selected candidate in other-window | | =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 The =swiper= package provides an interactive buffer search powered by ivy. It
can be invoked with: can be invoked with:
+ =SPC s s= + =SPC s s= (~swiper-isearch~)
+ =SPC s S= (uses thing at point as initial input) + =SPC s S= (~swiper-isearch-thing-at-point~)
+ =SPC s b= (~swiper~)
+ ~:sw[iper] [QUERY]~ + ~:sw[iper] [QUERY]~
https://assets.doomemacs.org/completion/ivy/swiper.png 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'." `+ivy-buffer-unreal-face'."
(let ((b (get-buffer candidate))) (let ((b (get-buffer candidate)))
(when (null uniquify-buffer-name-style) (when (null uniquify-buffer-name-style)
(when-let* ((file-path (buffer-file-name b)) (setq candidate (replace-regexp-in-string "<[0-9]+>$" "" candidate)))
(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))))
(cond ((ignore-errors (cond ((ignore-errors
(file-remote-p (file-remote-p
(buffer-local-value 'default-directory b))) (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")) (user-error "No completion session is active"))
(require 'wgrep) (require 'wgrep)
(let ((caller (ivy-state-caller ivy-last))) (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 (ivy-exit-with-action
(lambda (_) (funcall occur-fn))) (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 (let ((buffer (generate-new-buffer
(format "*ivy-occur%s \"%s\"*" (format "*ivy-occur%s \"%s\"*"
(if caller (concat " " (prin1-to-string caller)) "") (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." The point of this is to avoid Emacs locking up indexing massive file trees."
(interactive) (interactive)
(call-interactively ;; Spoof the command so that ivy/counsel will display the (well fleshed-out)
(cond ((or (file-equal-p default-directory "~") ;; actions list for `counsel-find-file' on C-o. The actions list for the other
(when-let (proot (doom-project-root)) ;; commands aren't as well configured or are empty.
(file-equal-p proot "~"))) (let ((this-command 'counsel-find-file))
#'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) ((doom-project-p)
(let ((files (projectile-current-project-files))) (let ((files (projectile-current-project-files)))
(if (<= (length files) ivy-sort-max-size) (if (<= (length files) ivy-sort-max-size)
#'counsel-projectile-find-file #'counsel-projectile-find-file
#'projectile-find-file))) #'projectile-find-file)))
(#'counsel-file-jump)))) (#'counsel-file-jump)))))
;;;###autoload ;;;###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. "Conduct a file search using ripgrep.
:query STRING :query STRING
@ -251,36 +246,35 @@ The point of this is to avoid Emacs locking up indexing massive file trees."
(unless (executable-find "rg") (unless (executable-find "rg")
(user-error "Couldn't find ripgrep in your PATH")) (user-error "Couldn't find ripgrep in your PATH"))
(require 'counsel) (require 'counsel)
(let* ((ivy-more-chars-alist '((t . 1))) (let* ((this-command 'counsel-rg)
(project-root (or (doom-project-root) default-directory)) (project-root (or (doom-project-root) default-directory))
(directory (or in project-root)) (directory (or in project-root))
(default-directory directory)
(args (concat (if all-files " -uu") (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 (counsel-rg
(or (if query query) (or query
(when (use-region-p) (when (doom-region-active-p)
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning))) (replace-regexp-in-string
(end (or (bound-and-true-p evil-visual-end) (region-end)))) "[! |]" (lambda (substr)
(when (> (abs (- end beg)) 1) (cond ((and (string= substr " ")
(let ((query (buffer-substring-no-properties beg end))) (not (featurep! +fuzzy)))
;; Escape characters that are special to ivy searches " ")
(replace-regexp-in-string "[! |]" (lambda (substr) ((string= substr "|")
(cond ((and (string= substr " ") "\\\\\\\\|")
(not (featurep! +fuzzy))) ((concat "\\\\" substr))))
" ") (rxt-quote-pcre (doom-thing-at-point-or-region)))))
((string= substr "|")
"\\\\\\\\|")
((concat "\\\\" substr))))
(rxt-quote-pcre query)))))))
directory args directory args
(format "rg%s %s" (or prompt
args (format "rg%s [%s]: "
(cond ((equal directory default-directory) args
"./") (cond ((equal directory default-directory)
((equal directory project-root) "./")
(projectile-project-name)) ((equal directory project-root)
((file-relative-name directory project-root))))))) (projectile-project-name))
((file-relative-name directory project-root))))))))
;;;###autoload ;;;###autoload
(defun +ivy/project-search (&optional arg initial-query directory) (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 non-nil, preview non-virtual buffers.
When 'everything, also preview 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 (defvar +ivy-buffer-unreal-face 'font-lock-comment-face
"The face for unreal buffers in `ivy-switch-to-buffer'.") "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 "A plist mapping ivy/counsel commands to commands that generate an editable
results buffer.") 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 ;;; Packages
@ -43,15 +21,24 @@ results buffer.")
(use-package! ivy (use-package! ivy
:after-call pre-command-hook :after-call pre-command-hook
:init :init
(setq ivy-re-builders-alist (let ((standard-search-fn
`(,@(cl-loop for cmd in '(counsel-ag (if (featurep! +prescient)
counsel-rg #'+ivy-prescient-non-fuzzy
counsel-grep #'ivy--regex-plus))
swiper (alt-search-fn
swiper-isearch) (if (featurep! +fuzzy)
collect (cons cmd +ivy-standard-search-fn)) #'ivy--regex-fuzzy
;; Ignore order for non-fuzzy searches by default ;; Ignore order for non-fuzzy searches by default
(t . ,+ivy-alternative-search-fn))) #'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! (define-key!
[remap switch-to-buffer] #'+ivy/switch-buffer [remap switch-to-buffer] #'+ivy/switch-buffer
@ -75,7 +62,7 @@ results buffer.")
;; ...but if that ever changes, show their full path ;; ...but if that ever changes, show their full path
ivy-virtual-abbreviate 'full ivy-virtual-abbreviate 'full
;; don't quit minibuffer on delete-error ;; 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') ;; enable ability to select prompt (alternative to `ivy-immediate-done')
ivy-use-selectable-prompt t) 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)) (let ((completion-in-region-function #'completion--in-region))
(apply orig-fn args))) (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) (ivy-mode +1)
@ -128,6 +117,8 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
(use-package! ivy-rich (use-package! ivy-rich
:after ivy :after ivy
:config :config
(setq ivy-rich-parse-remote-buffer nil)
(when (featurep! +icons) (when (featurep! +icons)
(cl-pushnew '(+ivy-rich-buffer-icon) (cl-pushnew '(+ivy-rich-buffer-icon)
(cadr (plist-get ivy-rich-display-transformers-list (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! (define-key!
[remap apropos] #'counsel-apropos [remap apropos] #'counsel-apropos
[remap bookmark-jump] #'counsel-bookmark [remap bookmark-jump] #'counsel-bookmark
[remap compile] #'+ivy/compile
[remap describe-bindings] #'counsel-descbinds
[remap describe-face] #'counsel-faces [remap describe-face] #'counsel-faces
[remap describe-function] #'counsel-describe-function [remap describe-function] #'counsel-describe-function
[remap describe-variable] #'counsel-describe-variable [remap describe-variable] #'counsel-describe-variable
[remap describe-bindings] #'counsel-descbinds [remap evil-ex-registers] #'counsel-evil-registers
[remap set-variable] #'counsel-set-variable [remap evil-show-marks] #'counsel-mark-ring
[remap execute-extended-command] #'counsel-M-x [remap execute-extended-command] #'counsel-M-x
[remap find-file] #'counsel-find-file [remap find-file] #'counsel-find-file
[remap find-library] #'counsel-find-library [remap find-library] #'counsel-find-library
[remap info-lookup-symbol] #'counsel-info-lookup-symbol
[remap imenu] #'counsel-imenu [remap imenu] #'counsel-imenu
[remap recentf-open-files] #'counsel-recentf [remap info-lookup-symbol] #'counsel-info-lookup-symbol
[remap swiper] #'counsel-grep-or-swiper [remap load-theme] #'counsel-load-theme
[remap evil-ex-registers] #'counsel-evil-registers
[remap evil-show-marks] #'counsel-mark-ring
[remap yank-pop] #'counsel-yank-pop
[remap locate] #'counsel-locate [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 unicode-chars-list-chars] #'counsel-unicode-char
[remap compile] #'+ivy/compile [remap yank-pop] #'counsel-yank-pop)
[remap projectile-compile-project] #'+ivy/project-compile)
:config :config
(set-popup-rule! "^\\*ivy-occur" :size 0.35 :ttl 0 :quit nil) (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 ;; Don't use ^ as initial input. Set this here because `counsel' defines more
;; of its own, on top of the defaults. ;; of its own, on top of the defaults.
(setq ivy-initial-inputs-alist nil) (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' ;; Integrate with `helpful'
(setq counsel-describe-function-function #'helpful-callable (setq counsel-describe-function-function #'helpful-callable
counsel-describe-variable-function #'helpful-variable) 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 ;; Make `counsel-compile' projectile-aware (if you prefer it over
;; `+ivy/compile' and `+ivy/project-compile') ;; `+ivy/compile' and `+ivy/project-compile')
(add-to-list 'counsel-compile-root-functions #'projectile-project-root) (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 ;; Persist `counsel-compile' history
(add-to-list 'savehist-additional-variables '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 (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)) (setq counsel-locate-cmd #'counsel-locate-cmd-mdfind))
;; `swiper'
;; Don't mess with font-locking on the dashboard; it causes breakages ;; Don't mess with font-locking on the dashboard; it causes breakages
(add-to-list 'swiper-font-lock-exclude #'+doom-dashboard-mode) (add-to-list 'swiper-font-lock-exclude #'+doom-dashboard-mode)
;; Record in jumplist when opening files via counsel-{ag,rg,pt,git-grep} ;; `counsel-find-file'
(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'
(setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)") (setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)")
(ivy-add-actions (dolist (fn '(counsel-rg counsel-find-file))
'counsel-find-file (ivy-add-actions
`(("b" counsel-find-file-cd-bookmark-action "cd bookmark") fn '(("p" (lambda (path) (with-ivy-window (insert (file-relative-name path default-directory))))
("s" counsel-find-file-as-root "open as root") "insert relative path")
("m" counsel-find-file-mkdir-action "mkdir") ("P" (lambda (path) (with-ivy-window (insert path)))
("c" ,(+ivy-action-given-file #'copy-file "Copy file") "copy file") "insert absolute path")
("d" ,(+ivy-action-reloading #'+ivy-confirm-delete-file) "delete") ("l" (lambda (path) (with-ivy-window (insert (format "[[./%s]]" (file-relative-name path default-directory)))))
("r" (lambda (path) (rename-file path (read-string "New name: "))) "rename") "insert relative org-link")
("R" ,(+ivy-action-reloading (+ivy-action-given-file #'rename-file "Move")) "move") ("L" (lambda (path) (with-ivy-window (insert (format "[[%s]]" path))))
("f" find-file-other-window "other window") "Insert absolute org-link"))))
("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)")))
(ivy-add-actions (ivy-add-actions 'counsel-file-jump (plist-get ivy--actions-list 'counsel-find-file))
'counsel-ag ; also applies to `counsel-rg'
'(("O" +ivy-git-grep-other-window-action "open in other window")))) ;; `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 (use-package! counsel-projectile
@ -310,7 +303,10 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
#'+ivy/projectile-find-file) #'+ivy/projectile-find-file)
;; no highlighting visited files; slows down the filtering ;; 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 (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) (setf (alist-get t ivy-posframe-display-functions-alist)
#'+ivy-display-at-frame-center-near-bottom-fn) #'+ivy-display-at-frame-center-near-bottom-fn)
;; posframe doesn't work well with async sources ;; posframe doesn't work well with async sources (the posframe will
(dolist (fn '(swiper counsel-ag counsel-grep counsel-git-grep)) ;; 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) (setf (alist-get fn ivy-posframe-display-functions-alist)
#'ivy-display-function-fallback))) #'ivy-display-function-fallback)))
@ -353,7 +351,6 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
(if (featurep! +fuzzy) (if (featurep! +fuzzy)
'(literal regexp initialism fuzzy) '(literal regexp initialism fuzzy)
'(literal regexp initialism)) '(literal regexp initialism))
ivy-prescient-enable-filtering nil ; we do this ourselves
ivy-prescient-retain-classic-highlighting t) ivy-prescient-retain-classic-highlighting t)
:config :config

View file

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