A concise alternative to the file IO elisp idioms we're used to,
involving some combination of with-temp-file, with-temp-buffer,
insert-file-contents, coding-system-for-{read,write}, write-region, read
loops, print-to-current-buffer loops, etc.
These were engineered to make reading/writing text and lisp data from/to
files simpler, and will be used extensively in the v3 CLI.
Consecutive expand-file-name and recursive apply's can be expensive, so
the function has been simplified to rely more on file-name-concat. This
does change one trait about it, however: absolute paths in SEGMENTS no
long reroot the whole path, and are concatenated as ordinary file
segments.
The performance benefit is more pronounced on Emacs 28+, and will be
even more so when Doom later starts byte-compiling its libraries.
There are two issues here.
1. Projectile uses file-remote-p to check for remote (tramp) paths in
its known project list, when it automatically cleans it up on
projectile-mode's activation. This causes tramp.el to be loaded,
which is expensive.
2. file-remote-p relies on an entry in file-name-handler-alist
(autoloaded by tramp.el) to detect remote paths, which causes tramp
to be loaded. However, Doom sets file-name-handler-alist to nil at
startup for a noteable boost in startup performance.
Normally, this is not an issue, as I defer projectile-mode until well
after file-name-handler-alist is restored, but it is trivial for a
user to inadvertantly load it too early (often as part of another
package that depends on it, or by blindly following projectile's
install instructions and calling projectile-mode themselves).
In order to address both of these, I defer projectile's cleanup process
altogether. Another approach I considered was to ensure projectile-mode
wasn't activated until the right time, regardless of when projectile is
loaded, but this may trouble savvier Emacs users who need projectile's
API early during startup, so it needs more consideration.
Fix: #6552
Ref: bbatsov/projectile#1649
Rather than impose a 10-45min compilation step on users, I've disabled
ahead-of-time compilation for deferred compilation. In exchange, it will
eat up some CPU time the first time each uncompiled package is loaded,
but as this happens asynchronously (and are then quietly loaded in the
background), I think this is acceptable.
An --aot switch (or similar) will be added to `doom sync` and `doom
build` in the future, in case folks prefer the old behavior.
In the future, doom-lib (among other things) will be byte-compiled as
part of 'doom sync'. To spare runtime the overhead of checking for these
functions, I've wrapped these in a macro. It also makes their
definitions a tad simpler.
This was removed upstream, and while we haven't bumped use-package for
this to affect us, I may as well remove it early.
Doom will be dropping use-package from core in 3.0, in any case.
Fix: #6699
Ref: 8a3d29e433
This was brought over from `doom-info` in f33d8e7, but one of the
lexical function calls wasn't refactored out.
Ref: a5c80fcb4b/lisp/lib/debug.el (L216-L219)Fix: #6698
Amend: c5e3f4d632
Co-authored-by: ivanbrennan <ivanbrennan@users.noreply.github.com>
If defer-feature! was called with one argument (as is the case in the
:lang common-lisp module), FNS defaulted to an empty list. As a result,
FEATURE was deferred but never re-added to the features list, and after!
blocks were never triggered.
Instead of defaulting to an empty list, fallback to a singleton list
containing just (FEATURE). This aligns with the behavior this macro had
prior to 5b8b04f0c8, which generalized FNS
to support a list of functions rather than just one.
It used to be that after! suppressed macro expansion, but at some point
around 28.1, the elisp interpreter started recognizing the
compiler-macro hint in eval-after-load's definition; implicitly wrapping
quoted forms in a function. Therefore, we can no longer rely on
eval-after-load to hide macros from the byte-compiler. Instead, modules
will need to take care to wrap macro calls in `eval` or similar, on a
case-by-case basis.
This fixes a couple bugs with this macro:
- Nested %-refs (in nested fn!'s) were interpolated as arguments of the
outer-most fn!. E.g. (fn! (fn! %2)) would expand to:
Before this fix:
(lambda (_%1 %2)
(lambda (_%1 %2)
%2))
After this fix:
(lambda ()
(lambda (_%1 %2)
%2))
- Unused arguments were not only listed in the wrong order, they were
off-by-one. E.g.
(fn! %3 %5) expands to (lambda (_%4 _%3 %3 _%1 %5) %3 %5)
This never caused any actual issues, but it was unexpected.
I've also moved the lookup table to `fn!`, and removed unnecessary
entries from it.
startup-redirect-eln-cache adds the new directory and removes
$EMACSDIR/eln-cache from native-comp-eln-load-path, but it's not
available in 28.1, so we'll have to wait until Doom drops 28.1 support
to use it.
doom-etc-dir will be renamed to doom-data-dir, to better reflect its
purpose, and align it with XDG_DATA_HOME (where it will be moved to in
v3, where Doom will begin to obey XDG directory conventions more
closely).
- Deprecates the doom-private-dir variable in favor of doom-user-dir.
- Renames the pseudo category for the user's module: :private -> :user.
- Renames the doom-private-error error type to doom-user-error.
Emacs uses the term "user" to refer to the "things" in user space (e.g.
user-init-file, user-emacs-directory, user-mail-address, xdg-user-dirs,
package-user-dir, etc), and I'd like to be consistent with that. It also
has the nice side-effect of being slightly shorter. I also hope
'doom-user-error' will be less obtuse to beginners than
'doom-private-error'.
featurep! will be renamed modulep! in the future, so it's been
deprecated. They have identical interfaces, and can be replaced without
issue.
featurep! was never quite the right name for this macro. It implied that
it had some connection to featurep, which it doesn't (only that it was
similar in purpose; still, Doom modules are not features). To undo such
implications and be consistent with its namespace (and since we're
heading into a storm of breaking changes with the v3 release anyway),
now was the best opportunity to begin the transition.
To reduce redundancy, remove the maintenance hassle that version
constants would impose later on, and rely on built-in
facilities (featurep) more over global variables or doomisms, these
global constants have been deprecated in favor of Emacs "features":
- EMACS28+ -- replace with (> emacs-major-version 27)
- EMACS29+ -- replace with (> emacs-major-version 28)
- NATIVECOMP -- replace with (featurep 'native-compile)
- MODULES -- replace with (featurep 'dynamic-modules)
(These constants will be formally removed when v3 is released. The IS-*
constants are likely next, but I haven't decided on their substitutes
yet)
I also decided to follow native-compile's example and provide features
for Emacs' system features (since system-configuration-features' docs
outs itself as a poor method to detect features):
- dynamic-modules
- jansson
- native-compile -- this one already exists, but will instead be removed
if it's non-functional; i.e. (native-comp-available-p) returns nil.
These are now detectable using featurep, which is fast and built-in.
Some of our comments/docs can come off as disparaging or snide. They're
glimpses of unfiltered frustration or snarky rubber ducking gone too
far, something I can totally sympathize with, as a scatterbrained
tinkerer, unwittingly made responsible for a lot of work that isn't mine
because of Doom's position as a middleman. But now that Doom has a
veritable userbase, I'd like to hold it to a higher standard.
Light-hearted banter and aired grievances in our source code,
documentation, or community are fine if focused on the problem or the
personal/shared experiences of the community (things that offer value or
amusement to others), but it is never acceptable to attack people or
their efforts. Especially not the very people on whose shoulders Doom
stands.
I sincerely apologize if these have offended you.
Amend: b07614037f
A regression introduced in 1d8c61698b. Doom disables its
file-name-handler-alist optimization if in a daemon session or if debug
mode is active.
Fix: #6657
Amend: 1d8c61698b
If you've moved $EMACSDIR, comp-el-to-eln-filename will throw errors
about missing directories/files, rendering 'doom sync' ineffective and
forcing the user to delete $EMACSDIR and reinstall Doom.
Unsetting file-name-handler-alist around a `load` call prevents any
change to this variable from surviving that file's evaluation (e.g. by
packages loaded therein). Since the user's config files are loaded with
this macro, this affects users' configs, which is unacceptable.
Since this optimization is already done in early-init.el, we can get
away with being more selective here.
See 6f1c0f7cc7 for part 1.
Turns out startup.elc likely exists on most Emacs installations (and,
since it's so integral to Emacs, it likely gets special treatment), so
it was a poor heuristic for this fix. Instead, a more variable target
would be calc-loaddefs.el.
On some systems, only calc-loaddefs.el.gz exists (in which case, we
should turn off the optimization). On others, calc-loaddefs.el
exists (so I'll assume it's safe to leave them on). I won't check for
calc-loaddefs.elc because it doesn't matter; calc.el explicitly
calls (load "calc-loaddefs.el") so it is never loaded.
Of course, you can sidestep the entire issue by building Emacs with
--without-compress-install, but it's not practical for users to
know/want to do that.
Amend: 6f1c0f7cc7
Some installs of Emacs do not come with byte-compiled versions of its
bundled elisp files, so when loading them, Emacs falls back to loading
its *.el.gz files. This would be fine if it were not for a startup
optimization Doom employs, where it sets file-name-handler-alist to
nil (and by doing so, robs Emacs of the ability to read compressed
elisp). This causes "symbol's value as variable is void: \213" errors at
startup.
With this commit, Doom now disables this optimization early if it
suspects this applies to your install. But time will tell if it's early
enough.
Ref: https://mail.gnu.org/archive/html/emacs-devel/2022-08/msg00234.html