Merge branch 'develop' of https://github.com/hlissner/doom-emacs into download-iosevka
This commit is contained in:
commit
825557895c
117 changed files with 1954 additions and 2926 deletions
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
|
@ -16,9 +16,9 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
emacs_version:
|
||||
- 25.3
|
||||
- 26.1
|
||||
- snapshot
|
||||
- 26.2
|
||||
- 26.3
|
||||
include:
|
||||
- emacs_version: 26.3
|
||||
lint_ignore: 1
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<img src="https://img.shields.io/github/tag/hlissner/doom-emacs.svg?label=release&color=orange" alt="Made with Doom Emacs">
|
||||
</a>
|
||||
<a href="https://emacs.org">
|
||||
<img src="https://img.shields.io/badge/Made_for-Emacs_25.3+-blueviolet.svg" alt="Made for Emacs 25.3+">
|
||||
<img src="https://img.shields.io/badge/Made_for-Emacs_26.1+-blueviolet.svg" alt="Made for Emacs 26.1+">
|
||||
</a>
|
||||
<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">
|
||||
|
|
171
bin/doom
171
bin/doom
|
@ -1,105 +1,79 @@
|
|||
#!/usr/bin/env sh
|
||||
":"; ( echo "$EMACS" | grep -q "term" ) && EMACS=emacs || EMACS=${EMACS:-emacs} # -*-emacs-lisp-*-
|
||||
":"; command -v $EMACS >/dev/null || { >&2 echo "Emacs isn't installed"; exit 1; }
|
||||
":"; VERSION=$($EMACS --version | head -n1)
|
||||
":"; case "$VERSION" in *\ 2[0-2].[0-1].[0-9]) echo "You're running $VERSION"; echo "That version is too old to run Doom. Check your PATH"; echo; exit 2 ;; esac
|
||||
":"; DOOMBASE=$(dirname "$0")/..
|
||||
":"; [ "$1" = -d ] || [ "$1" = --debug ] && { shift; export DEBUG=1; }
|
||||
":"; [ "$1" = doc ] || [ "$1" = doctor ] && { cd "$DOOMBASE"; shift; exec $EMACS --script bin/doom-doctor "$@"; exit 0; }
|
||||
":"; [ "$1" = run ] && { cd "$DOOMBASE"; shift; exec $EMACS -q --no-splash -l bin/doom "$@"; exit 0; }
|
||||
":"; exec $EMACS --script "$0" -- "$@"
|
||||
":"; exit 0
|
||||
:; ( echo "$EMACS" | grep -q "term" ) && EMACS=emacs || EMACS=${EMACS:-emacs} # -*-emacs-lisp-*-
|
||||
:; command -v $EMACS >/dev/null || { >&2 echo "Can't find emacs in your PATH"; exit 1; }
|
||||
:; VERSION=$($EMACS --version | head -n1)
|
||||
:; case "$VERSION" in *\ 2[0-5].[0-9]) echo "Detected Emacs $VERSION"; echo "Doom only supports Emacs 26.1 and newer"; echo; exit 2 ;; esac
|
||||
:; DOOMBASE="$(dirname "$0")/.."
|
||||
:; [ "$1" = -d ] || [ "$1" = --debug ] && { shift; export DEBUG=1; }
|
||||
:; [ "$1" = run ] && { cd "$DOOMBASE"; shift; exec $EMACS -q --no-splash -l bin/doom "$@"; exit 0; }
|
||||
:; exec $EMACS --script "$0" -- "$@"
|
||||
:; exit 0
|
||||
|
||||
(defconst user-emacs-directory
|
||||
(or (getenv "EMACSDIR")
|
||||
(expand-file-name "../" (file-name-directory (file-truename load-file-name)))))
|
||||
(let* ((loaddir (file-name-directory (file-truename load-file-name)))
|
||||
(emacsdir (getenv "EMACSDIR"))
|
||||
(user-emacs-directory (or emacsdir (expand-file-name "../" loaddir)))
|
||||
(load-prefer-newer t))
|
||||
|
||||
(defun usage ()
|
||||
(with-temp-buffer
|
||||
(insert (format! "%s %s [COMMAND] [ARGS...]\n"
|
||||
(bold "Usage:")
|
||||
(file-name-nondirectory load-file-name))
|
||||
"\n"
|
||||
"A command line interface for managing Doom Emacs; including\n"
|
||||
"package management, diagnostics, unit tests, and byte-compilation.\n"
|
||||
"\n"
|
||||
"This tool also makes it trivial to launch Emacs out of a different\n"
|
||||
"folder or with a different private module.\n"
|
||||
"\n"
|
||||
(format! (bold "Example:\n"))
|
||||
" doom install\n"
|
||||
" doom help update\n"
|
||||
" doom compile :core lang/php lang/python\n"
|
||||
" doom run\n"
|
||||
" doom run -nw file.txt file2.el\n"
|
||||
" doom run -p ~/.other.doom.d -e ~/.other.emacs.d -nw file.txt\n"
|
||||
"\n"
|
||||
(format! (bold "Options:\n"))
|
||||
" -h --help\t\tSame as help command\n"
|
||||
" -d --debug\t\tTurns on doom-debug-mode (and debug-on-error)\n"
|
||||
" -e --emacsd DIR\tUse the emacs config at DIR (e.g. ~/.emacs.d)\n"
|
||||
" -i --insecure\t\tDisable TLS/SSL validation (not recommended)\n"
|
||||
" -l --local DIR\tUse DIR as your local storage directory\n"
|
||||
" -p --private DIR\tUse the private module at DIR (e.g. ~/.doom.d)\n"
|
||||
" -y --yes\t\tAuto-accept all confirmation prompts\n\n")
|
||||
(princ (buffer-string)))
|
||||
(doom--dispatch-help))
|
||||
(push (expand-file-name "core" user-emacs-directory) load-path)
|
||||
(require 'core)
|
||||
(require 'core-cli)
|
||||
|
||||
;;
|
||||
(let ((args (cdr (cdr (cdr command-line-args)))))
|
||||
;; Parse options
|
||||
(while (ignore-errors (string-prefix-p "-" (car args)))
|
||||
(pcase (pop args)
|
||||
((or "-h" "--help")
|
||||
(push "help" args))
|
||||
((or "-d" "--debug")
|
||||
(setenv "DEBUG" "1")
|
||||
(message "Debug mode on"))
|
||||
((or "-i" "--insecure")
|
||||
(setenv "INSECURE" "1")
|
||||
(message "Insecure mode on"))
|
||||
((or "-p" "--private")
|
||||
(setq doom-private-dir (expand-file-name (concat (pop args) "/")))
|
||||
(setenv "DOOMDIR" doom-private-dir)
|
||||
(message "DOOMDIR changed to %s" doom-private-dir)
|
||||
(or (file-directory-p doom-private-dir)
|
||||
(message "Warning: %s does not exist"
|
||||
(abbreviate-file-name doom-private-dir))))
|
||||
((or "-l" "--local")
|
||||
(setq doom-local-dir (expand-file-name (concat (pop args) "/")))
|
||||
(setenv "DOOMLOCALDIR" doom-local-dir)
|
||||
(message "DOOMLOCALDIR changed to %s" doom-local-dir))
|
||||
((or "-e" "--emacsd")
|
||||
(setq user-emacs-directory (expand-file-name (concat (pop args) "/")))
|
||||
(message "Emacs directory changed to %s" user-emacs-directory))
|
||||
((or "-y" "--yes")
|
||||
(setenv "YES" "1")
|
||||
(message "Auto-yes mode on"))))
|
||||
(defcli! :main
|
||||
((help-p ["-h" "--help"] "Same as help command")
|
||||
(debug-p ["-d" "--debug"] "Turns on doom-debug-mode (and debug-on-error)")
|
||||
(yes-p ["-y" "--yes"] "Auto-accept all confirmation prompts")
|
||||
(emacsdir ["--emacsdir" dir] "Use the emacs config at DIR (e.g. ~/.emacs.d)")
|
||||
(doomdir ["--doomdir" dir] "Use the private module at DIR (e.g. ~/.doom.d)")
|
||||
(localdir ["--localdir" dir] "Use DIR as your local storage directory")
|
||||
&optional command &rest args)
|
||||
"A command line interface for managing Doom Emacs.
|
||||
|
||||
(unless (file-directory-p user-emacs-directory)
|
||||
(error "%s does not exist" user-emacs-directory))
|
||||
Includes package management, diagnostics, unit tests, and byte-compilation.
|
||||
|
||||
;; Bootstrap Doom
|
||||
(if (not noninteractive)
|
||||
(let ((doom-interactive-mode t))
|
||||
(load (expand-file-name "init.el" user-emacs-directory)
|
||||
nil 'nomessage)
|
||||
(doom-run-all-startup-hooks-h))
|
||||
(load (expand-file-name "core/core.el" user-emacs-directory)
|
||||
nil 'nomessage)
|
||||
(doom-initialize 'force-p)
|
||||
(doom-initialize-modules)
|
||||
This tool also makes it trivial to launch Emacs out of a different folder or
|
||||
with a different private module."
|
||||
:bare t
|
||||
(when emacsdir
|
||||
(setq user-emacs-directory (file-name-as-directory emacsdir))
|
||||
(print! (info "EMACSDIR=%s") localdir))
|
||||
(when doomdir
|
||||
(setenv "DOOMDIR" doomdir)
|
||||
(print! (info "DOOMDIR=%s") localdir))
|
||||
(when localdir
|
||||
(setenv "DOOMLOCALDIR" localdir)
|
||||
(print! (info "DOOMLOCALDIR=%s") localdir))
|
||||
(when debug-p
|
||||
(setenv "DEBUG" "1")
|
||||
(setq doom-debug-mode t)
|
||||
(print! (info "Debug mode on")))
|
||||
(when yes-p
|
||||
(setenv "YES" "1")
|
||||
(setq doom-auto-accept t)
|
||||
(print! (info "Auto-yes on")))
|
||||
(when help-p
|
||||
(push command args)
|
||||
(setq command "help"))
|
||||
|
||||
(cond ((or (not args)
|
||||
(and (not (cdr args))
|
||||
(member (car args) '("help" "h"))))
|
||||
(unless args
|
||||
(print! (error "No command detected.\n")))
|
||||
(usage))
|
||||
((require 'core-cli)
|
||||
(setq argv nil)
|
||||
(condition-case e
|
||||
(doom-dispatch (car args) (cdr args))
|
||||
;; Reload core in case any of the directories were changed.
|
||||
(when (or emacsdir doomdir localdir)
|
||||
(load! "core/core.el" user-emacs-directory))
|
||||
|
||||
(cond ((not noninteractive)
|
||||
(print! "Doom launched out of %s (test mode)" (path user-emacs-directory))
|
||||
(load! "init.el" user-emacs-directory)
|
||||
(doom-run-all-startup-hooks-h))
|
||||
|
||||
((null command)
|
||||
(doom-cli-execute "help"))
|
||||
|
||||
((condition-case e
|
||||
(let ((start-time (current-time)))
|
||||
(and (doom-cli-execute command args)
|
||||
(terpri)
|
||||
(print! (success "Finished! (%.4fs)")
|
||||
(float-time
|
||||
(time-subtract (current-time)
|
||||
start-time)))))
|
||||
(user-error
|
||||
(print! (error "%s\n") (error-message-string e))
|
||||
(print! (yellow "See 'doom help %s' for documentation on this command.") (car args)))
|
||||
|
@ -116,5 +90,8 @@
|
|||
"report, please include it!\n\n"
|
||||
"Emacs outputs to standard error, so you'll need to redirect stderr to\n"
|
||||
"stdout to pipe this to a file or clipboard!\n\n"
|
||||
" e.g. doom -d install 2>&1 | clipboard-program"))
|
||||
(signal 'doom-error e))))))))
|
||||
" e.g. doom -d install 2>&1 | clipboard-program\n"))
|
||||
(signal 'doom-error e)))))))
|
||||
|
||||
(doom-cli-execute :main (cdr (member "--" argv)))
|
||||
(setq argv nil))
|
||||
|
|
257
bin/doom-doctor
257
bin/doom-doctor
|
@ -1,257 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
":"; command -v emacs >/dev/null || { >&2 echo "Emacs isn't installed"; exit 1; } # -*-emacs-lisp-*-
|
||||
":"; VERSION=$(emacs --version | head -n1)
|
||||
":"; case $VERSION in *\ 2[0-2].[0-1].[0-9]) echo "You're running $VERSION"; echo "That version is too old to run the doctor (25.3 minimum). Check your PATH"; echo; exit 2 ;; esac
|
||||
":"; exec emacs --quick --script "$0"; exit 0
|
||||
|
||||
;; The Doom doctor is essentially one big, self-contained elisp shell script
|
||||
;; that uses a series of simple heuristics to diagnose common issues on your
|
||||
;; system. Issues that could intefere with Doom Emacs.
|
||||
;;
|
||||
;; Doom modules may optionally have a doctor.el file to run their own heuristics
|
||||
;; in. Doctor scripts may run in versions of Emacs as old as Emacs 23, so make
|
||||
;; no assumptions about what's available in the standard library (e.g. avoid
|
||||
;; cl/cl-lib, subr-x, map, seq, etc).
|
||||
|
||||
|
||||
;; Ensure Doom doctor always runs out of the current Emacs directory (optionally
|
||||
;; specified by the EMACSDIR envvar)
|
||||
(setq user-emacs-directory
|
||||
(or (getenv "EMACSDIR")
|
||||
(expand-file-name "../" (file-name-directory (file-truename load-file-name))))
|
||||
default-directory user-emacs-directory)
|
||||
|
||||
(unless (file-directory-p user-emacs-directory)
|
||||
(error "Couldn't find a Doom config!"))
|
||||
(unless noninteractive
|
||||
(error "This script must not be run from an interactive session."))
|
||||
(when (getenv "DEBUG")
|
||||
(setq debug-on-error t))
|
||||
|
||||
(require 'subr-x)
|
||||
(require 'pp)
|
||||
(load (expand-file-name "core/autoload/format" user-emacs-directory) nil t)
|
||||
|
||||
|
||||
(defvar doom-init-p nil)
|
||||
(defvar doom-warnings 0)
|
||||
(defvar doom-errors 0)
|
||||
|
||||
|
||||
;;; Helpers
|
||||
|
||||
(defun sh (cmd &rest args)
|
||||
(ignore-errors
|
||||
(string-trim-right
|
||||
(shell-command-to-string (if args (apply #'format cmd args) cmd)))))
|
||||
|
||||
(defun elc-check-dir (dir)
|
||||
(dolist (file (directory-files-recursively dir "\\.elc$"))
|
||||
(when (file-newer-than-file-p (concat (file-name-sans-extension file) ".el")
|
||||
file)
|
||||
(warn! "%s is out-of-date" (abbreviate-file-name file)))))
|
||||
|
||||
(defmacro assert! (condition message &rest args)
|
||||
`(unless ,condition
|
||||
(error! ,message ,@args)))
|
||||
|
||||
|
||||
;;; Logging
|
||||
|
||||
(defvar indent 0)
|
||||
(defvar prefix "")
|
||||
|
||||
(defmacro msg! (msg &rest args)
|
||||
`(print!
|
||||
(indent indent
|
||||
(format (concat prefix ,msg)
|
||||
,@args))))
|
||||
|
||||
(defmacro error! (&rest args)
|
||||
`(progn (msg! (red ,@args))
|
||||
(setq doom-errors (+ doom-errors 1))))
|
||||
(defmacro warn! (&rest args)
|
||||
`(progn (msg! (yellow ,@args))
|
||||
(setq doom-warnings (+ doom-warnings 1))))
|
||||
(defmacro success! (&rest args) `(msg! (green ,@args)))
|
||||
(defmacro section! (&rest args) `(msg! (bold (blue ,@args))))
|
||||
|
||||
(defmacro explain! (&rest args)
|
||||
`(msg! (indent (+ indent 2) (autofill ,@args))))
|
||||
|
||||
|
||||
;;; Polyfills
|
||||
;; early versions of emacs won't have this
|
||||
(unless (fboundp 'string-match-p)
|
||||
(defun string-match-p (regexp string &optional start)
|
||||
(save-match-data
|
||||
(string-match regexp string &optional start))))
|
||||
|
||||
;; subr-x don't exist in older versions of Emacs
|
||||
(unless (fboundp 'string-trim-right)
|
||||
(defsubst string-trim-right (string &optional regexp)
|
||||
(if (string-match (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'") string)
|
||||
(replace-match "" t t string)
|
||||
string)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Basic diagnostics
|
||||
|
||||
(msg! (bold "Doom Doctor"))
|
||||
(msg! "Emacs v%s" emacs-version)
|
||||
(msg! "Doom v%s (%s)"
|
||||
(or (let ((core-file (expand-file-name "core/core.el" user-emacs-directory)))
|
||||
(and (file-exists-p core-file)
|
||||
(ignore-errors
|
||||
(with-temp-buffer
|
||||
(insert-file-contents-literally core-file)
|
||||
(goto-char (point-min))
|
||||
(when (search-forward "doom-version" nil t)
|
||||
(forward-char)
|
||||
(sexp-at-point))))))
|
||||
"???")
|
||||
(if (and (executable-find "git")
|
||||
(file-directory-p (expand-file-name ".git" user-emacs-directory)))
|
||||
(sh "git log -1 --format=\"%D %h %ci\"")
|
||||
"n/a"))
|
||||
(msg! "shell: %s%s"
|
||||
(getenv "SHELL")
|
||||
(if (equal (getenv "SHELL") (sh "echo $SHELL"))
|
||||
""
|
||||
(red " (mismatch)")))
|
||||
(when (boundp 'system-configuration-features)
|
||||
(msg! "Compiled with:\n%s" (indent 2 system-configuration-features)))
|
||||
(msg! "uname -msrv:\n%s\n" (indent 2 (sh "uname -msrv")))
|
||||
|
||||
|
||||
;;
|
||||
;;; Check if Emacs is set up correctly
|
||||
|
||||
(section! "Checking Emacs")
|
||||
(let ((indent 2))
|
||||
(section! "Checking your Emacs version is 25.3 or newer...")
|
||||
(when (version< emacs-version "25.3")
|
||||
(error! "Important: Emacs %s detected [%s]" emacs-version (executable-find "emacs"))
|
||||
(explain!
|
||||
"DOOM only supports >= 25.3. Perhaps your PATH wasn't set up properly."
|
||||
(when (eq system-type 'darwin)
|
||||
(concat "\nMacOS users should use homebrew (https://brew.sh) to install Emacs\n"
|
||||
" brew install emacs --with-modules --with-imagemagick --with-cocoa"))))
|
||||
|
||||
(section! "Checking for Emacs config conflicts...")
|
||||
(when (file-exists-p "~/.emacs")
|
||||
(warn! "Detected an ~/.emacs file, which may prevent Doom from loading")
|
||||
(explain! "If Emacs finds an ~/.emacs file, it will ignore ~/.emacs.d, where Doom is "
|
||||
"typically installed. If you're seeing a vanilla Emacs splash screen, this "
|
||||
"may explain why. If you use Chemacs, you may ignore this warning."))
|
||||
|
||||
(section! "Checking for private config conflicts...")
|
||||
(let ((xdg-dir (concat (or (getenv "XDG_CONFIG_HOME")
|
||||
"~/.config")
|
||||
"/doom/"))
|
||||
(doom-dir (or (getenv "DOOMDIR")
|
||||
"~/.doom.d/")))
|
||||
(when (and (not (file-equal-p xdg-dir doom-dir))
|
||||
(file-directory-p xdg-dir)
|
||||
(file-directory-p doom-dir))
|
||||
(warn! "Detected two private configs, in %s and %s"
|
||||
(abbreviate-file-name xdg-dir)
|
||||
doom-dir)
|
||||
(explain! "The second directory will be ignored, as it has lower precedence.")))
|
||||
|
||||
(section! "Checking for stale elc files...")
|
||||
(elc-check-dir user-emacs-directory))
|
||||
|
||||
|
||||
;;
|
||||
;;; Check if system environment is set up correctly
|
||||
|
||||
(section! "Checking your system...")
|
||||
(let ((indent 2))
|
||||
;; on windows?
|
||||
(when (memq system-type '(windows-nt ms-dos cygwin))
|
||||
(warn! "Warning: Windows detected")
|
||||
(explain! "DOOM was designed for MacOS and Linux. Expect a bumpy ride!")))
|
||||
|
||||
|
||||
;;
|
||||
;;; Check if Doom Emacs is set up correctly
|
||||
|
||||
(condition-case-unless-debug ex
|
||||
(let ((after-init-time (current-time))
|
||||
(doom-format-backend 'ansi)
|
||||
noninteractive)
|
||||
(section! "Checking DOOM Emacs...")
|
||||
(load (concat user-emacs-directory "core/core.el") nil t)
|
||||
(unless (file-directory-p doom-private-dir)
|
||||
(error "No DOOMDIR was found, did you run `doom install` yet?"))
|
||||
|
||||
(let ((indent 2))
|
||||
;; Make sure Doom is initialized and loaded
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-core)
|
||||
(success! "Initialized Doom Emacs %s" doom-version)
|
||||
|
||||
(doom-initialize-modules)
|
||||
(if (hash-table-p doom-modules)
|
||||
(success! "Initialized %d modules" (hash-table-count doom-modules))
|
||||
(warn! "Failed to load any modules. Do you have an private init.el?"))
|
||||
|
||||
(doom-initialize-packages)
|
||||
(success! "Initialized %d packages" (length doom-packages))
|
||||
|
||||
(section! "Checking Doom core for irregularities...")
|
||||
(let ((indent (+ indent 2)))
|
||||
(load (expand-file-name "doctor.el" doom-core-dir) nil 'nomessage))
|
||||
|
||||
(section! "Checking for stale elc files in your DOOMDIR...")
|
||||
(when (file-directory-p doom-private-dir)
|
||||
(let ((indent (+ indent 2)))
|
||||
(elc-check-dir doom-private-dir)))
|
||||
|
||||
(when doom-modules
|
||||
(section! "Checking your enabled modules...")
|
||||
(let ((indent (+ indent 2)))
|
||||
(advice-add #'require :around #'doom-shut-up-a)
|
||||
(maphash
|
||||
(lambda (key plist)
|
||||
(let ((prefix (format! (bold "(%s %s) " (car key) (cdr key)))))
|
||||
(condition-case-unless-debug ex
|
||||
(let ((doctor-file (doom-module-path (car key) (cdr key) "doctor.el"))
|
||||
(packages-file (doom-module-path (car key) (cdr key) "packages.el")))
|
||||
(cl-loop for name in (let (doom-packages
|
||||
doom-disabled-packages)
|
||||
(load packages-file 'noerror 'nomessage)
|
||||
(mapcar #'car doom-packages))
|
||||
unless (or (doom-package-get name :disable)
|
||||
(eval (doom-package-get name :ignore))
|
||||
(doom-package-built-in-p name)
|
||||
(doom-package-installed-p name))
|
||||
do (error! "%s is not installed" name))
|
||||
(load doctor-file 'noerror 'nomessage))
|
||||
(file-missing (error! "%s" (error-message-string ex)))
|
||||
(error (error! "Syntax error: %s" ex)))))
|
||||
doom-modules)))))
|
||||
(error
|
||||
(warn! "Attempt to load DOOM failed\n %s\n"
|
||||
(or (cdr-safe ex) (car ex)))
|
||||
(setq doom-modules nil)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Final report
|
||||
|
||||
(message "")
|
||||
(dolist (msg (list (list doom-errors "error" 'red)
|
||||
(list doom-warnings "warning" 'yellow)))
|
||||
(when (> (car msg) 0)
|
||||
(msg! (color (nth 2 msg)
|
||||
(if (= (car msg) 1)
|
||||
"There is %d %s!"
|
||||
"There are %d %ss!")
|
||||
(car msg) (nth 1 msg)))))
|
||||
|
||||
(when (and (zerop doom-errors)
|
||||
(zerop doom-warnings))
|
||||
(success! "Everything seems fine, happy Emacs'ing!"))
|
|
@ -289,6 +289,7 @@ belong to the current project."
|
|||
(when (memq (current-buffer) buffer-list)
|
||||
(switch-to-buffer (doom-fallback-buffer)))
|
||||
(mapc #'doom-kill-buffer-and-windows buffer-list)
|
||||
(delete-other-windows)
|
||||
(when interactive
|
||||
(message "Killed %s buffers"
|
||||
(- (length buffer-list)
|
||||
|
|
|
@ -124,89 +124,3 @@ Warning: freezes indefinitely on any stdin prompt."
|
|||
(sit-for 0.1))
|
||||
(process-exit-status process))
|
||||
(string-trim (buffer-string)))))
|
||||
|
||||
(defun doom--cli-normalize (args specs)
|
||||
(let* ((args (cl-remove-if-not #'stringp args))
|
||||
(optspec (cl-remove-if-not #'listp specs))
|
||||
(argspec (cl-remove-if #'listp specs))
|
||||
(options (mapcar #'list (mapcar #'car-safe optspec)))
|
||||
extra
|
||||
arguments)
|
||||
(dolist (spec optspec)
|
||||
(setf (nth 1 spec) (doom-enlist (nth 1 spec))))
|
||||
(while args
|
||||
(let ((arg (pop args)))
|
||||
(cl-check-type arg string)
|
||||
(if (not (string-prefix-p "-" arg))
|
||||
(push arg arguments)
|
||||
(if-let (specs (cl-remove-if-not
|
||||
(if (string-prefix-p "--" arg)
|
||||
(doom-partial #'member arg)
|
||||
(lambda (flags)
|
||||
(cl-loop for switch in (split-string (string-remove-prefix "-" arg) "" t)
|
||||
if (member (concat "-" switch) flags)
|
||||
return t)))
|
||||
optspec
|
||||
:key #'cadr))
|
||||
(pcase-dolist (`(,sym ,flags ,type) specs)
|
||||
(setf (alist-get sym options)
|
||||
(list
|
||||
(let ((value (if type (pop args))))
|
||||
(pcase type
|
||||
(`&string value)
|
||||
(`&int `(truncate (read ,value)))
|
||||
(`&float `(float (read ,value)))
|
||||
(`&path `(expand-file-name ,value))
|
||||
(`&directory
|
||||
`(let ((path (expand-file-name ,value)))
|
||||
(unless (file-directory-p path)
|
||||
(error "Directory does not exist: %s" path))
|
||||
path))
|
||||
(`&file
|
||||
`(let ((path (expand-file-name ,value)))
|
||||
(unless (file-exists-p path)
|
||||
(error "File does not exist: %s" path))
|
||||
path))
|
||||
(`&sexp `(read ,value))
|
||||
((or `nil `t) arg)
|
||||
(_ (error "Not a valid type: %S" type)))))))
|
||||
(push arg extra)))))
|
||||
(list optspec (nreverse options)
|
||||
argspec (nreverse arguments))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cli-getopts (args specs)
|
||||
"TODO"
|
||||
(cl-destructuring-bind (optspec options argspec arguments)
|
||||
(doom--cli-normalize args specs)
|
||||
(let ((i 0)
|
||||
optional-p
|
||||
noerror-p)
|
||||
(cl-dolist (spec argspec)
|
||||
(cond ((eq spec '&rest)
|
||||
(push (list (cadr (member '&rest specs))
|
||||
`(quote
|
||||
,(reverse
|
||||
(butlast (reverse arguments) i))))
|
||||
options)
|
||||
(cl-return))
|
||||
((eq spec '&all)
|
||||
(push (list (cadr (member '&all specs))
|
||||
`(quote ,args))
|
||||
options))
|
||||
((eq spec '&noerror) (setq noerror-p t))
|
||||
((eq spec '&optional) (setq optional-p t))
|
||||
((and (>= i (length arguments)) (not optional-p))
|
||||
(signal 'wrong-number-of-arguments
|
||||
(list argspec (length arguments))))
|
||||
((push (list spec (nth i arguments)) options)
|
||||
(cl-incf i)))))
|
||||
(nreverse options)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro let-cliopts! (args spec &rest body)
|
||||
"Run BODY with command line ARGS parsed according to SPEC."
|
||||
(declare (indent 2))
|
||||
`(eval (append (list 'let (doom-cli-getopts ,args ',spec))
|
||||
(quote ,body))
|
||||
t))
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
emacs -Q -l init.el -f doom-run-all-startup-hooks-h"
|
||||
(run-hook-wrapped 'after-init-hook #'doom-try-run-hook)
|
||||
(setq after-init-time (current-time))
|
||||
(dolist (hook (list 'delayed-warnings-hook
|
||||
'emacs-startup-hook 'term-setup-hook
|
||||
'window-setup-hook))
|
||||
(run-hook-wrapped hook #'doom-try-run-hook)))
|
||||
(mapc (doom-rpartial #'run-hook-wrapped #'doom-try-run-hook)
|
||||
(list 'delayed-warnings-hook
|
||||
'emacs-startup-hook 'tty-setup-hook
|
||||
'window-setup-hook)))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -32,9 +32,8 @@ ready to be pasted in a bug report on github."
|
|||
(doom-modules (doom-modules)))
|
||||
(cl-letf
|
||||
(((symbol-function 'sh)
|
||||
(lambda (format)
|
||||
(string-trim
|
||||
(shell-command-to-string format)))))
|
||||
(lambda (&rest args)
|
||||
(cdr (apply #'doom-call-process args)))))
|
||||
`((emacs
|
||||
(version . ,emacs-version)
|
||||
(features ,@system-configuration-features)
|
||||
|
@ -47,14 +46,14 @@ ready to be pasted in a bug report on github."
|
|||
'server-running))))
|
||||
(doom
|
||||
(version . ,doom-version)
|
||||
(build . ,(sh "git log -1 --format=\"%D %h %ci\"")))
|
||||
(build . ,(sh "git" "log" "-1" "--format=%D %h %ci")))
|
||||
(system
|
||||
(type . ,system-type)
|
||||
(config . ,system-configuration)
|
||||
(shell . ,shell-file-name)
|
||||
(uname . ,(if IS-WINDOWS
|
||||
"n/a"
|
||||
(sh "uname -msrv")))
|
||||
(sh "uname" "-msrv")))
|
||||
(path . ,(mapcar #'abbreviate-file-name exec-path)))
|
||||
(config
|
||||
(envfile
|
||||
|
@ -117,7 +116,7 @@ branch and commit."
|
|||
"n/a")
|
||||
(or (vc-git-working-revision doom-core-dir)
|
||||
"n/a")
|
||||
(or (string-trim (shell-command-to-string "git log -1 --format=%ci"))
|
||||
(or (cdr (doom-call-process "git" "log" "-1" "--format=%ci"))
|
||||
"n/a"))))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -302,34 +301,6 @@ to reproduce bugs and determine if Doom is to blame."
|
|||
;;
|
||||
;;; Reporting bugs
|
||||
|
||||
(defun doom--report-bug ()
|
||||
"TODO"
|
||||
(interactive)
|
||||
(let ((url "https://github.com/hlissner/doom-emacs/issues/new?body="))
|
||||
;; TODO Refactor me
|
||||
(save-restriction
|
||||
(widen)
|
||||
(goto-char (point-min))
|
||||
(re-search-forward "^-------------------------------------------------------------------\n" nil t)
|
||||
(skip-chars-forward " \n\t")
|
||||
(condition-case e
|
||||
(progn
|
||||
(save-excursion
|
||||
(when (and (re-search-backward "\\+ [ ] " nil t)
|
||||
(not (y-or-n-p "You haven't checked all the boxes. Continue anyway?")))
|
||||
(error "Aborted submit")))
|
||||
(narrow-to-region (point) (point-max))
|
||||
(let ((text (buffer-string)))
|
||||
;; `url-encode-url' doesn't encode ampersands
|
||||
(setq text (replace-regexp-in-string "&" "%26" text))
|
||||
(setq url (url-encode-url (concat url text)))
|
||||
;; HACK: encode some characters according to HTML URL Encoding Reference
|
||||
;; http://www.w3schools.com/tags/ref_urlencode.asp
|
||||
(setq url (replace-regexp-in-string "#" "%23" url))
|
||||
(setq url (replace-regexp-in-string ";" "%3B" url))
|
||||
(browse-url url)))
|
||||
(error (signal (car e) (car e)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/report-bug ()
|
||||
"Open a markdown buffer destinated to populate the New Issue page on Doom
|
||||
|
@ -338,36 +309,7 @@ Emacs' issue tracker.
|
|||
If called when a backtrace buffer is present, it and the output of `doom-info'
|
||||
will be automatically appended to the result."
|
||||
(interactive)
|
||||
;; TODO Refactor me
|
||||
(let ((backtrace
|
||||
(when (get-buffer "*Backtrace*")
|
||||
(with-current-buffer "*Backtrace*"
|
||||
(string-trim
|
||||
(buffer-substring-no-properties
|
||||
(point-min)
|
||||
(min (point-max) 1000))))))
|
||||
(buf (get-buffer-create "*doom:sandbox*")))
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
(condition-case _ (gfm-mode)
|
||||
(error (text-mode)))
|
||||
(doom-template-insert "SUBMIT_BUG_REPORT")
|
||||
(goto-char (point-max))
|
||||
(let ((pos (point)))
|
||||
(save-excursion
|
||||
(insert
|
||||
"\n" (doom-info) "\n"
|
||||
(if (and backtrace (not (string-empty-p backtrace)))
|
||||
(format "\n<details>\n<summary>Backtrace</summary>\n\n```\n%s\n```\n</details>\n"
|
||||
backtrace)
|
||||
"")))
|
||||
(local-set-key (kbd "C-c C-c") #'doom--report-bug)
|
||||
(local-set-key (kbd "C-c C-k") #'kill-current-buffer)
|
||||
(setq header-line-format "C-c C-c to submit / C-c C-k to close")
|
||||
;;
|
||||
(narrow-to-region (point-min) pos)
|
||||
(goto-char (point-min)))
|
||||
(pop-to-buffer buf))))
|
||||
(browse-url "https://github.com/hlissner/doom-emacs/issues/new/choose"))
|
||||
|
||||
|
||||
;;
|
||||
|
|
|
@ -169,8 +169,10 @@ single file or nested compound statement of `and' and `or' statements."
|
|||
|
||||
;;;###autoload
|
||||
(defun doom-file-size (file &optional dir)
|
||||
"Returns the size of FILE (in DIR) in kilobytes."
|
||||
(when-let (file (file-exists-p! file dir))
|
||||
"Returns the size of FILE (in DIR) in bytes."
|
||||
(let ((file (expand-file-name file dir)))
|
||||
(unless (file-exists-p file)
|
||||
(error "Couldn't find file %S" file))
|
||||
(unless (file-readable-p file)
|
||||
(error "File %S is unreadable; can't acquire its filesize"
|
||||
file))
|
||||
|
@ -179,6 +181,8 @@ single file or nested compound statement of `and' and `or' statements."
|
|||
;;;###autoload
|
||||
(defun doom-directory-size (dir)
|
||||
"Returns the size of FILE (in DIR) in kilobytes."
|
||||
(unless (file-directory-p dir)
|
||||
(error "Directory %S does not exist" dir))
|
||||
(if (executable-find "du")
|
||||
(/ (string-to-number (cdr (doom-call-process "du" "-sb" dir)))
|
||||
1024.0)
|
||||
|
@ -313,18 +317,26 @@ file if it exists, without confirmation."
|
|||
(`aborted (message "Aborted"))
|
||||
(_ t)))
|
||||
|
||||
(defun doom--sudo-file (file)
|
||||
(let ((host (or (file-remote-p file 'host) "localhost")))
|
||||
(concat "/" (when (file-remote-p file)
|
||||
(concat (file-remote-p file 'method) ":"
|
||||
(if-let (user (file-remote-p file 'user))
|
||||
(concat user "@" host)
|
||||
host)
|
||||
"|"))
|
||||
"sudo:root@" host
|
||||
":" (or (file-remote-p file 'localname)
|
||||
file))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/sudo-find-file (file)
|
||||
"Open FILE as root."
|
||||
(interactive "FOpen file as root: ")
|
||||
(when (file-writable-p file)
|
||||
(user-error "File is user writeable, aborting sudo"))
|
||||
(find-file (if (file-remote-p file)
|
||||
(concat "/" (file-remote-p file 'method) ":" (file-remote-p file 'user) "@" (file-remote-p file 'host) "|sudo:root@" (file-remote-p file 'host) ":" (file-remote-p file 'localname))
|
||||
(concat "/sudo:root@localhost:" file))))
|
||||
(find-file (doom--sudo-file file)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/sudo-this-file ()
|
||||
"Open the current file as root."
|
||||
(interactive)
|
||||
(doom/sudo-find-file (file-truename buffer-file-name)))
|
||||
(find-alternate-file (doom--sudo-file buffer-file-name)))
|
||||
|
|
|
@ -395,13 +395,15 @@ current file is in, or d) the module associated with the current major mode (see
|
|||
(message "Couldn't find the config block"))))))))
|
||||
|
||||
(defun doom--help-package-configs (package)
|
||||
;; TODO Add git checks, in case ~/.emacs.d isn't a git repo
|
||||
(let ((default-directory doom-emacs-dir))
|
||||
;; TODO Use ripgrep instead
|
||||
(split-string
|
||||
(shell-command-to-string
|
||||
(format "git grep --no-break --no-heading --line-number '%s %s\\($\\| \\)' ':(exclude)*.org'"
|
||||
"\\(^;;;###package\\|(after!\\|(use-package!\\)"
|
||||
package))
|
||||
(cdr (doom-call-process
|
||||
"git" "grep" "--no-break" "--no-heading" "--line-number"
|
||||
(format "%s %s\\($\\| \\)"
|
||||
"\\(^;;;###package\\|(after!\\|(use-package!\\)"
|
||||
package)
|
||||
":(exclude)*.org"))
|
||||
"\n" t)))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -463,8 +465,8 @@ If prefix arg is present, refresh the cache."
|
|||
(`straight
|
||||
(format! "Straight (%s)\n%s"
|
||||
(let ((default-directory (straight--build-dir (symbol-name package))))
|
||||
(string-trim
|
||||
(shell-command-to-string "git log -1 --format=\"%D %h %ci\"")))
|
||||
(cdr
|
||||
(doom-call-process "git" "log" "-1" "--format=%D %h %ci")))
|
||||
(indent
|
||||
13 (string-trim
|
||||
(pp-to-string
|
||||
|
@ -608,18 +610,12 @@ Uses the symbol at point or the current selection, if available."
|
|||
(list (read-string
|
||||
(format "Search load-path (default: %s): " query)
|
||||
nil 'git-grep query))))
|
||||
;; REVIEW Replace with deadgrep or ivy/helm interface when we drop ag/git-grep
|
||||
;; support later
|
||||
;; REVIEW Replace with deadgrep
|
||||
(grep-find
|
||||
(mapconcat
|
||||
#'shell-quote-argument
|
||||
(cond ((executable-find "rg")
|
||||
`("rg" "-L" "--search-zip" "--no-heading" "--color=never"
|
||||
,query ,@(cl-remove-if-not #'file-directory-p load-path)))
|
||||
((executable-find "ag")
|
||||
`("ag" "--search-zip" "--nogroup" "--nocolor"
|
||||
,query ,@(cl-remove-if-not #'file-directory-p load-path)))
|
||||
((user-error "This command requires ripgrep or the_silver_searcher to be installed on your system")))
|
||||
(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
|
||||
|
@ -637,18 +633,13 @@ Uses the symbol at point or the current selection, if available."
|
|||
(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 or ivy/helm interface when we drop ag/git-grep
|
||||
;; support later
|
||||
;; REVIEW Replace with deadgrep
|
||||
(grep-find
|
||||
(mapconcat
|
||||
#'shell-quote-argument
|
||||
(let ((search (elisp-refs--loaded-paths)))
|
||||
(cond ((executable-find "rg")
|
||||
`("rg" "-L" "--search-zip" "--no-heading" "--color=never"
|
||||
,query ,@(cl-remove-if-not #'file-directory-p search)))
|
||||
((executable-find "ag")
|
||||
`("ag" "--search-zip" "--nogroup" "--nocolor"
|
||||
,query ,@(cl-remove-if-not #'file-directory-p search)))
|
||||
((user-error "This command requires ripgrep or the_silver_searcher to be installed on your system"))))
|
||||
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never" query)
|
||||
(cl-remove-if-not #'file-directory-p (elisp-refs--loaded-paths)))
|
||||
" ")))
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
;;; core/autoload/line-numbers.el -*- lexical-binding: t; -*-
|
||||
;;;###if (version< emacs-version "26.1")
|
||||
|
||||
;; DEPRECATED This was lifted out of the display-line-numbers library in Emacs
|
||||
;; 26.1 and modified to use nlinum for Emacs 25.x users. It should be removed
|
||||
;; should Emacs 25 support be removed.
|
||||
|
||||
;;;###autoload
|
||||
(defvar display-line-numbers t
|
||||
"Non-nil means display line numbers.
|
||||
|
||||
If the value is t, display the absolute number of each line of a buffer
|
||||
shown in a window. Absolute line numbers count from the beginning of
|
||||
the current narrowing, or from buffer beginning. If the value is
|
||||
relative, display for each line not containing the window's point its
|
||||
relative number instead, i.e. the number of the line relative to the
|
||||
line showing the window's point.
|
||||
|
||||
In either case, line numbers are displayed at the beginning of each
|
||||
non-continuation line that displays buffer text, i.e. after each newline
|
||||
character that comes from the buffer. The value visual is like
|
||||
relative but counts screen lines instead of buffer lines. In practice
|
||||
this means that continuation lines count as well when calculating the
|
||||
relative number of a line.
|
||||
|
||||
Lisp programs can disable display of a line number of a particular
|
||||
buffer line by putting the display-line-numbers-disable text property
|
||||
or overlay property on the first visible character of that line.")
|
||||
|
||||
(defgroup display-line-numbers nil "Display line number preferences"
|
||||
:group 'emacs)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom display-line-numbers-type t
|
||||
"The default type of line numbers to use in `display-line-numbers-mode'.
|
||||
See `display-line-numbers' for value options."
|
||||
:type '(choice (const :tag "Relative line numbers" relative)
|
||||
(const :tag "Relative visual line numbers" visual)
|
||||
(other :tag "Absolute line numbers" t)))
|
||||
|
||||
;;;###autoload
|
||||
(defcustom display-line-numbers-grow-only nil
|
||||
"If non-nil, do not shrink line number width."
|
||||
:type 'boolean)
|
||||
|
||||
;;;###autoload
|
||||
(defcustom display-line-numbers-width-start nil
|
||||
"If non-nil, count number of lines to use for line number width.
|
||||
When `display-line-numbers-mode' is turned on,
|
||||
`display-line-numbers-width' is set to the minimum width necessary
|
||||
to display all line numbers in the buffer."
|
||||
:type 'boolean)
|
||||
|
||||
;;;###autoload
|
||||
(defun line-number-display-width (&optional _)
|
||||
"Return the width used for displaying line numbers in the
|
||||
selected window."
|
||||
(length (save-excursion (goto-char (point-max))
|
||||
(format-mode-line "%l"))))
|
||||
|
||||
(defun display-line-numbers-update-width ()
|
||||
"Prevent the line number width from shrinking."
|
||||
(let ((width (line-number-display-width)))
|
||||
(when (> width (or display-line-numbers-width 1))
|
||||
(setq display-line-numbers-width width))))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode display-line-numbers-mode
|
||||
"Toggle display of line numbers in the buffer.
|
||||
This uses `display-line-numbers' internally.
|
||||
|
||||
To change the type of line numbers displayed by default,
|
||||
customize `display-line-numbers-type'. To change the type while
|
||||
the mode is on, set `display-line-numbers' directly."
|
||||
:lighter nil
|
||||
(cond ((null display-line-numbers-type))
|
||||
((eq display-line-numbers-type 'relative)
|
||||
(if display-line-numbers-mode
|
||||
(nlinum-relative-off)
|
||||
(nlinum-relative-on)))
|
||||
((nlinum-mode (if display-line-numbers-mode +1 -1)))))
|
||||
|
||||
(defun display-line-numbers--turn-on ()
|
||||
"Turn on `display-line-numbers-mode'."
|
||||
(unless (or (minibufferp)
|
||||
;; taken from linum.el
|
||||
(and (daemonp) (null (frame-parameter nil 'client))))
|
||||
(display-line-numbers-mode)))
|
||||
|
||||
;;;###autoload
|
||||
(define-globalized-minor-mode global-display-line-numbers-mode
|
||||
display-line-numbers-mode display-line-numbers--turn-on)
|
|
@ -81,7 +81,7 @@
|
|||
|
||||
Excludes packages that have a non-nil :built-in property."
|
||||
(when-let (plist (doom-package-get package))
|
||||
(not (plist-get plist :ignore) t)))
|
||||
(not (plist-get plist :ignore))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-private-p (package)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
Evaluate BODY with either ARGLIST bound to (cons PROP VAL) or, if ARGLIST is a
|
||||
list, the pair is destructured into (CAR . CDR)."
|
||||
(declare (indent defun))
|
||||
(declare (indent 1))
|
||||
(let ((plist-var (make-symbol "plist")))
|
||||
`(let ((,plist-var (copy-sequence ,plist)))
|
||||
(while ,plist-var
|
||||
|
|
|
@ -117,8 +117,7 @@ If DIR is not a project, it will be indexed (but not cached)."
|
|||
#'projectile-find-file)))
|
||||
((fboundp 'counsel-file-jump) ; ivy only
|
||||
(call-interactively #'counsel-file-jump))
|
||||
((and (fboundp 'project-find-file-in) ; emacs 26.1+ only
|
||||
(project-current))
|
||||
((project-current)
|
||||
(project-find-file-in nil (list default-directory) nil))
|
||||
((fboundp 'helm-find-files)
|
||||
(call-interactively #'helm-find-files))
|
||||
|
|
|
@ -72,21 +72,14 @@ visual-line-mode is on, this skips relative and uses visual instead.
|
|||
See `display-line-numbers' for what these values mean."
|
||||
(interactive)
|
||||
(defvar doom--line-number-style display-line-numbers-type)
|
||||
;; DEPRECATED
|
||||
(let* ((styles `(t ,(if (and EMACS26+ visual-line-mode) 'visual 'relative) nil))
|
||||
(let* ((styles `(t ,(if visual-line-mode 'visual 'relative) nil))
|
||||
(order (cons display-line-numbers-type (remq display-line-numbers-type styles)))
|
||||
(queue (memq doom--line-number-style order))
|
||||
(next (if (= (length queue) 1)
|
||||
(car order)
|
||||
(car (cdr queue)))))
|
||||
(setq doom--line-number-style next)
|
||||
;; DEPRECATED
|
||||
(if EMACS26+
|
||||
(setq display-line-numbers next)
|
||||
(pcase next
|
||||
(`t (nlinum-relative-off) (nlinum-mode +1))
|
||||
(`relative (nlinum-relative-on))
|
||||
(`nil (nlinum-mode -1))))
|
||||
(setq display-line-numbers next)
|
||||
(message "Switched to %s line numbers"
|
||||
(pcase next
|
||||
(`t "normal")
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
;;; core/cli/autoloads.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'autoload)
|
||||
|
||||
|
||||
(defvar doom-autoload-excluded-packages '("gh")
|
||||
"Packages that have silly or destructive autoload files that try to load
|
||||
everyone in the universe and their dog, causing errors that make babies cry. No
|
||||
one wants that.")
|
||||
|
||||
;; external variables
|
||||
;; externs
|
||||
(defvar autoload-timestamps)
|
||||
(defvar generated-autoload-load-name)
|
||||
(defvar generated-autoload-file)
|
||||
|
@ -27,15 +24,14 @@ byte-compiles `doom-autoload-file', as well as `doom-package-autoload-file'
|
|||
|
||||
It also caches `load-path', `Info-directory-list', `doom-disabled-packages',
|
||||
`package-activated-list' and `auto-mode-alist'."
|
||||
;; REVIEW Can we avoid calling `straight-check-all' everywhere?
|
||||
(straight-check-all)
|
||||
(doom-reload-autoloads nil 'force))
|
||||
(doom-cli-reload-autoloads nil 'force))
|
||||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defun doom-delete-autoloads-file (file)
|
||||
(defun doom--cli-delete-autoloads-file (file)
|
||||
"Delete FILE (an autoloads file) and accompanying *.elc file, if any."
|
||||
(cl-check-type file string)
|
||||
(when (file-exists-p file)
|
||||
|
@ -47,29 +43,29 @@ It also caches `load-path', `Info-directory-list', `doom-disabled-packages',
|
|||
(ignore-errors (delete-file (byte-compile-dest-file file)))
|
||||
t))
|
||||
|
||||
(defun doom--warn-refresh-session-h ()
|
||||
(defun doom--cli-warn-refresh-session-h ()
|
||||
(message "Restart or reload Doom Emacs for changes to take effect:\n")
|
||||
(message " M-x doom/restart-and-restore")
|
||||
(message " M-x doom/restart")
|
||||
(message " M-x doom/reload"))
|
||||
|
||||
(defun doom--byte-compile-file (file)
|
||||
(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)
|
||||
(prog1 (load file 'noerror 'nomessage)
|
||||
(prog1 (load file 'noerror 'nomessage 'nosuffix)
|
||||
(when noninteractive
|
||||
(add-hook 'doom-cli-post-success-execute-hook #'doom--warn-refresh-session-h))))
|
||||
(add-hook 'doom-cli-post-success-execute-hook #'doom--cli-warn-refresh-session-h))))
|
||||
((debug error)
|
||||
(let ((backup-file (concat file ".bk")))
|
||||
(print! (warn "Copied backup to %s") (relpath backup-file))
|
||||
(copy-file file backup-file 'overwrite))
|
||||
(doom-delete-autoloads-file file)
|
||||
(doom--cli-delete-autoloads-file file)
|
||||
(signal 'doom-autoload-error (list file e))))))
|
||||
|
||||
(defun doom-reload-autoloads (&optional file force-p)
|
||||
(defun doom-cli-reload-autoloads (&optional file force-p)
|
||||
"Reloads FILE (an autoload file), if it needs reloading.
|
||||
|
||||
FILE should be one of `doom-autoload-file' or `doom-package-autoload-file'. If
|
||||
|
@ -80,23 +76,23 @@ even if it doesn't need reloading!"
|
|||
(signal 'wrong-type-argument (list 'stringp file)))
|
||||
(if (stringp file)
|
||||
(cond ((file-equal-p file doom-autoload-file)
|
||||
(doom-reload-core-autoloads force-p))
|
||||
(doom-cli-reload-core-autoloads force-p))
|
||||
((file-equal-p file doom-package-autoload-file)
|
||||
(doom-reload-package-autoloads force-p))
|
||||
(doom-cli-reload-package-autoloads force-p))
|
||||
((error "Invalid autoloads file: %s" file)))
|
||||
(doom-reload-core-autoloads force-p)
|
||||
(doom-reload-package-autoloads force-p)))
|
||||
(doom-cli-reload-core-autoloads force-p)
|
||||
(doom-cli-reload-package-autoloads force-p)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Doom autoloads
|
||||
|
||||
(defun doom--generate-header (func)
|
||||
(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--generate-autoloads (targets)
|
||||
(defun doom--cli-generate-autoloads (targets)
|
||||
(let ((n 0))
|
||||
(dolist (file targets)
|
||||
(insert
|
||||
|
@ -115,7 +111,7 @@ even if it doesn't need reloading!"
|
|||
"Scanned %d file(s)")
|
||||
n)))
|
||||
|
||||
(defun doom--expand-autoload-paths (&optional allow-internal-paths)
|
||||
(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
|
||||
|
@ -140,7 +136,7 @@ even if it doesn't need reloading!"
|
|||
path)
|
||||
t t nil 1)))))
|
||||
|
||||
(defun doom--generate-autodefs-1 (path &optional member-p)
|
||||
(defun doom--cli-generate-autodefs-1 (path &optional member-p)
|
||||
(let (forms)
|
||||
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
|
||||
(let* ((sexp (sexp-at-point))
|
||||
|
@ -202,7 +198,7 @@ even if it doesn't need reloading!"
|
|||
(member-p (push sexp forms)))))
|
||||
forms))
|
||||
|
||||
(defun doom--generate-autodefs (targets enabled-targets)
|
||||
(defun doom--cli-generate-autodefs (targets enabled-targets)
|
||||
(goto-char (point-max))
|
||||
(search-backward ";;;***" nil t)
|
||||
(save-excursion (insert "\n"))
|
||||
|
@ -210,17 +206,17 @@ even if it doesn't need reloading!"
|
|||
(insert
|
||||
(with-temp-buffer
|
||||
(insert-file-contents path)
|
||||
(if-let (forms (doom--generate-autodefs-1 path (member path enabled-targets)))
|
||||
(if-let (forms (doom--cli-generate-autodefs-1 path (member path enabled-targets)))
|
||||
(concat (mapconcat #'prin1-to-string (nreverse forms) "\n")
|
||||
"\n")
|
||||
"")))))
|
||||
|
||||
(defun doom--cleanup-autoloads ()
|
||||
(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-reload-core-autoloads (&optional force-p)
|
||||
(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,
|
||||
|
@ -228,6 +224,7 @@ 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))
|
||||
|
||||
|
@ -269,37 +266,38 @@ Run this whenever your `doom!' block, or a module autoload file, is modified."
|
|||
(ignore
|
||||
(print! (success "Skipping core autoloads, they are up-to-date"))
|
||||
(doom-load-autoloads-file doom-autoload-file))
|
||||
(print! (start "Regenerating core autoloads file"))
|
||||
|
||||
(if (doom-delete-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))
|
||||
|
||||
(with-temp-file doom-autoload-file
|
||||
(doom--generate-header 'doom-reload-core-autoloads)
|
||||
(save-excursion
|
||||
(doom--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--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--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--cleanup-autoloads)
|
||||
(print! (success "Clean up autoloads")))
|
||||
(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--byte-compile-file doom-autoload-file)
|
||||
(print! (success "Finished 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)))
|
||||
|
||||
|
||||
|
@ -346,7 +344,7 @@ served no purpose but to waste cycles."
|
|||
(goto-char (match-beginning 1))
|
||||
(kill-sexp)))
|
||||
|
||||
(defun doom-reload-package-autoloads (&optional force-p)
|
||||
(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'.
|
||||
|
@ -355,6 +353,7 @@ 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)
|
||||
(print! (start "Checking package autoloads file"))
|
||||
(print-group!
|
||||
(if (and (not force-p)
|
||||
|
@ -381,37 +380,39 @@ This should be run whenever your `doom!' block or update your packages."
|
|||
(version-control 'never)
|
||||
(case-fold-search nil) ; reduce magic
|
||||
(autoload-timestamps nil))
|
||||
(print! (start "Regenerating package autoloads file"))
|
||||
|
||||
(if (doom-delete-autoloads-file doom-package-autoload-file)
|
||||
(if (doom--cli-delete-autoloads-file doom-package-autoload-file)
|
||||
(print! (success "Deleted old %s") (filename doom-package-autoload-file))
|
||||
(make-directory (file-name-directory doom-autoload-file) t))
|
||||
|
||||
(with-temp-file doom-package-autoload-file
|
||||
(doom--generate-header 'doom-reload-package-autoloads)
|
||||
(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")))
|
||||
(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--expand-autoload-paths)
|
||||
(print! (success "Expanded module autoload paths")))
|
||||
;; 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")))
|
||||
;; 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--byte-compile-file doom-package-autoload-file)
|
||||
(print! (success "Finished 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))
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
;;; core/cli/byte-compile.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defcli! (compile c) (&rest targets)
|
||||
(defcli! (compile c)
|
||||
((recompile-p ["-r" "--recompile"])
|
||||
&rest targets)
|
||||
"Byte-compiles your config or selected modules.
|
||||
|
||||
compile [TARGETS...]
|
||||
|
@ -10,14 +12,11 @@
|
|||
Accepts :core and :private as special arguments, which target Doom's core files
|
||||
and your private config files, respectively. To recompile your packages, use
|
||||
'doom rebuild' instead."
|
||||
(doom-byte-compile targets))
|
||||
|
||||
(defcli! (recompile rc) (&rest targets)
|
||||
"Re-byte-compiles outdated *.elc files."
|
||||
(doom-byte-compile targets 'recompile))
|
||||
(doom-cli-byte-compile targets recompile-p))
|
||||
|
||||
(defcli! clean ()
|
||||
"Delete all *.elc files."
|
||||
:bare t
|
||||
(doom-clean-byte-compiled-files))
|
||||
|
||||
|
||||
|
@ -31,7 +30,7 @@ and your private config files, respectively. To recompile your packages, use
|
|||
(not (equal (file-name-extension path) "el"))
|
||||
(member filename (list "packages.el" "doctor.el")))))
|
||||
|
||||
(cl-defun doom-byte-compile (&optional modules recompile-p)
|
||||
(cl-defun doom-cli-byte-compile (&optional modules recompile-p)
|
||||
"Byte compiles your emacs configuration.
|
||||
|
||||
init.el is always byte-compiled by this.
|
||||
|
@ -149,7 +148,7 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
|||
(unless recompile-p
|
||||
(doom-clean-byte-compiled-files))
|
||||
|
||||
(dolist (target (delete-dups targets))
|
||||
(dolist (target (delete-dups (delq nil targets)))
|
||||
(cl-incf
|
||||
(if (not (or (not recompile-p)
|
||||
(let ((elc-file (byte-compile-dest-file target)))
|
||||
|
@ -183,6 +182,7 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
|||
(defun doom-clean-byte-compiled-files ()
|
||||
"Delete all the compiled elc files in your Emacs configuration and private
|
||||
module. This does not include your byte-compiled, third party packages.'"
|
||||
(require 'core-modules)
|
||||
(print! (start "Cleaning .elc files"))
|
||||
(print-group!
|
||||
(cl-loop with default-directory = doom-emacs-dir
|
||||
|
|
|
@ -1,21 +1,11 @@
|
|||
;;; core/cli/debug.el -*- lexical-binding: t; -*-
|
||||
|
||||
(load! "autoload/debug" doom-core-dir)
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
(defcli! info (&optional format)
|
||||
"Output system info in markdown for bug reports.
|
||||
|
||||
Will print in the following formats:
|
||||
|
||||
--json
|
||||
--md / --markdown
|
||||
--lisp
|
||||
|
||||
If no arguments are given, --raw is assumed."
|
||||
(defcli! info
|
||||
((format ["--json" "--md" "--lisp"] "What format to dump info into"))
|
||||
"Output system info in markdown for bug reports."
|
||||
(pcase format
|
||||
("--json"
|
||||
(require 'json)
|
||||
|
@ -23,7 +13,7 @@ If no arguments are given, --raw is assumed."
|
|||
(insert (json-encode (doom-info)))
|
||||
(json-pretty-print-buffer)
|
||||
(print! (buffer-string))))
|
||||
((or "--md" "--markdown")
|
||||
("--md"
|
||||
(doom/info))
|
||||
((or `nil "--lisp")
|
||||
(doom/info 'raw))
|
||||
|
@ -33,6 +23,7 @@ If no arguments are given, --raw is assumed."
|
|||
nil)
|
||||
|
||||
(defcli! (version v) ()
|
||||
"Reports the version of Doom and Emacs."
|
||||
"Show version information for Doom & Emacs."
|
||||
:bare t
|
||||
(doom/version)
|
||||
nil)
|
||||
|
|
203
core/cli/doctor.el
Normal file
203
core/cli/doctor.el
Normal file
|
@ -0,0 +1,203 @@
|
|||
;;; core/cli/doctor.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-warnings ())
|
||||
(defvar doom-errors ())
|
||||
|
||||
;;; Helpers
|
||||
(defun elc-check-dir (dir)
|
||||
(dolist (file (directory-files-recursively dir "\\.elc$"))
|
||||
(when (file-newer-than-file-p (concat (file-name-sans-extension file) ".el")
|
||||
file)
|
||||
(warn! "%s is out-of-date" (abbreviate-file-name file)))))
|
||||
|
||||
(defmacro assert! (condition message &rest args)
|
||||
`(unless ,condition
|
||||
(error! ,message ,@args)))
|
||||
|
||||
|
||||
;;; Logging
|
||||
(defmacro error! (&rest args)
|
||||
`(progn (unless inhibit-message (print! (error ,@args)))
|
||||
(push (format! (error ,@args)) doom-errors)))
|
||||
(defmacro warn! (&rest args)
|
||||
`(progn (unless inhibit-message (print! (warn ,@args)))
|
||||
(push (format! (warn ,@args)) doom-warnings)))
|
||||
(defmacro success! (&rest args)
|
||||
`(print! (green ,@args)))
|
||||
(defmacro section! (&rest args)
|
||||
`(print! (bold (blue ,@args))))
|
||||
|
||||
(defmacro explain! (&rest args)
|
||||
`(print-group! (print! (autofill ,@args))))
|
||||
|
||||
|
||||
;;
|
||||
;;; CLI commands
|
||||
|
||||
(defcli! (doctor doc) ()
|
||||
"Diagnoses common issues on your system.
|
||||
|
||||
The Doom doctor is essentially one big, self-contained elisp shell script that
|
||||
uses a series of simple heuristics to diagnose common issues on your system.
|
||||
Issues that could intefere with Doom Emacs.
|
||||
|
||||
Doom modules may optionally have a doctor.el file to run their own heuristics
|
||||
in."
|
||||
:bare t
|
||||
(print! "The doctor will see you now...\n")
|
||||
|
||||
;; REVIEW Refactor me
|
||||
(print! (start "Checking your Emacs version..."))
|
||||
(when EMACS27+
|
||||
(warn! "Emacs %s detected. Emacs HEAD is unstable and may cause errors."
|
||||
emacs-version))
|
||||
|
||||
(print! (start "Checking for Emacs config conflicts..."))
|
||||
(when (file-exists-p "~/.emacs")
|
||||
(warn! "Detected an ~/.emacs file, which may prevent Doom from loading")
|
||||
(explain! "If Emacs finds an ~/.emacs file, it will ignore ~/.emacs.d, where Doom is "
|
||||
"typically installed. If you're seeing a vanilla Emacs splash screen, this "
|
||||
"may explain why. If you use Chemacs, you may ignore this warning."))
|
||||
|
||||
(print! (start "Checking for private config conflicts..."))
|
||||
(let ((xdg-dir (concat (or (getenv "XDG_CONFIG_HOME")
|
||||
"~/.config")
|
||||
"/doom/"))
|
||||
(doom-dir (or (getenv "DOOMDIR")
|
||||
"~/.doom.d/")))
|
||||
(when (and (not (file-equal-p xdg-dir doom-dir))
|
||||
(file-directory-p xdg-dir)
|
||||
(file-directory-p doom-dir))
|
||||
(print! (warn "Detected two private configs, in %s and %s")
|
||||
(abbreviate-file-name xdg-dir)
|
||||
doom-dir)
|
||||
(explain! "The second directory will be ignored, as it has lower precedence.")))
|
||||
|
||||
(print! (start "Checking for stale elc files..."))
|
||||
(elc-check-dir user-emacs-directory)
|
||||
|
||||
(print! (start "Checking Doom Emacs..."))
|
||||
(condition-case-unless-debug ex
|
||||
(print-group!
|
||||
(let ((doom-interactive-mode 'doctor))
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-core)
|
||||
(doom-initialize-modules))
|
||||
|
||||
(print! (success "Initialized Doom Emacs %s") doom-version)
|
||||
(print!
|
||||
(if (hash-table-p doom-modules)
|
||||
(success "Detected %d modules" (hash-table-count doom-modules))
|
||||
(warn "Failed to load any modules. Do you have an private init.el?")))
|
||||
|
||||
(print! (success "Detected %d packages") (length doom-packages))
|
||||
|
||||
(print! (start "Checking Doom core for irregularities..."))
|
||||
(print-group!
|
||||
;; Check for oversized problem files in cache that may cause unusual/tremendous
|
||||
;; delays or freezing. This shouldn't happen often.
|
||||
(dolist (file (list "savehist" "projectile.cache"))
|
||||
(when-let (size (ignore-errors (doom-file-size file doom-cache-dir)))
|
||||
(when (> size 1048576) ; larger than 1mb
|
||||
(warn! "%s is too large (%.02fmb). This may cause freezes or odd startup delays"
|
||||
file (/ size 1024))
|
||||
(explain! "Consider deleting it from your system (manually)"))))
|
||||
|
||||
(unless (ignore-errors (executable-find doom-projectile-fd-binary))
|
||||
(warn! "Couldn't find the `fd' binary; project file searches will be slightly slower")
|
||||
(unless (executable-find "rg")
|
||||
(warn! "Couldn't find the `rg' binary either; project file searches will be even slower")))
|
||||
|
||||
(require 'projectile)
|
||||
(when (projectile-project-root "~")
|
||||
(warn! "Your $HOME is recognized as a project root")
|
||||
(explain! "Doom will disable bottom-up root search, which may reduce the accuracy of project\n"
|
||||
"detection."))
|
||||
|
||||
;; There should only be one
|
||||
(when (and (file-equal-p doom-private-dir "~/.config/doom")
|
||||
(file-directory-p "~/.doom.d"))
|
||||
(print! (warn "Both %S and '~/.doom.d' exist on your system")
|
||||
(path doom-private-dir))
|
||||
(explain! "Doom will only load one of these (~/.config/doom takes precedence). Possessing\n"
|
||||
"both is rarely intentional; you should one or the other."))
|
||||
|
||||
;; Check for fonts
|
||||
(if (not (fboundp 'find-font))
|
||||
(progn
|
||||
(warn! "Warning: unable to detect font")
|
||||
(explain! "The `find-font' function is missing. This could indicate the incorrect "
|
||||
"version of Emacs is being used!"))
|
||||
;; all-the-icons fonts
|
||||
(when (and (pcase system-type
|
||||
(`gnu/linux (concat (or (getenv "XDG_DATA_HOME")
|
||||
"~/.local/share")
|
||||
"/fonts/"))
|
||||
(`darwin "~/Library/Fonts/"))
|
||||
(require 'all-the-icons nil t))
|
||||
(with-temp-buffer
|
||||
(insert (cdr (doom-call-process "fc-list")))
|
||||
(dolist (font all-the-icons-font-names)
|
||||
(if (save-excursion (re-search-backward font nil t))
|
||||
(success! "Found font %s" font)
|
||||
(print! (warn "Warning: couldn't find %S font") font)
|
||||
(explain! "You can install it by running `M-x all-the-icons-install-fonts' within Emacs.\n\n"
|
||||
"This could also mean you've installed them in non-standard locations, in which "
|
||||
"case feel free to ignore this warning.")))))))
|
||||
|
||||
(print! (start "Checking for stale elc files in your DOOMDIR..."))
|
||||
(when (file-directory-p doom-private-dir)
|
||||
(print-group!
|
||||
(elc-check-dir doom-private-dir)))
|
||||
|
||||
(when doom-modules
|
||||
(print! (start "Checking your enabled modules..."))
|
||||
(advice-add #'require :around #'doom-shut-up-a)
|
||||
(maphash (lambda (key plist)
|
||||
(let (doom-local-errors
|
||||
doom-local-warnings)
|
||||
(let (doom-errors
|
||||
doom-warnings)
|
||||
(condition-case-unless-debug ex
|
||||
(let ((doctor-file (doom-module-path (car key) (cdr key) "doctor.el"))
|
||||
(packages-file (doom-module-path (car key) (cdr key) "packages.el")))
|
||||
(cl-loop for name in (let (doom-packages
|
||||
doom-disabled-packages)
|
||||
(load packages-file 'noerror 'nomessage)
|
||||
(mapcar #'car doom-packages))
|
||||
unless (or (doom-package-get name :disable)
|
||||
(eval (doom-package-get name :ignore))
|
||||
(doom-package-built-in-p name)
|
||||
(doom-package-installed-p name))
|
||||
do (print! (error "%s is not installed") name))
|
||||
(let ((inhibit-message t))
|
||||
(load doctor-file 'noerror 'nomessage)))
|
||||
(file-missing (error! "%s" (error-message-string ex)))
|
||||
(error (error! "Syntax error: %s" ex)))
|
||||
(when (or doom-errors doom-warnings)
|
||||
(print-group!
|
||||
(print! (start (bold "%s %s")) (car key) (cdr key))
|
||||
(print! "%s" (string-join (append doom-errors doom-warnings) "\n")))
|
||||
(setq doom-local-errors doom-errors
|
||||
doom-local-warnings doom-warnings)))
|
||||
(appendq! doom-errors doom-local-errors)
|
||||
(appendq! doom-warnings doom-local-warnings)))
|
||||
doom-modules)))
|
||||
(error
|
||||
(warn! "Attempt to load DOOM failed\n %s\n"
|
||||
(or (cdr-safe ex) (car ex)))
|
||||
(setq doom-modules nil)))
|
||||
|
||||
;; Final report
|
||||
(message "")
|
||||
(dolist (msg (list (list doom-errors "error" 'red)
|
||||
(list doom-warnings "warning" 'yellow)))
|
||||
(when (car msg)
|
||||
(print! (color (nth 2 msg)
|
||||
(if (cdr msg)
|
||||
"There are %d %ss!"
|
||||
"There is %d %s!")
|
||||
(length (car msg)) (nth 1 msg)))))
|
||||
(unless (or doom-errors doom-warnings)
|
||||
(success! "Everything seems fine, happy Emacs'ing!"))
|
||||
t)
|
144
core/cli/env.el
144
core/cli/env.el
|
@ -1,13 +1,14 @@
|
|||
;;; core/cli/env.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defcli! env (&rest args)
|
||||
(defcli! env
|
||||
((clear-p ["-c" "--clear"] "Clear and delete your envvar file")
|
||||
(outputfile ["-o" PATH]
|
||||
"Generate the envvar file at PATH. Note that envvar files that aren't in
|
||||
`doom-env-file' won't be loaded automatically at startup. You will need to
|
||||
load them manually from your private config with the `doom-load-envvars-file'
|
||||
function."))
|
||||
"Creates or regenerates your envvars file.
|
||||
|
||||
doom env [-c|--clear]
|
||||
|
||||
This is meant to be a faster and more comprehensive alternative to
|
||||
exec-path-from-shell. See the FAQ in the documentation for an explanation why.
|
||||
|
||||
The envvars file is created by scraping your (interactive) shell environment
|
||||
into newline-delimited KEY=VALUE pairs. Typically by running '$SHELL -ic env'
|
||||
(or '$SHELL -c set' on windows). Doom loads this file at startup (if it exists)
|
||||
|
@ -21,14 +22,23 @@ app launchers on Linux).
|
|||
This file is automatically regenerated when you run this command or 'doom
|
||||
refresh'. However, 'doom refresh' will only regenerate this file if it exists.
|
||||
|
||||
Use the -c or --clear switch to delete your envvar file."
|
||||
(when (member "clear" args) ; DEPRECATED
|
||||
(message "'doom env clear' is deprecated. Use 'doom env -c' or 'doom env --clear' instead")
|
||||
(push "-c" args))
|
||||
(let ((env-file (or (cadr (member "-o" args))
|
||||
doom-env-file)))
|
||||
(cond ((or (member "-c" args)
|
||||
(member "--clear" args))
|
||||
Why this over exec-path-from-shell?
|
||||
|
||||
1. `exec-path-from-shell' spawns (at least) one process at startup to scrape
|
||||
your shell environment. This can be arbitrarily slow depending on the
|
||||
user's shell configuration. A single program (like pyenv or nvm) or config
|
||||
framework (like oh-my-zsh) could undo all of Doom's startup optimizations
|
||||
in one fell swoop.
|
||||
|
||||
2. `exec-path-from-shell' only scrapes some state from your shell. You have to
|
||||
be proactive in order to get it to capture all the envvars relevant to your
|
||||
development environment.
|
||||
|
||||
I'd rather it inherit your shell environment /correctly/ (and /completely/)
|
||||
or not at all. It frontloads the debugging process rather than hiding it
|
||||
until it you least want to deal with it."
|
||||
(let ((env-file (expand-file-name (or outputfile doom-env-file))))
|
||||
(cond (clear-p
|
||||
(unless (file-exists-p env-file)
|
||||
(user-error! "%S does not exist to be cleared"
|
||||
(path env-file)))
|
||||
|
@ -36,12 +46,11 @@ Use the -c or --clear switch to delete your envvar file."
|
|||
(print! (success "Successfully deleted %S")
|
||||
(path env-file)))
|
||||
|
||||
((or (null args)
|
||||
(member "-o" args))
|
||||
(doom-reload-env-file 'force env-file))
|
||||
(args
|
||||
(user-error "I don't understand 'doom env %s'"
|
||||
(string-join args " ")))
|
||||
|
||||
((user-error "I don't understand 'doom env %s'"
|
||||
(string-join args " "))))))
|
||||
((doom-cli-reload-env-file 'force env-file)))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -66,22 +75,7 @@ Use the -c or --clear switch to delete your envvar file."
|
|||
Each string is a regexp, matched against variable names to omit from
|
||||
`doom-env-file'.")
|
||||
|
||||
(defvar doom-env-executable
|
||||
(if IS-WINDOWS
|
||||
"set"
|
||||
(executable-find "env"))
|
||||
"The program to use to scrape your shell environment with.
|
||||
It is rare that you'll need to change this.")
|
||||
|
||||
(defvar doom-env-switches
|
||||
(if IS-WINDOWS
|
||||
"-c"
|
||||
"-ic") ; Execute in an interactive shell
|
||||
"The `shell-command-switch'es to use on `doom-env-executable'.
|
||||
This is a list of strings. Each entry is run separately and in sequence with
|
||||
`doom-env-executable' to scrape envvars from your shell environment.")
|
||||
|
||||
(defun doom-reload-env-file (&optional force-p env-file)
|
||||
(defun doom-cli-reload-env-file (&optional force-p env-file)
|
||||
"Generates `doom-env-file', if it doesn't exist (or if FORCE-P).
|
||||
|
||||
This scrapes the variables from your shell environment by running
|
||||
|
@ -99,49 +93,37 @@ default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
|
|||
"Generating")
|
||||
(path env-file))
|
||||
(let ((process-environment doom--initial-process-environment))
|
||||
(let ((shell-command-switch doom-env-switches)
|
||||
(error-buffer (get-buffer-create "*env errors*")))
|
||||
(print! (info "Scraping shell environment with '%s %s %s'")
|
||||
(filename shell-file-name)
|
||||
shell-command-switch
|
||||
(filename doom-env-executable))
|
||||
(save-excursion
|
||||
(shell-command doom-env-executable (current-buffer) error-buffer))
|
||||
(print-group!
|
||||
(let ((errors (with-current-buffer error-buffer (buffer-string))))
|
||||
(unless (string-empty-p errors)
|
||||
(print! (info "Warnings:\n\n%s") (indent 4 errors))))
|
||||
;; Remove undesireable variables
|
||||
(insert
|
||||
(concat
|
||||
"# -*- mode: dotenv -*-\n"
|
||||
(format "# Generated with: %s %s %s\n"
|
||||
shell-file-name
|
||||
doom-env-switches
|
||||
doom-env-executable)
|
||||
"# ---------------------------------------------------------------------------\n"
|
||||
"# This file was auto-generated by `doom env'. It contains a list of environment\n"
|
||||
"# variables scraped from your default shell (excluding variables blacklisted\n"
|
||||
"# in doom-env-ignored-vars).\n"
|
||||
"#\n"
|
||||
"# It is NOT safe to edit this file. Changes will be overwritten next time that\n"
|
||||
"# `doom refresh` is executed. Alternatively, create your own env file with\n"
|
||||
"# `doom env -o ~/.doom.d/myenv`, then load it with (doom-load-envvars-file FILE)\n"
|
||||
"# in your private config.el.\n"
|
||||
"# ---------------------------------------------------------------------------\n\n"))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "\n\\([^= \n]+\\)=" nil t)
|
||||
(save-excursion
|
||||
(let* ((valend (or (save-match-data
|
||||
(when (re-search-forward "^\\([^= ]+\\)=" nil t)
|
||||
(line-beginning-position)))
|
||||
(point-max)))
|
||||
(var (match-string 1)))
|
||||
(when (cl-loop for regexp in doom-env-ignored-vars
|
||||
if (string-match-p regexp var)
|
||||
return t)
|
||||
(print! (info "Ignoring %s") var)
|
||||
(delete-region (match-beginning 0) (1- valend)))))))
|
||||
(print! (success "Successfully generated %S")
|
||||
(path env-file))
|
||||
t))))))
|
||||
(print! (info "Scraping shell environment"))
|
||||
(print-group!
|
||||
(when doom-interactive-mode
|
||||
(user-error "'doom env' must be run on the command line, not an interactive session"))
|
||||
(goto-char (point-min))
|
||||
(insert
|
||||
(concat
|
||||
"# -*- mode: dotenv -*-\n"
|
||||
(format "# Generated from a %s shell environent\n" shell-file-name)
|
||||
"# ---------------------------------------------------------------------------\n"
|
||||
"# This file was auto-generated by `doom env'. It contains a list of environment\n"
|
||||
"# variables scraped from your default shell (excluding variables blacklisted\n"
|
||||
"# in doom-env-ignored-vars).\n"
|
||||
"#\n"
|
||||
(if (file-equal-p env-file doom-env-file)
|
||||
(concat "# It is NOT safe to edit this file. Changes will be overwritten next time you\n"
|
||||
"# run 'doom refresh'. To create a safe-to-edit envvar file use:\n#\n"
|
||||
"# doom env -o ~/.doom.d/myenv\n#\n"
|
||||
"# And load it with (doom-load-envvars-file \"~/.doom.d/myenv\").\n")
|
||||
(concat "# This file is safe to edit by hand, but needs to be loaded manually with:\n#\n"
|
||||
"# (doom-load-envvars-file \"path/to/this/file\")\n#\n"
|
||||
"# Use 'doom env -o path/to/this/file' to regenerate it."))
|
||||
"# ---------------------------------------------------------------------------\n\n"))
|
||||
;; We assume that this noninteractive session was spawned from the
|
||||
;; user's interactive shell, therefore we just dump
|
||||
;; `process-environment' to a file.
|
||||
(dolist (env process-environment)
|
||||
(if (cl-find-if (doom-rpartial #'string-match-p env)
|
||||
doom-env-ignored-vars)
|
||||
(print! (info "Ignoring %s") env)
|
||||
(insert env "\n")))
|
||||
(print! (success "Successfully generated %S")
|
||||
(path env-file))
|
||||
t))))))
|
||||
|
|
101
core/cli/help.el
Normal file
101
core/cli/help.el
Normal file
|
@ -0,0 +1,101 @@
|
|||
;;; core/cli/help.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun doom--cli-print-signature (cli)
|
||||
(print! (bold "Usage: doom %s%s%s")
|
||||
(if (doom-cli-internal-p cli)
|
||||
""
|
||||
(concat (doom-cli-name cli) " "))
|
||||
(if-let* ((optlist (doom-cli-optlist cli))
|
||||
(flags (cl-loop for opt in optlist
|
||||
append (doom-cli-option-flags opt)))
|
||||
(fn (doom-partial #'string-prefix-p "--")))
|
||||
(concat (when-let (short-flags (cl-remove-if fn flags))
|
||||
;; TODO Show arguments of short flags
|
||||
(format "[-%s]"
|
||||
(string-join (mapcar (doom-rpartial #'substring 1 nil) short-flags)
|
||||
"")))
|
||||
;; TODO Show long flags
|
||||
;; (when-let (long-flags (cl-remove-if-not fn flags))
|
||||
;; (concat " " (string-join long-flags " ")))
|
||||
" ")
|
||||
"")
|
||||
(if-let (arglist (doom-cli-arglist cli))
|
||||
(string-join (append (cl-loop for arg in arglist
|
||||
until (memq arg cl--lambda-list-keywords)
|
||||
collect (upcase (symbol-name arg)))
|
||||
(cl-loop for arg in (cdr (memq '&optional arglist))
|
||||
until (memq arg cl--lambda-list-keywords)
|
||||
collect (format "[%s]" (upcase (symbol-name arg)))))
|
||||
" ")
|
||||
"")))
|
||||
|
||||
(defun doom--cli-print-desc (cli &optional short)
|
||||
(print! "%s"
|
||||
(if short
|
||||
(car (split-string (doom-cli-desc cli) "\n"))
|
||||
(doom-cli-desc cli))))
|
||||
|
||||
(defun doom--cli-print-short-desc (cli)
|
||||
(doom--cli-print-desc cli 'short))
|
||||
|
||||
(defun doom--cli-print-options (cli)
|
||||
(when-let (optlist (doom-cli-optlist cli))
|
||||
(print! (bold "Options:"))
|
||||
(print-group!
|
||||
(cl-loop for opt in optlist
|
||||
for flags = (doom-cli-option-flags opt)
|
||||
for desc = (doom-cli-option-desc opt)
|
||||
for args = (doom-cli-option-args opt)
|
||||
for flagstr = (string-join (doom-cli-option-flags opt) ", ")
|
||||
do
|
||||
;; TODO Adjust columns dynamically
|
||||
(print! "%-18s"
|
||||
(concat flagstr
|
||||
(when-let (arg (car args))
|
||||
(concat " " (upcase (symbol-name arg))))))
|
||||
(print-group!
|
||||
(print! (autofill "%s") desc))))))
|
||||
|
||||
|
||||
(defun doom--cli-print (cli)
|
||||
(doom--cli-print-signature cli)
|
||||
(terpri)
|
||||
(doom--cli-print-desc cli)
|
||||
(terpri)
|
||||
(doom--cli-print-options cli))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
(defcli! (help h) (&optional command)
|
||||
"Describe a command or list them all."
|
||||
:bare t
|
||||
(if command
|
||||
(doom--cli-print (doom-cli-get (intern command)))
|
||||
(doom--cli-print (doom-cli-get :main))
|
||||
(terpri)
|
||||
(print! (bold "Commands:"))
|
||||
(print-group!
|
||||
(dolist (group (seq-group-by (lambda (cli)
|
||||
(plist-get (doom-cli-plist cli) :group))
|
||||
(cl-loop for name being the hash-keys of doom--cli-commands
|
||||
for cli = (gethash name doom--cli-commands)
|
||||
if (and (doom-cli-p cli)
|
||||
(not (doom-cli-internal-p cli))
|
||||
(not (plist-get (doom-cli-plist cli) :hidden)))
|
||||
collect cli)))
|
||||
(if (null (car group))
|
||||
(dolist (cli (cdr group))
|
||||
(print! "%-16s %s"
|
||||
(doom-cli-name cli)
|
||||
(car (split-string (doom-cli-desc cli) "\n"))))
|
||||
(print! "%-26s %s"
|
||||
(bold (concat (car group) ":"))
|
||||
(gethash (car group) doom--cli-groups))
|
||||
(print-group!
|
||||
(dolist (cli (cdr group))
|
||||
(print! "%-16s %s"
|
||||
(doom-cli-name cli)
|
||||
(car (split-string (doom-cli-desc cli) "\n"))))))
|
||||
(terpri)))))
|
|
@ -1,13 +1,11 @@
|
|||
;;; core/cli/install.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defcli! quickstart (&rest args) ; DEPRECATED
|
||||
"This is a deprecated alias for 'doom install'.
|
||||
|
||||
See 'doom help install' instead."
|
||||
:hidden t
|
||||
(apply #'doom-cli-install args))
|
||||
|
||||
(defcli! (install i) (&rest args)
|
||||
(defcli! (install i)
|
||||
((noconfig-p ["--no-config"] "Don't create DOOMDIR or dummy files therein")
|
||||
(noenv-p ["--no-env"] "Don't generate an envvars file (see 'doom help env')")
|
||||
(noinstall-p ["--no-install"] "Don't auto-install packages")
|
||||
(nofonts-p ["--no-fonts"] "Don't install (or prompt to install) all-the-icons fonts")
|
||||
&rest args)
|
||||
"Installs and sets up Doom Emacs for the first time.
|
||||
|
||||
This command does the following:
|
||||
|
@ -25,23 +23,17 @@ The location of DOOMDIR can be changed with the -p option, or by setting the
|
|||
DOOMDIR environment variable. e.g.
|
||||
|
||||
doom -p ~/.config/doom install
|
||||
DOOMDIR=~/.config/doom doom install
|
||||
|
||||
The following switches are recognized:
|
||||
|
||||
--no-config Don't create DOOMDIR or dummy files therein
|
||||
--no-install Don't auto-install packages
|
||||
--no-env Don't generate an envvars file (see `doom help env`)
|
||||
--no-fonts Don't install (or prompt to install) all-the-icons fonts
|
||||
-y / --yes Auto-accept any confirmation prompts"
|
||||
DOOMDIR=~/.config/doom doom install"
|
||||
:bare t
|
||||
(print! (green "Installing Doom Emacs!\n"))
|
||||
(let ((default-directory (doom-path "~")))
|
||||
;; Create `doom-private-dir'
|
||||
(if (member "--no-config" args)
|
||||
(if noconfig-p
|
||||
(print! (warn "Not copying private config template, as requested"))
|
||||
(print! "> Creating %s" (relpath doom-private-dir))
|
||||
(print! (start "Creating %s") (relpath doom-private-dir))
|
||||
(make-directory doom-private-dir 'parents)
|
||||
(print! (success "Created %s") (relpath doom-private-dir))
|
||||
(print-group!
|
||||
(print! (success "Created %s") (relpath doom-private-dir)))
|
||||
|
||||
;; Create init.el, config.el & packages.el
|
||||
(mapc (lambda (file)
|
||||
|
@ -71,26 +63,29 @@ The following switches are recognized:
|
|||
|
||||
;; In case no init.el was present the first time `doom-initialize-modules' was
|
||||
;; called in core.el (e.g. on first install)
|
||||
(doom-initialize-packages 'force-p)
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-modules)
|
||||
|
||||
;; Ask if Emacs.app should be patched
|
||||
(if (member "--no-env" args)
|
||||
(print! (warn "- Not generating envvars file, as requested"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Generate an env file? (see `doom help env` for details)"))
|
||||
(doom-reload-env-file 'force-p)))
|
||||
;; Ask if user would like an envvar file generated
|
||||
(if noenv-p
|
||||
(print! (warn "Not generating envvars file, as requested"))
|
||||
(if (file-exists-p doom-env-file)
|
||||
(print! (info "Envvar file already exists, skipping"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Generate an env file? (see `doom help env` for details)"))
|
||||
(doom-cli-reload-env-file 'force-p))))
|
||||
|
||||
;; Install Doom packages
|
||||
(if (member "--no-install" args)
|
||||
(print! (warn "- Not installing plugins, as requested"))
|
||||
(if noinstall-p
|
||||
(print! (warn "Not installing plugins, as requested"))
|
||||
(print! "Installing plugins")
|
||||
(doom-packages-install doom-auto-accept))
|
||||
(doom-cli-packages-install))
|
||||
|
||||
(print! "Regenerating autoloads files")
|
||||
(doom-reload-autoloads nil 'force-p)
|
||||
(doom-cli-reload-autoloads nil 'force-p)
|
||||
|
||||
(if (member "--no-fonts" args)
|
||||
(print! (warn "- Not installing fonts, as requested"))
|
||||
(if nofonts-p
|
||||
(print! (warn "Not installing fonts, as requested"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Download and install all-the-icon's fonts?"))
|
||||
(require 'all-the-icons)
|
||||
|
@ -98,6 +93,9 @@ The following switches are recognized:
|
|||
(IS-LINUX 'x))))
|
||||
(all-the-icons-install-fonts 'yes))))
|
||||
|
||||
(when (file-exists-p "~/.emacs")
|
||||
(print! (warn "A ~/.emacs file was detected. This conflicts with Doom and should be deleted!")))
|
||||
|
||||
(print! (success "\nFinished! Doom is ready to go!\n"))
|
||||
(with-temp-buffer
|
||||
(doom-template-insert "QUICKSTART_INTRO")
|
||||
|
|
|
@ -1,73 +1,55 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; core/cli/packages.el
|
||||
|
||||
(defmacro doom--ensure-autoloads-while (&rest body)
|
||||
`(progn
|
||||
(straight-check-all)
|
||||
(doom-reload-core-autoloads)
|
||||
(when (progn ,@body)
|
||||
(doom-reload-package-autoloads 'force-p))
|
||||
t))
|
||||
|
||||
|
||||
;;
|
||||
;;; Dispatchers
|
||||
|
||||
(defcli! (update u) (&rest args)
|
||||
(defcli! (update u) ()
|
||||
"Updates packages.
|
||||
|
||||
This works by fetching all installed package repos and checking the distance
|
||||
between HEAD and FETCH_HEAD. This can take a while.
|
||||
|
||||
This excludes packages whose `package!' declaration contains a non-nil :freeze
|
||||
or :ignore property.
|
||||
or :ignore property."
|
||||
(straight-check-all)
|
||||
(doom-cli-reload-core-autoloads)
|
||||
(when (doom-cli-packages-update)
|
||||
(doom-cli-reload-package-autoloads 'force-p))
|
||||
t)
|
||||
|
||||
Switches:
|
||||
-t/--timeout TTL Seconds until a thread is timed out (default: 45)
|
||||
--threads N How many threads to use (default: 8)"
|
||||
(doom--ensure-autoloads-while
|
||||
(doom-packages-update
|
||||
doom-auto-accept
|
||||
(when-let (threads (cadr (member "--threads" args)))
|
||||
(string-to-number threads))
|
||||
(when-let (timeout (cadr (or (member "--timeout" args)
|
||||
(member "-t" args))))
|
||||
(string-to-number timeout)))))
|
||||
|
||||
(defcli! (rebuild build b) (&rest args)
|
||||
"Rebuilds all installed packages.
|
||||
(defcli! (build b)
|
||||
((rebuild-p ["-r"] "Only rebuild packages that need rebuilding"))
|
||||
"Byte-compiles & symlinks installed packages.
|
||||
|
||||
This ensures that all needed files are symlinked from their package repo and
|
||||
their elisp files are byte-compiled.
|
||||
their elisp files are byte-compiled. This is especially necessary if you upgrade
|
||||
Emacs (as byte-code is generally not forward-compatible)."
|
||||
(when (doom-cli-packages-build (not rebuild-p))
|
||||
(doom-cli-reload-package-autoloads 'force-p))
|
||||
t)
|
||||
|
||||
Switches:
|
||||
-f Forcibly rebuild autoloads files, even if they're up-to-date"
|
||||
(doom--ensure-autoloads-while
|
||||
(doom-packages-rebuild doom-auto-accept (member "-f" args))))
|
||||
(defcli! (purge p)
|
||||
((nobuilds-p ["-b" "--no-builds"] "Don't purge unneeded (built) packages")
|
||||
(noelpa-p ["-p" "--no-elpa"] "Don't purge ELPA packages")
|
||||
(norepos-p ["-r" "--no-repos"] "Don't purge unused straight repos")
|
||||
(regraft-p ["-g" "--regraft"] "Regraft git repos (ie. compact them)"))
|
||||
"Deletes orphaned packages & repos, and compacts them.
|
||||
|
||||
(defcli! (purge p) (&rest args)
|
||||
"Deletes any unused ELPA packages, straight builds, and (optionally) repos.
|
||||
Purges all installed ELPA packages (as they are considered temporary). Purges
|
||||
all orphaned package repos and builds. If -g/--regraft is supplied, the git
|
||||
repos among them will be regrafted and compacted to ensure they are as small as
|
||||
possible.
|
||||
|
||||
By default, this does not purge ELPA packages or repos. It is a good idea to run
|
||||
'doom purge --all' once in a while, to stymy build-up of repos and ELPA
|
||||
packages that could be taking up precious space.
|
||||
It is a good idea to occasionally run this doom purge -g to ensure your package
|
||||
list remains lean."
|
||||
(straight-check-all)
|
||||
(when (doom-cli-packages-purge
|
||||
(not noelpa-p)
|
||||
(not norepos-p)
|
||||
(not nobuilds-p)
|
||||
regraft-p)
|
||||
(doom-cli-reload-package-autoloads 'force-p))
|
||||
t)
|
||||
|
||||
Switches:
|
||||
--no-builds Don't purge unneeded (built) packages
|
||||
-e / --elpa Don't purge ELPA packages
|
||||
-r / --repos Purge unused repos
|
||||
--all Purge builds, elpa packages and repos"
|
||||
(doom--ensure-autoloads-while
|
||||
(doom-packages-purge (or (member "-e" args)
|
||||
(member "--elpa" args)
|
||||
(member "--all" args))
|
||||
(not (member "--no-builds" args))
|
||||
(or (member "-r" args)
|
||||
(member "--repos" args)
|
||||
(member "--all" args))
|
||||
doom-auto-accept)))
|
||||
|
||||
;; (defcli! rollback () ; TODO rollback
|
||||
;; (defcli! rollback () ; TODO doom rollback
|
||||
;; "<Not implemented yet>"
|
||||
;; (user-error "Not implemented yet, sorry!"))
|
||||
|
||||
|
@ -75,15 +57,12 @@ Switches:
|
|||
;;
|
||||
;;; Library
|
||||
|
||||
(defun doom-packages-install (&optional auto-accept-p)
|
||||
(defun doom-cli-packages-install ()
|
||||
"Installs missing packages.
|
||||
|
||||
This function will install any primary package (i.e. a package with a `package!'
|
||||
declaration) or dependency thereof that hasn't already been.
|
||||
|
||||
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||
a list of packages that will be installed."
|
||||
(print! "> Installing & building packages...")
|
||||
declaration) or dependency thereof that hasn't already been."
|
||||
(print! (start "Installing & building packages..."))
|
||||
(print-group!
|
||||
(let ((n 0))
|
||||
(dolist (package (hash-table-keys straight--recipe-cache))
|
||||
|
@ -91,7 +70,7 @@ a list of packages that will be installed."
|
|||
(local-repo)
|
||||
(let ((existed-p (file-directory-p (straight--repos-dir package))))
|
||||
(condition-case-unless-debug e
|
||||
(and (straight-use-package (intern package) nil nil " ")
|
||||
(and (straight-use-package (intern package) nil nil (make-string (1- (or doom-format-indent 1)) 32))
|
||||
(not existed-p)
|
||||
(file-directory-p (straight--repos-dir package))
|
||||
(cl-incf n))
|
||||
|
@ -104,17 +83,18 @@ a list of packages that will be installed."
|
|||
t))))
|
||||
|
||||
|
||||
(defun doom-packages-rebuild (&optional auto-accept-p all)
|
||||
(defun doom-cli-packages-build (&optional force-p)
|
||||
"(Re)build all packages."
|
||||
(print! (start "(Re)building %spackages...") (if all "all " ""))
|
||||
(print! (start "(Re)building %spackages...") (if force-p "all " ""))
|
||||
(print-group!
|
||||
(let ((n 0))
|
||||
(if all
|
||||
(if force-p
|
||||
(let ((straight--packages-to-rebuild :all)
|
||||
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(dolist (package (hash-table-keys straight--recipe-cache))
|
||||
(straight-use-package
|
||||
(intern package) nil (lambda (_) (cl-incf n) nil) " ")))
|
||||
(intern package) nil (lambda (_) (cl-incf n) nil)
|
||||
(make-string (1- (or doom-format-indent 1)) 32))))
|
||||
(dolist (recipe (hash-table-values straight--recipe-cache))
|
||||
(straight--with-plist recipe (package local-repo no-build)
|
||||
(unless (or no-build (null local-repo))
|
||||
|
@ -139,7 +119,9 @@ a list of packages that will be installed."
|
|||
(lambda (&rest _) (cl-incf n)))
|
||||
(let ((straight--packages-to-rebuild :all)
|
||||
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(straight-use-package (intern package) nil nil " "))
|
||||
(straight-use-package
|
||||
(intern package) nil nil
|
||||
(make-string (or doom-format-indent 0) 32)))
|
||||
(straight--byte-compile-package recipe)
|
||||
(dolist (dep (straight--get-dependencies package))
|
||||
(when-let (recipe (gethash dep straight--recipe-cache))
|
||||
|
@ -151,268 +133,107 @@ a list of packages that will be installed."
|
|||
t))))
|
||||
|
||||
|
||||
(defun doom--packages-remove-outdated-f (packages)
|
||||
(async-start
|
||||
`(lambda ()
|
||||
(setq load-path ',load-path
|
||||
doom-modules ',doom-modules
|
||||
user-emacs-directory ',user-emacs-directory)
|
||||
(condition-case e
|
||||
(let (packages errors)
|
||||
(load ,(concat doom-core-dir "core.el"))
|
||||
(doom-initialize 'force)
|
||||
(dolist (recipe ',group)
|
||||
(when (straight--repository-is-available-p recipe)
|
||||
(straight-vc-git--destructure recipe
|
||||
(package local-repo nonrecursive upstream-remote upstream-repo upstream-host branch)
|
||||
(condition-case e
|
||||
(let ((default-directory (straight--repos-dir local-repo)))
|
||||
;; HACK We normalize packages to avoid certain scenarios
|
||||
;; where `straight-fetch-package' will create an
|
||||
;; interactive popup prompting for action (which will
|
||||
;; cause this async process to block indefinitely). We
|
||||
;; can't use `straight-normalize-package' because could
|
||||
;; create popup prompts too, so we do it manually:
|
||||
(shell-command-to-string "git merge --abort")
|
||||
(straight--get-call "git" "reset" "--hard" branch)
|
||||
(straight--get-call "git" "clean" "-ffd")
|
||||
(unless nonrecursive
|
||||
(shell-command-to-string "git submodule update --init --recursive"))
|
||||
(when upstream-repo
|
||||
(let ((desired-url (straight-vc-git--encode-url upstream-repo upstream-host))
|
||||
(actual-url (condition-case nil
|
||||
(straight--get-call "git" "remote" "get-url" upstream-remote)
|
||||
(error nil))))
|
||||
(unless (straight-vc-git--urls-compatible-p actual-url desired-url)
|
||||
(straight--get-call "git" "remote" "remove" upstream-remote)
|
||||
(straight--get-call "git" "remote" "add" upstream-remote desired-url)
|
||||
(straight--get-call "git" "fetch" upstream-remote))))
|
||||
(straight-fetch-package package)
|
||||
;; REVIEW Is there no better way to get this information?
|
||||
(let ((n (length
|
||||
(split-string
|
||||
(straight--get-call "git" "rev-list" "--left-right" "HEAD..@{u}")
|
||||
"\n" t)))
|
||||
(pretime
|
||||
(string-to-number
|
||||
(shell-command-to-string "git log -1 --format=%at HEAD")))
|
||||
(time
|
||||
(string-to-number
|
||||
;; HACK `straight--get-call' has a higher failure
|
||||
;; rate when querying FETCH_HEAD; not sure why.
|
||||
;; Doing this manually, with
|
||||
;; `shell-command-to-string' works fine.
|
||||
(shell-command-to-string "git log -1 --format=%at FETCH_HEAD"))))
|
||||
(with-current-buffer (straight--process-get-buffer)
|
||||
(with-silent-modifications
|
||||
(print! (debug (autofill "%s") (indent 2 (buffer-string))))
|
||||
(erase-buffer)))
|
||||
(when (> n 0)
|
||||
(push (list n pretime time recipe)
|
||||
packages))))
|
||||
(error
|
||||
(push (list package e (string-trim (or (straight--process-get-output) "")))
|
||||
errors))))))
|
||||
(if errors
|
||||
(cons 'error errors)
|
||||
(cons 'ok (nreverse packages))))
|
||||
(error
|
||||
(cons 'error e))))))
|
||||
|
||||
|
||||
(defun doom-packages-update (&optional auto-accept-p threads timeout)
|
||||
"Updates packages.
|
||||
|
||||
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||
a list of packages that will be updated."
|
||||
(print! (start "Scanning for outdated packages (this may take a while)..."))
|
||||
(print-group!
|
||||
(when timeout
|
||||
(print! (info "Using %S as timeout value" timeout)))
|
||||
(when threads
|
||||
(print! (info "Limiting to %d thread(s)" threads)))
|
||||
;; REVIEW Does this fail gracefully enough? Is it error tolerant?
|
||||
;; TODO Add version-lock checks; don't want to spend all this effort on
|
||||
;; packages that shouldn't be updated
|
||||
(let* ((futures
|
||||
;; REVIEW We can do better "thread" management here
|
||||
(or (cl-loop for group
|
||||
in (seq-partition (hash-table-values straight--repo-cache)
|
||||
(/ (hash-table-count straight--repo-cache)
|
||||
(or threads 8)))
|
||||
for future = (doom--packages-remove-outdated-f group)
|
||||
if (processp future)
|
||||
collect (cons future group)
|
||||
else
|
||||
do (print! (warn "Failed to create thread for:\n\n%s\n\nReason: %s"
|
||||
group future)))
|
||||
(error! "Failed to create any threads")))
|
||||
(total (length futures))
|
||||
(timeout (or timeout 45)))
|
||||
(condition-case-unless-debug e
|
||||
(let (specs)
|
||||
(while futures
|
||||
(print! ". %.0f%%" (* (/ (- total (length futures))
|
||||
(float total))
|
||||
100))
|
||||
(let ((time 0))
|
||||
(catch 'timeout
|
||||
(while (not (async-ready (caar futures)))
|
||||
(when (> time timeout)
|
||||
(print! (warn "A thread has timed out. The following packages were skipped: %s"
|
||||
(mapconcat (lambda (p) (plist-get p :package))
|
||||
(cdar futures)
|
||||
", ")))
|
||||
(throw 'timeout (pop futures)))
|
||||
(sleep-for 1)
|
||||
(when (cl-evenp time)
|
||||
(print! "."))
|
||||
(cl-incf time))
|
||||
(cl-destructuring-bind (status . result)
|
||||
(or (async-get (car (pop futures)))
|
||||
(cons nil nil))
|
||||
(cond ((null status)
|
||||
(error "Thread returned an invalid result: %S" errors))
|
||||
((eq status 'error)
|
||||
(error "There were errors:\n\n%s"
|
||||
(cond ((and (listp result)
|
||||
(symbolp (car result)))
|
||||
(prin1-to-string result))
|
||||
((stringp result)
|
||||
result)
|
||||
((mapconcat (lambda (e)
|
||||
(format! " - %s: %s" (yellow (car e)) (cdr e)))
|
||||
result
|
||||
"\n")))))
|
||||
((eq status 'ok)
|
||||
(print! (debug "Appended %S to package list") (or result "nothing"))
|
||||
(appendq! specs result))
|
||||
((error "Thread returned a non-standard status: %s\n\n%s"
|
||||
status result)))))))
|
||||
(print! ". 100%%")
|
||||
(terpri)
|
||||
(if-let (specs (delq nil specs))
|
||||
(if (not
|
||||
(or auto-accept-p
|
||||
(y-or-n-p
|
||||
(format!
|
||||
"%s\n\nThere %s %d package%s available to update. Update them?"
|
||||
(mapconcat
|
||||
(lambda (spec)
|
||||
(cl-destructuring-bind (n pretime time recipe) spec
|
||||
(straight--with-plist recipe (package)
|
||||
(format! "+ %-33s %s commit(s) behind %s -> %s"
|
||||
(yellow package) (yellow n)
|
||||
(format-time-string "%Y%m%d" pretime)
|
||||
(format-time-string "%Y%m%d" time)))))
|
||||
specs
|
||||
"\n")
|
||||
(if (cdr specs) "are" "is")
|
||||
(length specs)
|
||||
(if (cdr specs) "s" "")))))
|
||||
(ignore (print! (info "Aborted update")))
|
||||
(terpri)
|
||||
(straight--make-package-modifications-available)
|
||||
(let ((straight--packages-to-rebuild (make-hash-table :test #'equal))
|
||||
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(dolist (spec specs)
|
||||
(cl-destructuring-bind (n pretime time recipe) spec
|
||||
(straight--with-plist recipe (local-repo package)
|
||||
(let ((default-directory (straight--repos-dir local-repo)))
|
||||
(print! (start "Updating %S") package)
|
||||
(straight-merge-package package)
|
||||
;; HACK `straight-rebuild-package' doesn't pick up that
|
||||
;; this package has changed, so we do it manually. Is
|
||||
;; there a better way?
|
||||
(ignore-errors
|
||||
(delete-directory (straight--build-dir package) 'recursive))
|
||||
(puthash package t straight--packages-to-rebuild)
|
||||
(cl-incf n))
|
||||
(with-current-buffer (straight--process-get-buffer)
|
||||
(with-silent-modifications
|
||||
(print! (debug (autofill "%s") (indent 2 (buffer-string))))
|
||||
(erase-buffer))))))
|
||||
(doom--finalize-straight)
|
||||
(doom-packages-rebuild auto-accept-p))
|
||||
t)
|
||||
(print! (success "No packages to update"))
|
||||
nil))
|
||||
(error
|
||||
(message "Output:\n%s" (straight--process-get-output))
|
||||
(signal (car e) (error-message-string e)))))))
|
||||
(defun doom-cli-packages-update ()
|
||||
"Updates packages."
|
||||
(print! (start "Updating packages (this may take a while)..."))
|
||||
(let ((straight--packages-to-rebuild (make-hash-table :test #'equal))
|
||||
(total (hash-table-count straight--repo-cache))
|
||||
(i 1)
|
||||
errors)
|
||||
(print-group!
|
||||
(dolist (recipe (hash-table-values straight--repo-cache))
|
||||
(straight--with-plist recipe (package type local-repo)
|
||||
(condition-case-unless-debug e
|
||||
(let* ((default-directory (straight--repos-dir local-repo))
|
||||
(commit (straight-vc-get-commit type local-repo)))
|
||||
(if (not (straight-vc-fetch-from-remote recipe))
|
||||
(print! (warn "(%d/%d) Failed to fetch %s" i total package))
|
||||
(let ((output (straight--process-get-output)))
|
||||
(straight-merge-package package)
|
||||
(let ((newcommit (straight-vc-get-commit type local-repo)))
|
||||
(if (string= commit newcommit)
|
||||
(print! (info "(%d/%d) %s is up-to-date") i total package)
|
||||
(ignore-errors
|
||||
(delete-directory (straight--build-dir package) 'recursive))
|
||||
(puthash package t straight--packages-to-rebuild)
|
||||
(print! (success "(%d/%d) %s updated (%s -> %s)") i total package
|
||||
(substring commit 0 7)
|
||||
(substring newcommit 0 7))
|
||||
(unless (string-empty-p output)
|
||||
(print-group!
|
||||
(print! (info "%s") output)
|
||||
(when (eq type 'git)
|
||||
(straight--call "git" "log" "--oneline" newcommit (concat "^" commit))
|
||||
(print-group!
|
||||
(print! "%s" (straight--process-get-output))))))))))
|
||||
(cl-incf i))
|
||||
(user-error
|
||||
(signal 'user-error (error-message-string e)))
|
||||
(error
|
||||
(print! (warn "(%d/%d) Encountered error with %s" i total package))
|
||||
(print-group!
|
||||
(print! (error "%s" e))
|
||||
(print-group! (print! (info "%s" (straight--process-get-output)))))
|
||||
(push package errors)))))
|
||||
(when errors
|
||||
(print! (error "There were %d errors, the offending packages are: %s")
|
||||
(length errors) (string-join errors ", ")))
|
||||
(if (hash-table-empty-p straight--packages-to-rebuild)
|
||||
(ignore
|
||||
(print! (success "All %d packages are up-to-date")
|
||||
(hash-table-count straight--repo-cache)))
|
||||
(let ((count (hash-table-count straight--packages-to-rebuild))
|
||||
(packages (hash-table-keys straight--packages-to-rebuild)))
|
||||
(sort packages #'string-lessp)
|
||||
(doom--finalize-straight)
|
||||
(doom-cli-packages-build)
|
||||
(print! (success "Updated %d package(s)") count))
|
||||
t))))
|
||||
|
||||
|
||||
;;; PURGE (for the emperor)
|
||||
(defun doom--prompt-p (list-fn list preamble postamble)
|
||||
(or (y-or-n-p (format "%s%s\n\n%s"
|
||||
(if preamble (concat preamble "\n\n") "")
|
||||
(mapconcat list-fn list "\n")
|
||||
(or postamble "")))
|
||||
(user-error! "Aborted")))
|
||||
|
||||
(defun doom--prompt-columns-p (row-fn list preamble postamble)
|
||||
(doom--prompt-p (lambda (row)
|
||||
(mapconcat row-fn row ""))
|
||||
(seq-partition (cl-sort (copy-sequence list) #'string-lessp)
|
||||
3)
|
||||
preamble
|
||||
postamble))
|
||||
|
||||
(defun doom--packages-purge-build (build)
|
||||
(defun doom--cli-packages-purge-build (build)
|
||||
(let ((build-dir (straight--build-dir build)))
|
||||
(print! (start "Purging build/%s..." build))
|
||||
(delete-directory build-dir 'recursive)
|
||||
(if (file-directory-p build-dir)
|
||||
(ignore (print! (error "Failed to purg build/%s" build)))
|
||||
(print! (success "Purged build/%s" build))
|
||||
t)))
|
||||
|
||||
(defun doom--packages-purge-builds (builds &optional auto-accept-p)
|
||||
(defun doom--cli-packages-purge-builds (builds)
|
||||
(if (not builds)
|
||||
(progn (print! (info "No builds to purge"))
|
||||
0)
|
||||
(or auto-accept-p
|
||||
(doom--prompt-columns-p
|
||||
(lambda (p) (format " + %-20.20s" p)) builds nil
|
||||
(format! "Found %d orphaned package builds. Purge them?"
|
||||
(length builds))))
|
||||
(length
|
||||
(delq nil (mapcar #'doom--packages-purge-build builds)))))
|
||||
(delq nil (mapcar #'doom--cli-packages-purge-build builds)))))
|
||||
|
||||
(defun doom--packages-regraft-repo (repo)
|
||||
(defun doom--cli-packages-regraft-repo (repo)
|
||||
(let ((default-directory (straight--repos-dir repo)))
|
||||
(if (not (file-directory-p ".git"))
|
||||
(ignore (print! (warn "repos/%s is not a git repo, skipping" repo)))
|
||||
(print! (debug "Regrafting repos/%s..." repo))
|
||||
(straight--call "git" "reset" "--hard")
|
||||
(straight--call "git" "clean" "--ffd")
|
||||
(straight--call "git" "replace" "--graft" "HEAD")
|
||||
(straight--call "git" "gc")
|
||||
(print! (debug "%s" (straight--process-get-output)))
|
||||
(print! (success "Regrafted repos/%s" repo))
|
||||
(let ((before-size (doom-directory-size default-directory)))
|
||||
(straight--call "git" "reset" "--hard")
|
||||
(straight--call "git" "clean" "-ffd")
|
||||
(if (not (car (straight--call "git" "replace" "--graft" "HEAD")))
|
||||
(print! (info "repos/%s is already compact" repo))
|
||||
(straight--call "git" "gc")
|
||||
(print! (success "Regrafted repos/%s (from %0.1fKB to %0.1fKB)")
|
||||
repo before-size (doom-directory-size default-directory))
|
||||
(print-group! (print! "%s" (straight--process-get-output)))))
|
||||
t)))
|
||||
|
||||
(defun doom--packages-regraft-repos (repos &optional auto-accept-p)
|
||||
(defun doom--cli-packages-regraft-repos (repos)
|
||||
(if (not repos)
|
||||
(progn (print! (info "No repos to regraft"))
|
||||
0)
|
||||
(or auto-accept-p
|
||||
(y-or-n-p (format! "Preparing to regraft all %d repos. Continue?"
|
||||
(length repos)))
|
||||
(user-error! "Aborted!"))
|
||||
(if (executable-find "du")
|
||||
(cl-destructuring-bind (status . size)
|
||||
(doom-sh "du" "-sh" (straight--repos-dir))
|
||||
(prog1 (delq nil (mapcar #'doom--packages-regraft-repo repos))
|
||||
(cl-destructuring-bind (status . newsize)
|
||||
(doom-sh "du" "-sh" (straight--repos-dir))
|
||||
(print! (success "Finshed regrafted. Size before: %s and after: %s"
|
||||
(car (split-string size "\t"))
|
||||
(car (split-string newsize "\t")))))))
|
||||
(delq nil (mapcar #'doom--packages-regraft-repo repos)))))
|
||||
(let ((before-size (doom-directory-size (straight--repos-dir))))
|
||||
(prog1 (print-group! (delq nil (mapcar #'doom--cli-packages-regraft-repo repos)))
|
||||
(let ((after-size (doom-directory-size (straight--repos-dir))))
|
||||
(print! (success "Finished regrafting. Size before: %0.1fKB and after: %0.1fKB (%0.1fKB)")
|
||||
before-size after-size
|
||||
(- after-size before-size)))))))
|
||||
|
||||
(defun doom--packages-purge-repo (repo)
|
||||
(print! (debug "Purging repos/%s..." repo))
|
||||
(defun doom--cli-packages-purge-repo (repo)
|
||||
(let ((repo-dir (straight--repos-dir repo)))
|
||||
(delete-directory repo-dir 'recursive)
|
||||
(ignore-errors
|
||||
|
@ -422,19 +243,14 @@ a list of packages that will be updated."
|
|||
(print! (success "Purged repos/%s" repo))
|
||||
t)))
|
||||
|
||||
(defun doom--packages-purge-repos (repos &optional auto-accept-p)
|
||||
(defun doom--cli-packages-purge-repos (repos)
|
||||
(if (not repos)
|
||||
(progn (print! (info "No repos to purge"))
|
||||
0)
|
||||
(or auto-accept-p
|
||||
(doom--prompt-columns-p
|
||||
(lambda (p) (format " + %-20.20s" p)) repos nil
|
||||
(format! "Found %d orphaned repos. Purge them?"
|
||||
(length repos))))
|
||||
(length
|
||||
(delq nil (mapcar #'doom--packages-purge-repo repos)))))
|
||||
(delq nil (mapcar #'doom--cli-packages-purge-repo repos)))))
|
||||
|
||||
(defun doom--packages-purge-elpa (&optional auto-accept-p)
|
||||
(defun doom--cli-packages-purge-elpa ()
|
||||
(unless (bound-and-true-p package--initialized)
|
||||
(package-initialize))
|
||||
(let ((packages (cl-loop for (package desc) in package-alist
|
||||
|
@ -444,16 +260,11 @@ a list of packages that will be updated."
|
|||
(if (not package-alist)
|
||||
(progn (print! (info "No ELPA packages to purge"))
|
||||
0)
|
||||
(doom--prompt-columns-p
|
||||
(lambda (p) (format " + %-20.20s" p))
|
||||
(mapcar #'car packages) nil
|
||||
(format! "Found %d orphaned ELPA packages. Purge them?"
|
||||
(length package-alist)))
|
||||
(mapc (doom-rpartial #'delete-directory 'recursive)
|
||||
(mapcar #'cdr packages))
|
||||
(length packages))))
|
||||
|
||||
(defun doom-packages-purge (&optional elpa-p builds-p repos-p auto-accept-p)
|
||||
(defun doom-cli-packages-purge (&optional elpa-p builds-p repos-p regraft-repos-p)
|
||||
"Auto-removes orphaned packages and repos.
|
||||
|
||||
An orphaned package is a package that isn't a primary package (i.e. doesn't have
|
||||
|
@ -461,10 +272,7 @@ a `package!' declaration) or isn't depended on by another primary package.
|
|||
|
||||
If BUILDS-P, include straight package builds.
|
||||
If REPOS-P, include straight repos.
|
||||
If ELPA-P, include packages installed with package.el (M-x package-install).
|
||||
|
||||
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||
a list of packages that will be removed."
|
||||
If ELPA-P, include packages installed with package.el (M-x package-install)."
|
||||
(print! (start "Searching for orphaned packages to purge (for the emperor)..."))
|
||||
(cl-destructuring-bind (&optional builds-to-purge repos-to-purge repos-to-regraft)
|
||||
(let ((rdirs (straight--directory-files (straight--repos-dir) nil nil 'sort))
|
||||
|
@ -479,18 +287,20 @@ a list of packages that will be removed."
|
|||
(print-group!
|
||||
(if (not builds-p)
|
||||
(print! (info "Skipping builds"))
|
||||
(and (/= 0 (doom--packages-purge-builds builds-to-purge auto-accept-p))
|
||||
(and (/= 0 (doom--cli-packages-purge-builds builds-to-purge))
|
||||
(setq success t)
|
||||
(straight-prune-build-cache)))
|
||||
(if (not elpa-p)
|
||||
(print! (info "Skipping elpa packages"))
|
||||
(and (/= 0 (doom--packages-purge-elpa auto-accept-p))
|
||||
(and (/= 0 (doom--cli-packages-purge-elpa))
|
||||
(setq success t)))
|
||||
(if (not repos-p)
|
||||
(print! (info "Skipping repos"))
|
||||
(and (/= 0 (doom--packages-purge-repos repos-to-purge auto-accept-p))
|
||||
(setq success t))
|
||||
(and (doom--packages-regraft-repos repos-to-regraft auto-accept-p)
|
||||
(and (/= 0 (doom--cli-packages-purge-repos repos-to-purge))
|
||||
(setq success t)))
|
||||
(if (not regraft-repos-p)
|
||||
(print! (info "Skipping regrafting"))
|
||||
(and (doom--cli-packages-regraft-repos repos-to-regraft)
|
||||
(setq success t)))
|
||||
(when success
|
||||
(doom--finalize-straight)
|
||||
|
|
117
core/cli/test.el
117
core/cli/test.el
|
@ -7,17 +7,21 @@
|
|||
runemacs-binary-path
|
||||
emacs-binary-path)))
|
||||
|
||||
|
||||
(defcli! test (&rest targets)
|
||||
"Run Doom unit tests."
|
||||
(let (files error)
|
||||
:bare t
|
||||
(doom-initialize 'force)
|
||||
(require 'ansi-color)
|
||||
(let (files error read-files)
|
||||
(unless targets
|
||||
(setq targets
|
||||
(cons doom-core-dir
|
||||
(cl-remove-if-not
|
||||
(lambda (path) (file-in-directory-p path doom-emacs-dir))
|
||||
(doom-rpartial #'file-in-directory-p doom-emacs-dir)
|
||||
;; Omit `doom-private-dir', which is always first
|
||||
(let (doom-modules)
|
||||
(load! "test/init" doom-core-dir)
|
||||
(load (expand-file-name "test/init" doom-core-dir) nil t)
|
||||
(cdr (doom-module-load-path)))))))
|
||||
(while targets
|
||||
(let ((target (pop targets)))
|
||||
|
@ -29,47 +33,72 @@
|
|||
(appendq! files (nreverse (doom-glob target "test/test-*.el"))))
|
||||
((file-exists-p target)
|
||||
(push target files)))))
|
||||
(setenv "DOOMLOCALDIR" (concat doom-local-dir "test/"))
|
||||
(setenv "DOOMDIR" (concat doom-core-dir "test/"))
|
||||
(with-temp-buffer
|
||||
(print! (start "Bootstrapping test environment, if necessary..."))
|
||||
(if (zerop
|
||||
(call-process
|
||||
(doom--emacs-binary)
|
||||
nil t nil "--batch"
|
||||
"--eval" (prin1-to-string
|
||||
`(progn
|
||||
(setq doom-emacs-dir ,doom-emacs-dir
|
||||
doom-local-dir ,(concat doom-local-dir "test/")
|
||||
doom-private-dir ,(concat doom-core-dir "test/"))
|
||||
(require 'core ,(locate-library "core"))
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-modules)
|
||||
(require 'core-cli)
|
||||
(doom-reload-core-autoloads 'force)
|
||||
(when (doom-packages-install 'auto-accept)
|
||||
(doom-reload-package-autoloads 'force))))))
|
||||
(message "%s" (buffer-string))
|
||||
(message "%s" (buffer-string))
|
||||
(error "Failed to bootstrap unit tests")))
|
||||
(dolist (file files)
|
||||
(if (doom-file-cookie-p file "if" t)
|
||||
(with-temp-buffer
|
||||
(unless
|
||||
(zerop
|
||||
(apply #'call-process
|
||||
(doom--emacs-binary)
|
||||
nil t nil "--batch"
|
||||
(append (list
|
||||
"-L" doom-core-dir
|
||||
"-l" "core"
|
||||
"-l" (concat doom-core-dir "test/helpers.el"))
|
||||
(when (file-in-directory-p file doom-modules-dir)
|
||||
(list "-f" "doom-initialize-core"))
|
||||
(list
|
||||
"-l" file
|
||||
"-f" "buttercup-run"))))
|
||||
(setq error t))
|
||||
(message "%s" (buffer-string)))
|
||||
(print! (info "Ignoring %s" (relpath file)))))
|
||||
(if error
|
||||
(user-error "A test failed")
|
||||
(cl-destructuring-bind (status . output)
|
||||
(doom-exec-process
|
||||
(doom--emacs-binary)
|
||||
"--batch"
|
||||
"--eval"
|
||||
(prin1-to-string
|
||||
`(progn
|
||||
(setq user-emacs-directory ,doom-emacs-dir
|
||||
doom-auto-accept t)
|
||||
(require 'core ,(locate-library "core"))
|
||||
(require 'core-cli)
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-modules)
|
||||
(doom-cli-reload-core-autoloads 'force)
|
||||
(when (doom-cli-packages-install)
|
||||
(doom-cli-reload-package-autoloads 'force)))))
|
||||
(unless (zerop status)
|
||||
(error "Failed to bootstrap unit tests"))))
|
||||
(with-temp-buffer
|
||||
(dolist (file files)
|
||||
(if (doom-file-cookie-p file "if" t)
|
||||
(cl-destructuring-bind (_status . output)
|
||||
(apply #'doom-exec-process
|
||||
(doom--emacs-binary)
|
||||
"--batch"
|
||||
"-l" (concat doom-core-dir "core.el")
|
||||
"-l" (concat doom-core-dir "test/helpers.el")
|
||||
(append (when (file-in-directory-p file doom-modules-dir)
|
||||
(list "-f" "doom-initialize-core"))
|
||||
(list "-l" file
|
||||
"-f" "buttercup-run")))
|
||||
(insert (replace-regexp-in-string ansi-color-control-seq-regexp "" output))
|
||||
(push file read-files))
|
||||
(print! (info "Ignoring %s" (relpath file)))))
|
||||
(let ((total 0)
|
||||
(total-failed 0)
|
||||
(i 0))
|
||||
(print! "\n----------------------------------------\nTests finished")
|
||||
(print-group!
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "^Ran \\([0-9]+\\) specs, \\([0-9]+\\) failed," nil t)
|
||||
(let ((ran (string-to-number (match-string 1)))
|
||||
(failed (string-to-number (match-string 2))))
|
||||
(when (> failed 0)
|
||||
(terpri)
|
||||
(print! (warn "(%s) Failed %d/%d tests")
|
||||
(path (nth i read-files))
|
||||
failed ran)
|
||||
(save-excursion
|
||||
(print-group!
|
||||
(print!
|
||||
"%s" (string-trim
|
||||
(buffer-substring
|
||||
(match-beginning 0)
|
||||
(dotimes (_ failed (point))
|
||||
(search-backward "========================================"))))))))
|
||||
(cl-incf total ran)
|
||||
(cl-incf total-failed failed)
|
||||
(cl-incf i))))
|
||||
(terpri)
|
||||
(if (= total-failed 0)
|
||||
(print! (success "Ran %d tests successfully." total total-failed))
|
||||
(print! (error "Ran %d tests, %d failed") total total-failed)
|
||||
(kill-emacs 1)))
|
||||
t)))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
;;; core/cli/upgrade.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defcli! (upgrade up) (&rest args)
|
||||
(defcli! (upgrade up)
|
||||
((force-p ["-f" "--force"]))
|
||||
"Updates Doom and packages.
|
||||
|
||||
This requires that ~/.emacs.d is a git repo, and is the equivalent of the
|
||||
|
@ -10,22 +11,14 @@ following shell commands:
|
|||
git pull --rebase
|
||||
bin/doom clean
|
||||
bin/doom refresh
|
||||
bin/doom update
|
||||
|
||||
Switches:
|
||||
-t/--timeout TTL Seconds until a thread is timed out (default: 45)
|
||||
--threads N How many threads to use (default: 8)"
|
||||
(and (doom-upgrade doom-auto-accept
|
||||
(or (member "-f" args)
|
||||
(member "--force" args)))
|
||||
(doom-packages-update
|
||||
doom-auto-accept
|
||||
(when-let (threads (cadr (member "--threads" args)))
|
||||
(string-to-number threads))
|
||||
(when-let (timeout (cadr (or (member "--timeout" args)
|
||||
(member "-t" args))))
|
||||
(string-to-number timeout)))
|
||||
(doom-reload-package-autoloads 'force-p)))
|
||||
bin/doom update"
|
||||
:bare t
|
||||
(when (doom-cli-upgrade doom-auto-accept force-p)
|
||||
(require 'core-packages)
|
||||
(doom-initialize)
|
||||
(doom-initialize-packages)
|
||||
(when (doom-cli-packages-update)
|
||||
(doom-cli-reload-package-autoloads 'force))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -38,13 +31,13 @@ Switches:
|
|||
|
||||
(defun doom--working-tree-dirty-p (dir)
|
||||
(cl-destructuring-bind (success . stdout)
|
||||
(doom-sh "git" "status" "--porcelain" "-uno")
|
||||
(doom-call-process "git" "status" "--porcelain" "-uno")
|
||||
(if (= 0 success)
|
||||
(string-match-p "[^ \t\n]" (buffer-string))
|
||||
(error "Failed to check working tree in %s" dir))))
|
||||
|
||||
|
||||
(defun doom-upgrade (&optional auto-accept-p force-p)
|
||||
(defun doom-cli-upgrade (&optional auto-accept-p force-p)
|
||||
"Upgrade Doom to the latest version non-destructively."
|
||||
(require 'vc-git)
|
||||
(let ((default-directory doom-emacs-dir)
|
||||
|
@ -65,15 +58,15 @@ Switches:
|
|||
(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.")
|
||||
(print! (info "You have local modifications in Doom's source. Discarding them..."))
|
||||
(doom-sh "git" "reset" "--hard" (format "origin/%s" branch))
|
||||
(doom-sh "git" "clean" "-ffd")))
|
||||
(doom-call-process "git" "reset" "--hard" (format "origin/%s" branch))
|
||||
(doom-call-process "git" "clean" "-ffd")))
|
||||
|
||||
(doom-sh "git" "remote" "remove" doom-repo-remote)
|
||||
(doom-call-process "git" "remote" "remove" doom-repo-remote)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(or (zerop (car (doom-sh "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))
|
||||
(or (zerop (car (doom-sh "git" "fetch" "--tags" doom-repo-remote branch)))
|
||||
(or (zerop (car (doom-call-process "git" "fetch" "--tags" doom-repo-remote branch)))
|
||||
(error "Failed to fetch from upstream"))
|
||||
|
||||
(let ((this-rev (vc-git--rev-parse "HEAD"))
|
||||
|
@ -89,9 +82,9 @@ Switches:
|
|||
|
||||
((print! (info "A new version of Doom Emacs is available!\n\n Old revision: %s (%s)\n New revision: %s (%s)\n"
|
||||
(substring this-rev 0 10)
|
||||
(cdr (doom-sh "git" "log" "-1" "--format=%cr" "HEAD"))
|
||||
(cdr (doom-call-process "git" "log" "-1" "--format=%cr" "HEAD"))
|
||||
(substring new-rev 0 10)
|
||||
(cdr (doom-sh "git" "log" "-1" "--format=%cr" target-remote))))
|
||||
(cdr (doom-call-process "git" "log" "-1" "--format=%cr" target-remote))))
|
||||
|
||||
(when (and (not auto-accept-p)
|
||||
(y-or-n-p "View the comparison diff in your browser?"))
|
||||
|
@ -106,15 +99,13 @@ Switches:
|
|||
(print! (start "Upgrading Doom Emacs..."))
|
||||
(print-group!
|
||||
(doom-clean-byte-compiled-files)
|
||||
(unless (and (zerop (car (doom-sh "git" "reset" "--hard" target-remote)))
|
||||
(unless (and (zerop (car (doom-call-process "git" "reset" "--hard" target-remote)))
|
||||
(equal (vc-git--rev-parse "HEAD") new-rev))
|
||||
(error "Failed to check out %s" (substring new-rev 0 10)))
|
||||
(print! (success "Finished upgrading Doom Emacs")))
|
||||
(doom-delete-autoloads-file doom-autoload-file)
|
||||
(doom-delete-autoloads-file doom-package-autoload-file)
|
||||
(doom-cli-refresh "-f")
|
||||
(doom-cli-execute "refresh" (if auto-accept-p '("-y")))
|
||||
t)
|
||||
|
||||
(print! (success "Done! Restart Emacs for changes to take effect."))))))
|
||||
(ignore-errors
|
||||
(doom-sh "git" "remote" "remove" doom-repo-remote))))))
|
||||
(doom-call-process "git" "remote" "remove" doom-repo-remote))))))
|
||||
|
|
343
core/core-cli.el
343
core/core-cli.el
|
@ -2,155 +2,221 @@
|
|||
|
||||
(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
|
||||
|
||||
(defvar doom-auto-accept (getenv "YES")
|
||||
"If non-nil, Doom will auto-accept any confirmation prompts during batch
|
||||
commands like `doom-packages-install', `doom-packages-update' and
|
||||
commands like `doom-cli-packages-install', `doom-cli-packages-update' and
|
||||
`doom-packages-autoremove'.")
|
||||
|
||||
(defvar doom-cli-pre-execute-hook nil
|
||||
"TODO")
|
||||
(defvar doom-cli-post-success-execute-hook nil
|
||||
"TODO")
|
||||
|
||||
(defvar doom--cli-p nil)
|
||||
(defvar doom--cli-commands (make-hash-table :test 'equal))
|
||||
(defvar doom--cli-groups (make-hash-table :test 'equal))
|
||||
(defvar doom--cli-group nil)
|
||||
|
||||
(cl-defstruct
|
||||
(doom-cli
|
||||
(:constructor nil)
|
||||
(:constructor
|
||||
make-doom-cli
|
||||
(name &key desc aliases optlist arglist plist fn
|
||||
&aux
|
||||
(optlist
|
||||
(cl-loop for (symbol options desc) in optlist
|
||||
for ((_ . options) (_ . params))
|
||||
= (seq-group-by #'stringp options)
|
||||
collect
|
||||
(make-doom-cli-option :symbol symbol
|
||||
:flags options
|
||||
:args params
|
||||
:desc desc))))))
|
||||
(name nil :read-only t)
|
||||
(desc "TODO")
|
||||
aliases
|
||||
optlist
|
||||
arglist
|
||||
plist
|
||||
(fn (lambda (_) (print! "But nobody came!"))))
|
||||
|
||||
;;
|
||||
;;; Dispatcher API
|
||||
(cl-defstruct doom-cli-option
|
||||
(symbol)
|
||||
(flags ())
|
||||
(args ())
|
||||
(desc "TODO"))
|
||||
|
||||
(defun doom-sh (command &rest args)
|
||||
"Execute COMMAND with ARGS in the shell and return (STATUS . OUTPUT).
|
||||
(defun doom--cli-get-option (cli flag)
|
||||
(cl-find-if (doom-partial #'member flag)
|
||||
(doom-cli-optlist cli)
|
||||
:key #'doom-cli-option-flags))
|
||||
|
||||
STATUS is a boolean"
|
||||
(let ((output (get-buffer-create "*doom-sh-output*")))
|
||||
(unwind-protect
|
||||
(cons (or (apply #'call-process command nil output nil args)
|
||||
-1)
|
||||
(with-current-buffer output
|
||||
(string-trim (buffer-string))))
|
||||
(kill-buffer output))))
|
||||
(defun doom--cli-process (cli args)
|
||||
(let* ((args (copy-sequence args))
|
||||
(arglist (copy-sequence (doom-cli-arglist cli)))
|
||||
(expected (or (cl-position-if (doom-rpartial #'memq cl--lambda-list-keywords)
|
||||
arglist)
|
||||
(length arglist)))
|
||||
(got 0)
|
||||
restvar
|
||||
rest
|
||||
alist)
|
||||
(catch 'done
|
||||
(while args
|
||||
(let ((arg (pop args)))
|
||||
(cond ((eq (car arglist) '&rest)
|
||||
(setq restvar (cadr arglist)
|
||||
rest (cons arg args))
|
||||
(throw 'done t))
|
||||
|
||||
(defun doom--dispatch-command (command)
|
||||
(when (symbolp command)
|
||||
(setq command (symbol-name command)))
|
||||
(cl-check-type command string)
|
||||
(intern-soft
|
||||
(format "doom-cli-%s"
|
||||
(if (gethash command doom--cli-commands)
|
||||
command
|
||||
(cl-loop for key
|
||||
being the hash-keys in doom--cli-commands
|
||||
for aliases = (plist-get (gethash key doom--cli-commands) :aliases)
|
||||
if (member command aliases)
|
||||
return key)))))
|
||||
((string-match "^\\(--\\([a-zA-Z0-9][a-zA-Z0-9-_]*\\)\\)\\(?:=\\(.+\\)\\)?$" arg)
|
||||
(let* ((fullflag (match-string 1 arg))
|
||||
(opt (doom--cli-get-option cli fullflag)))
|
||||
(unless opt
|
||||
(user-error "Unrecognized switch %S" (concat "--" (match-string 2 arg))))
|
||||
(setf (alist-get (doom-cli-option-symbol opt) alist)
|
||||
(or (if (doom-cli-option-args opt)
|
||||
(or (match-string 3 arg)
|
||||
(pop args)
|
||||
(user-error "%S expected an argument, but got none"
|
||||
fullflag))
|
||||
(if (match-string 3 arg)
|
||||
(user-error "%S was not expecting an argument, but got %S"
|
||||
fullflag (match-string 3 arg))
|
||||
fullflag))))))
|
||||
|
||||
(defun doom--dispatch-format (desc &optional short)
|
||||
(with-temp-buffer
|
||||
(let ((fill-column 72))
|
||||
(save-excursion
|
||||
(insert desc)
|
||||
(while (re-search-backward "\n\n[^ \n]" nil t)
|
||||
(fill-paragraph))))
|
||||
(if (not short)
|
||||
(buffer-string)
|
||||
(buffer-substring (line-beginning-position)
|
||||
(line-end-position)))))
|
||||
((string-match "^\\(-\\([a-zA-Z0-9]+\\)\\)$" arg)
|
||||
(let ((fullflag (match-string 1 arg))
|
||||
(flag (match-string 2 arg)))
|
||||
(dolist (switch (split-string flag "" t))
|
||||
(if-let (opt (doom--cli-get-option cli (concat "-" switch)))
|
||||
(setf (alist-get (doom-cli-option-symbol opt) alist)
|
||||
(if (doom-cli-option-args opt)
|
||||
(or (pop args)
|
||||
(user-error "%S expected an argument, but got none"
|
||||
fullflag))
|
||||
fullflag))
|
||||
(user-error "Unrecognized switch %S" (concat "-" switch))))))
|
||||
|
||||
(defun doom--dispatch-help-1 (command)
|
||||
(cl-destructuring-bind (&key aliases hidden _group)
|
||||
(gethash command doom--cli-commands)
|
||||
(unless hidden
|
||||
(print! "%-11s\t%s\t%s"
|
||||
command (if aliases (string-join aliases ",") "")
|
||||
(doom--dispatch-format
|
||||
(documentation (doom--dispatch-command command))
|
||||
t)))))
|
||||
(arglist
|
||||
(cl-incf got)
|
||||
(let ((spec (pop arglist)))
|
||||
(when (eq spec '&optional)
|
||||
(setq spec (pop arglist)))
|
||||
(setf (alist-get spec alist) arg))
|
||||
(when (null arglist)
|
||||
(throw 'done t)))
|
||||
|
||||
(defun doom--dispatch-help (&optional fn &rest args)
|
||||
"Display help documentation for a dispatcher command. If fn and DESC are
|
||||
omitted, show all available commands, their aliases and brief descriptions."
|
||||
(if fn
|
||||
(princ (documentation fn))
|
||||
(print! (bold "%-11s\t%s\t%s" "Command:" "Alias" "Description"))
|
||||
(print-group!
|
||||
(dolist (group (seq-group-by (lambda (key) (plist-get (gethash key doom--cli-commands) :group))
|
||||
(hash-table-keys doom--cli-commands)))
|
||||
(if (null (car group))
|
||||
(mapc #'doom--dispatch-help-1 (cdr group))
|
||||
(print! "%-30s\t%s" (bold (car group)) (gethash (car group) doom--cli-groups))
|
||||
(print-group!
|
||||
(mapc #'doom--dispatch-help-1 (cdr group))))
|
||||
(terpri)))))
|
||||
(t
|
||||
(push arg args)
|
||||
(throw 'done t))))))
|
||||
(when (< got expected)
|
||||
(error "Expected %d arguments, got %d" expected got))
|
||||
(when rest
|
||||
(setf (alist-get restvar alist) rest))
|
||||
alist))
|
||||
|
||||
(defun doom-dispatch (cmd args &optional show-help)
|
||||
"Parses ARGS and invokes a dispatcher.
|
||||
(defun doom-cli-get (command)
|
||||
"Return a CLI object associated by COMMAND name (string)."
|
||||
(cond ((null command) nil)
|
||||
((doom-cli-p command) command)
|
||||
((doom-cli-get
|
||||
(gethash (cond ((symbolp command) command)
|
||||
((stringp command) (intern command))
|
||||
(command))
|
||||
doom--cli-commands)))))
|
||||
|
||||
If SHOW-HELP is non-nil, show the documentation for said dispatcher."
|
||||
(when (equal cmd "help")
|
||||
(setq show-help t)
|
||||
(when args
|
||||
(setq cmd (car args)
|
||||
args (cdr args))))
|
||||
(let ((fn (doom--dispatch-command cmd)))
|
||||
(unless (fboundp fn)
|
||||
(user-error "%S is not any command *I* know!" cmd))
|
||||
(if show-help
|
||||
(doom--dispatch-help fn args)
|
||||
(let ((start-time (current-time)))
|
||||
(run-hooks 'doom-cli-pre-execute-hook)
|
||||
(unwind-protect
|
||||
(when-let (ret (apply fn args))
|
||||
(print!
|
||||
"\n%s"
|
||||
(success "Finished! (%.4fs)"
|
||||
(float-time
|
||||
(time-subtract (current-time)
|
||||
start-time))))
|
||||
(run-hooks 'doom-cli-post-execute-hook)
|
||||
ret)
|
||||
(run-hooks 'doom-cli-post-error-execute-hook))))))
|
||||
(defun doom-cli-internal-p (cli)
|
||||
"Return non-nil if CLI is an internal (non-public) command."
|
||||
(string-prefix-p ":" (doom-cli-name cli)))
|
||||
|
||||
(defun doom-cli-execute (command &optional args)
|
||||
"Execute COMMAND (string) with ARGS (list of strings).
|
||||
|
||||
Executes a cli defined with `defcli!' with the name or alias specified by
|
||||
COMMAND, and passes ARGS to it."
|
||||
(if-let (cli (doom-cli-get command))
|
||||
(funcall (doom-cli-fn cli)
|
||||
(doom--cli-process cli args))
|
||||
(user-error "Couldn't find any %S command" command)))
|
||||
|
||||
(defmacro defcli! (name speclist &optional docstring &rest body)
|
||||
"Defines a CLI command.
|
||||
|
||||
COMMAND is a symbol or a list of symbols representing the aliases for this
|
||||
command. DOCSTRING is a string description; its first line should be short
|
||||
(under 60 characters), as it will be used as a summary for 'doom help'.
|
||||
|
||||
SPECLIST is a specification for options and arguments, which can be a list
|
||||
specification for an option/switch in the following format:
|
||||
|
||||
(VAR [FLAGS... ARGS...] DESCRIPTION)
|
||||
|
||||
Otherwise, SPECLIST accepts the same argument specifiers as `defun'.
|
||||
|
||||
BODY will be run when this dispatcher is called."
|
||||
(declare (indent 2) (doc-string 3))
|
||||
(unless (stringp docstring)
|
||||
(push docstring body)
|
||||
(setq docstring "TODO"))
|
||||
(let ((names (doom-enlist name))
|
||||
(optlist (cl-remove-if-not #'listp speclist))
|
||||
(arglist (cl-remove-if #'listp speclist))
|
||||
(plist (cl-loop for (key val) on body by #'cddr
|
||||
if (keywordp key)
|
||||
nconc (list key val) into plist
|
||||
else return plist)))
|
||||
`(let ((name ',(car names))
|
||||
(aliases ',(cdr names))
|
||||
(plist ',plist))
|
||||
(when doom--cli-group
|
||||
(setq plist (plist-put plist :group doom--cli-group)))
|
||||
(puthash
|
||||
name
|
||||
(make-doom-cli (symbol-name name)
|
||||
:desc ,docstring
|
||||
:aliases (mapcar #'symbol-name aliases)
|
||||
:arglist ',arglist
|
||||
:optlist ',optlist
|
||||
:plist plist
|
||||
:fn
|
||||
(lambda (--alist--)
|
||||
(let ,(cl-loop for opt in speclist
|
||||
for optsym = (if (listp opt) (car opt) opt)
|
||||
unless (memq optsym cl--lambda-list-keywords)
|
||||
collect (list optsym `(cdr (assq ',optsym --alist--))))
|
||||
,@(unless (plist-get plist :bare)
|
||||
'((unless doom-init-p
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-modules))))
|
||||
,@body)))
|
||||
doom--cli-commands)
|
||||
(when aliases
|
||||
(mapc (doom-rpartial #'puthash name doom--cli-commands)
|
||||
aliases)))))
|
||||
|
||||
(defmacro defcligroup! (name docstring &rest body)
|
||||
"TODO"
|
||||
"Declare all enclosed cli commands are part of the NAME group."
|
||||
(declare (indent defun) (doc-string 2))
|
||||
`(let ((doom--cli-group ,name))
|
||||
(puthash doom--cli-group ,docstring doom--cli-groups)
|
||||
,@body))
|
||||
|
||||
(defmacro defcli! (names arglist docstring &rest body)
|
||||
"Define a dispatcher command. COMMAND is a symbol or a list of symbols
|
||||
representing the aliases for this command. DESC is a string description. The
|
||||
first line should be short (under 60 letters), as it will be displayed for
|
||||
bin/doom help.
|
||||
|
||||
BODY will be run when this dispatcher is called."
|
||||
(declare (indent defun) (doc-string 3))
|
||||
(let* ((names (mapcar #'symbol-name (doom-enlist names)))
|
||||
(fn (intern (format "doom-cli-%s" (car names))))
|
||||
(plist (cl-loop while (keywordp (car body))
|
||||
collect (pop body)
|
||||
collect (pop body))))
|
||||
(macroexp-progn
|
||||
(reverse
|
||||
`((let ((plist ',plist))
|
||||
(setq plist (plist-put plist :aliases ',(cdr names)))
|
||||
(unless (or (plist-member plist :group)
|
||||
(null doom--cli-group))
|
||||
(plist-put plist :group doom--cli-group))
|
||||
(puthash ,(car names) plist doom--cli-commands))
|
||||
(defun ,fn ,arglist
|
||||
,docstring
|
||||
,@body))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Dispatch commands
|
||||
;;; CLI Commands
|
||||
|
||||
;; Load all of our subcommands
|
||||
(defcli! (refresh re) (&rest args)
|
||||
(load! "cli/help")
|
||||
(load! "cli/install")
|
||||
|
||||
(defcli! (refresh re)
|
||||
((if-necessary-p ["-n" "--if-necessary"] "Only regenerate autoloads files if necessary"))
|
||||
"Ensure Doom is properly set up.
|
||||
|
||||
This is the equivalent of running autoremove, install, autoloads, then
|
||||
|
@ -165,36 +231,25 @@ It will ensure that unneeded packages are removed, all needed packages are
|
|||
installed, autoloads files are up-to-date and no byte-compiled files have gone
|
||||
stale."
|
||||
(print! (green "Initiating a refresh of Doom Emacs...\n"))
|
||||
(let ((force-p (or (member "-f" args)
|
||||
(member "--force" args)))
|
||||
success)
|
||||
(let (success)
|
||||
(when (file-exists-p doom-env-file)
|
||||
(doom-reload-env-file 'force))
|
||||
(doom-reload-core-autoloads force-p)
|
||||
(doom-cli-reload-env-file 'force))
|
||||
(doom-cli-reload-core-autoloads (not if-necessary-p))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(and (doom-packages-install doom-auto-accept)
|
||||
(and (doom-cli-packages-install)
|
||||
(setq success t))
|
||||
(and (doom-packages-rebuild doom-auto-accept)
|
||||
(and (doom-cli-packages-build)
|
||||
(setq success t))
|
||||
(and (doom-packages-purge nil 'builds-p nil doom-auto-accept)
|
||||
(and (doom-cli-packages-purge nil 'builds-p nil)
|
||||
(setq success t)))
|
||||
(doom-reload-package-autoloads (or success force-p))
|
||||
(doom-byte-compile nil 'recompile))
|
||||
(doom-cli-reload-package-autoloads (or success (not if-necessary-p)))
|
||||
(doom-cli-byte-compile nil 'recompile))
|
||||
t))
|
||||
|
||||
|
||||
;; Load all of our subcommands
|
||||
(load! "cli/install")
|
||||
|
||||
(defcligroup! "Diagnostics"
|
||||
"For troubleshooting and diagnostics"
|
||||
(defcli! (doctor doc) ()
|
||||
"Checks for issues with your environment & Doom config.
|
||||
|
||||
Use the doctor to diagnose common problems or list missing dependencies in
|
||||
enabled modules.")
|
||||
|
||||
(load! "cli/doctor")
|
||||
(load! "cli/debug")
|
||||
(load! "cli/test"))
|
||||
|
||||
|
@ -205,8 +260,8 @@ enabled modules.")
|
|||
(load! "cli/packages")
|
||||
(load! "cli/autoloads"))
|
||||
|
||||
(defcligroup! "Byte compilation"
|
||||
"For byte-compiling Doom and your config"
|
||||
(defcligroup! "Compilation"
|
||||
"For compiling Doom and your config"
|
||||
(load! "cli/byte-compile"))
|
||||
|
||||
(defcligroup! "Utilities"
|
||||
|
@ -214,7 +269,7 @@ enabled modules.")
|
|||
(defcli! run ()
|
||||
"Run Doom Emacs from bin/doom's parent directory.
|
||||
|
||||
All arguments are passed on to Emacs (except for -p and -e).
|
||||
All arguments are passed on to Emacs.
|
||||
|
||||
doom run
|
||||
doom run -nw init.el
|
||||
|
|
|
@ -3,41 +3,6 @@
|
|||
(require 'cl-lib)
|
||||
(require 'subr-x)
|
||||
|
||||
;; DEPRECATED Polyfills
|
||||
(unless EMACS26+
|
||||
(with-no-warnings
|
||||
;; `kill-current-buffer' was introduced in Emacs 26
|
||||
(defalias 'kill-current-buffer #'kill-this-buffer)
|
||||
;; if-let and when-let were moved to (if|when)-let* in Emacs 26+ so we alias
|
||||
;; them for 25 users.
|
||||
(defalias 'if-let* #'if-let)
|
||||
(defalias 'when-let* #'when-let)
|
||||
|
||||
;; `mapcan' was introduced in 26.1. `cl-mapcan' isn't a perfect replacement,
|
||||
;; but it's close enough.
|
||||
(defalias 'mapcan #'cl-mapcan)
|
||||
|
||||
(defun alist-get (key alist &optional default remove testfn)
|
||||
"Return the value associated with KEY in ALIST.
|
||||
If KEY is not found in ALIST, return DEFAULT.
|
||||
Use TESTFN to lookup in the alist if non-nil. Otherwise, use `assq'.
|
||||
|
||||
This is a generalized variable suitable for use with `setf'.
|
||||
When using it to set a value, optional argument REMOVE non-nil
|
||||
means to remove KEY from ALIST if the new value is `eql' to DEFAULT."
|
||||
(ignore remove) ;;Silence byte-compiler.
|
||||
(let ((x (if (not testfn)
|
||||
(assq key alist)
|
||||
;; In Emacs<26, `assoc' has no testfn arg, so we have to
|
||||
;; implement it ourselves
|
||||
(if testfn
|
||||
(cl-loop for entry in alist
|
||||
if (funcall testfn key entry)
|
||||
return entry)
|
||||
(assoc key alist)))))
|
||||
(if x (cdr x) default)))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
|
|
|
@ -161,15 +161,20 @@ missing) and shouldn't be deleted.")
|
|||
(push func options)
|
||||
(print! "%2s) %s" (length options) desc)))))
|
||||
(terpri)
|
||||
(let ((answer
|
||||
(read-number (format! "How to proceed? (%s) "
|
||||
(mapconcat #'number-to-string
|
||||
(number-sequence 1 (length options))
|
||||
", "))))
|
||||
fn)
|
||||
(setq options (nreverse options))
|
||||
(while (not (setq fn (nth (1- answer) options)))
|
||||
(print! "%s is not a valid answer, try again." answer))
|
||||
(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))))))
|
||||
|
||||
|
||||
|
@ -249,7 +254,7 @@ necessary package metadata is initialized and available for them."
|
|||
;;; Module package macros
|
||||
|
||||
(cl-defmacro package!
|
||||
(name &rest plist &key built-in _recipe disable ignore _freeze)
|
||||
(name &rest plist &key built-in recipe ignore _disable _freeze)
|
||||
"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
|
||||
|
@ -277,6 +282,13 @@ Accepts the following properties:
|
|||
Returns t if package is successfully registered, and nil if it was disabled
|
||||
elsewhere."
|
||||
(declare (indent defun))
|
||||
(when (and recipe (keywordp (car-safe recipe)))
|
||||
(plist-put! plist :recipe `(quote ,recipe)))
|
||||
(when built-in
|
||||
(when (and (not ignore) (equal built-in '(quote prefer)))
|
||||
(setq built-in `(locate-library ,(symbol-name name) nil doom--initial-load-path)))
|
||||
(plist-delete! plist :built-in)
|
||||
(plist-put! plist :ignore built-in))
|
||||
`(let* ((name ',name)
|
||||
(plist (cdr (assq name doom-packages))))
|
||||
(let ((module-list (plist-get plist :modules))
|
||||
|
@ -287,33 +299,23 @@ elsewhere."
|
|||
(list module)
|
||||
nil))))
|
||||
|
||||
;; Handle :built-in
|
||||
(let ((built-in ,built-in))
|
||||
(unless ,ignore
|
||||
(when built-in
|
||||
(doom-log "Ignoring built-in package %S" name)
|
||||
(when (eq built-in 'prefer)
|
||||
(setq built-in (locate-library (symbol-name name) nil doom--initial-load-path))))
|
||||
(plist-put! plist :ignore built-in)))
|
||||
|
||||
;; DEPRECATED Translate :fetcher to :host
|
||||
(with-plist! plist (recipe)
|
||||
(with-plist! recipe (fetcher)
|
||||
(when fetcher
|
||||
(message "%s\n%s"
|
||||
(format "WARNING: The :fetcher property was used for the %S package."
|
||||
name)
|
||||
"This property is deprecated. Replace it with :host.")
|
||||
(plist-put! recipe :host fetcher)
|
||||
(plist-delete! recipe :fetcher))
|
||||
(plist-put! plist :recipe recipe)))
|
||||
|
||||
(doplist! ((prop val) ',plist plist)
|
||||
(doplist! ((prop val) (list ,@plist) plist)
|
||||
(unless (null val)
|
||||
(plist-put! plist prop val)))
|
||||
|
||||
;; Some basic key validation; error if you're not using a valid key
|
||||
(condition-case e
|
||||
(cl-destructuring-bind
|
||||
(&key _local-repo _files _flavor _no-build
|
||||
_type _repo _host _branch _remote _nonrecursive _fork _depth)
|
||||
(plist-get plist :recipe))
|
||||
(error
|
||||
(signal 'doom-package-error
|
||||
(cons ,(symbol-name name)
|
||||
(error-message-string e)))))
|
||||
|
||||
(setf (alist-get name doom-packages) plist)
|
||||
(if (not ,disable) t
|
||||
(if (not (plist-get plist :disable)) t
|
||||
(doom-log "Disabling package %S" name)
|
||||
(cl-pushnew name doom-disabled-packages)
|
||||
nil)))
|
||||
|
|
|
@ -72,9 +72,9 @@ Emacs.")
|
|||
|
||||
;; Disable commands that won't work, as is, and that Doom already provides a
|
||||
;; better alternative for.
|
||||
(put 'projectile-ag 'disabled "Use +{ivy,helm}/project-search or +{ivy,helm}/ag instead")
|
||||
(put 'projectile-ripgrep 'disabled "Use +{ivy,helm}/project-search or +{ivy,helm}/rg instead")
|
||||
(put 'projectile-grep 'disabled "Use +{ivy,helm}/project-search or +{ivy,helm}/grep instead")
|
||||
(put 'projectile-ag 'disabled "Use +{ivy,helm}/project-search instead")
|
||||
(put 'projectile-ripgrep 'disabled "Use +{ivy,helm}/project-search instead")
|
||||
(put 'projectile-grep 'disabled "Use +{ivy,helm}/project-search instead")
|
||||
|
||||
;; Treat current directory in dired as a "file in a project" and track it
|
||||
(add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
|
||||
|
|
|
@ -366,9 +366,7 @@ treat Emacs as a non-application window."
|
|||
(setq ansi-color-for-comint-mode t)
|
||||
|
||||
|
||||
(use-package! compile
|
||||
:defer t
|
||||
:config
|
||||
(after! compile
|
||||
(setq compilation-always-kill t ; kill compilation process before starting another
|
||||
compilation-ask-about-save nil ; save all buffers on `compile'
|
||||
compilation-scroll-output 'first-error)
|
||||
|
@ -376,9 +374,7 @@ treat Emacs as a non-application window."
|
|||
(add-hook 'compilation-filter-hook #'doom-apply-ansi-color-to-compilation-buffer-h))
|
||||
|
||||
|
||||
(use-package! ediff
|
||||
:defer t
|
||||
:config
|
||||
(after! ediff
|
||||
(setq ediff-diff-options "-w" ; turn off whitespace checking
|
||||
ediff-split-window-function #'split-window-horizontally
|
||||
ediff-window-setup-function #'ediff-setup-windows-plain)
|
||||
|
@ -512,79 +508,6 @@ treat Emacs as a non-application window."
|
|||
(defun doom-enable-line-numbers-h () (display-line-numbers-mode +1))
|
||||
(defun doom-disable-line-numbers-h () (display-line-numbers-mode -1))
|
||||
|
||||
;; DEPRECATED `nlinum' is used for Emacs 25 users; 26+ has native line numbers.
|
||||
(use-package! nlinum
|
||||
;; Line number column. A faster (or equivalent, in the worst case) line number
|
||||
;; plugin than `linum-mode'.
|
||||
:unless EMACS26+
|
||||
:defer t
|
||||
:init
|
||||
(defvar doom-line-number-lpad 4
|
||||
"How much padding to place before line numbers.")
|
||||
(defvar doom-line-number-rpad 1
|
||||
"How much padding to place after line numbers.")
|
||||
(defvar doom-line-number-pad-char 32
|
||||
"Character to use for padding line numbers.
|
||||
|
||||
By default, this is a space character. If you use `whitespace-mode' with
|
||||
`space-mark', the whitespace in line numbers will be affected (this can look
|
||||
ugly). In this case, you can change this to ?\u2002, which is a unicode
|
||||
character that looks like a space that `whitespace-mode' won't affect.")
|
||||
:config
|
||||
(setq nlinum-highlight-current-line t)
|
||||
|
||||
;; Fix lingering hl-line overlays (caused by nlinum)
|
||||
(add-hook! 'hl-line-mode-hook
|
||||
(remove-overlays (point-min) (point-max) 'face 'hl-line))
|
||||
|
||||
(defun doom-nlinum-format-fn (line _width)
|
||||
"A more customizable `nlinum-format-function'. See `doom-line-number-lpad',
|
||||
`doom-line-number-rpad' and `doom-line-number-pad-char'. Allows a fix for
|
||||
`whitespace-mode' space-marks appearing inside the line number."
|
||||
(let ((str (number-to-string line)))
|
||||
(setq str (concat (make-string (max 0 (- doom-line-number-lpad (length str)))
|
||||
doom-line-number-pad-char)
|
||||
str
|
||||
(make-string doom-line-number-rpad doom-line-number-pad-char)))
|
||||
(put-text-property 0 (length str) 'face
|
||||
(if (and nlinum-highlight-current-line
|
||||
(= line nlinum--current-line))
|
||||
'nlinum-current-line
|
||||
'linum)
|
||||
str)
|
||||
str))
|
||||
(setq nlinum-format-function #'doom-nlinum-format-fn)
|
||||
|
||||
(add-hook! 'nlinum-mode-hook
|
||||
(defun doom-init-nlinum-width-h ()
|
||||
"Calculate line number column width beforehand (optimization)."
|
||||
(setq nlinum--width
|
||||
(length (save-excursion (goto-char (point-max))
|
||||
(format-mode-line "%l")))))))
|
||||
|
||||
(use-package! nlinum-hl
|
||||
;; Fixes disappearing line numbers in nlinum and other quirks
|
||||
:unless EMACS26+
|
||||
:after nlinum
|
||||
:config
|
||||
;; With `markdown-fontify-code-blocks-natively' enabled in `markdown-mode',
|
||||
;; line numbers tend to vanish next to code blocks.
|
||||
(advice-add #'markdown-fontify-code-block-natively
|
||||
:after #'nlinum-hl-do-markdown-fontify-region)
|
||||
;; When using `web-mode's code-folding an entire range of line numbers will
|
||||
;; vanish in the affected area.
|
||||
(advice-add #'web-mode-fold-or-unfold :after #'nlinum-hl-do-generic-flush)
|
||||
;; Changing fonts can leave nlinum line numbers in their original size; this
|
||||
;; forces them to resize.
|
||||
(add-hook 'after-setting-font-hook #'nlinum-hl-flush-all-windows))
|
||||
|
||||
(use-package! nlinum-relative
|
||||
:unless EMACS26+
|
||||
:defer t
|
||||
:config
|
||||
(setq nlinum-format " %d ")
|
||||
(add-hook 'evil-mode-hook #'nlinum-relative-setup-evil))
|
||||
|
||||
|
||||
;;
|
||||
;;; Theme & font
|
||||
|
|
58
core/core.el
58
core/core.el
|
@ -1,14 +1,13 @@
|
|||
;;; core.el --- the heart of the beast -*- lexical-binding: t; -*-
|
||||
|
||||
(when (version< emacs-version "25.3")
|
||||
(error "Detected Emacs %s. Doom only supports Emacs 25.3 and higher"
|
||||
(when (version< emacs-version "26.1")
|
||||
(error "Detected Emacs %s. Doom only supports Emacs 26.1 and higher"
|
||||
emacs-version))
|
||||
|
||||
(defconst doom-version "2.0.9"
|
||||
"Current version of Doom Emacs.")
|
||||
|
||||
(defconst EMACS26+ (> emacs-major-version 25))
|
||||
(defconst EMACS27+ (> emacs-major-version 26))
|
||||
(defconst EMACS27+ (> emacs-major-version 26))
|
||||
(defconst IS-MAC (eq system-type 'darwin))
|
||||
(defconst IS-LINUX (eq system-type 'gnu/linux))
|
||||
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
|
||||
|
@ -29,6 +28,8 @@
|
|||
;; Load the bare necessities
|
||||
(require 'core-lib)
|
||||
|
||||
(autoload 'doom-initialize-packages "core-packages")
|
||||
|
||||
|
||||
;;
|
||||
;;; Global variables
|
||||
|
@ -209,6 +210,7 @@ users).")
|
|||
tramp-auto-save-directory (concat doom-cache-dir "tramp-auto-save/")
|
||||
tramp-backup-directory-alist backup-directory-alist
|
||||
tramp-persistency-file-name (concat doom-cache-dir "tramp-persistency.el")
|
||||
tramp-histfile-override (concat doom-cache-dir "tramp-histfile.el")
|
||||
url-cache-directory (concat doom-cache-dir "url/")
|
||||
url-configuration-directory (concat doom-etc-dir "url/")
|
||||
gamegrid-user-score-file-directory (concat doom-etc-dir "games/"))
|
||||
|
@ -426,35 +428,35 @@ in interactive sessions, nil otherwise (but logs a warning)."
|
|||
(let (command-switch-alist)
|
||||
(load (substring file 0 -3) 'noerror 'nomessage))
|
||||
((debug error)
|
||||
(if doom-interactive-mode
|
||||
(message "Autoload file warning: %s -> %s" (car e) (error-message-string e))
|
||||
(signal 'doom-autoload-error (list (file-name-nondirectory file) e))))))
|
||||
(message "Autoload file error: %s -> %s" (file-name-nondirectory file) e)
|
||||
nil)))
|
||||
|
||||
(defun doom-load-envvars-file (file &optional noerror)
|
||||
"Read and set envvars from FILE."
|
||||
(if (not (file-readable-p file))
|
||||
(unless noerror
|
||||
(signal 'file-error (list "Couldn't read envvar file" file)))
|
||||
(let (vars)
|
||||
(let (environment)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(while (re-search-forward "\n *\\([^#][^= \n]+\\)=" nil t)
|
||||
(save-excursion
|
||||
(let ((var (string-trim-left (match-string 1)))
|
||||
(value (buffer-substring-no-properties
|
||||
(point)
|
||||
(1- (or (when (re-search-forward "^\\([^= ]+\\)=" nil t)
|
||||
(line-beginning-position))
|
||||
(point-max))))))
|
||||
(push (cons var value) vars)
|
||||
(setenv var value)))))
|
||||
(when vars
|
||||
(save-excursion
|
||||
(insert "\n")
|
||||
(insert-file-contents file))
|
||||
(while (re-search-forward "\n *\\([^#= \n]*\\)=" nil t)
|
||||
(push (buffer-substring
|
||||
(match-beginning 1)
|
||||
(1- (or (save-excursion
|
||||
(when (re-search-forward "^\\([^= ]+\\)=" nil t)
|
||||
(line-beginning-position)))
|
||||
(point-max))))
|
||||
environment)))
|
||||
(when environment
|
||||
(setq-default
|
||||
process-environment (nreverse environment)
|
||||
exec-path (append (parse-colon-path (getenv "PATH"))
|
||||
(list exec-directory))
|
||||
shell-file-name (or (getenv "SHELL")
|
||||
shell-file-name))
|
||||
(nreverse vars)))))
|
||||
process-environment))))
|
||||
|
||||
(defun doom-initialize (&optional force-p)
|
||||
"Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil).
|
||||
|
@ -504,16 +506,12 @@ to least)."
|
|||
(let (;; `doom-autoload-file' tells Emacs where to load all its functions
|
||||
;; from. This includes everything in core/autoload/*.el and autoload
|
||||
;; files in enabled modules.
|
||||
(core-autoloads-p
|
||||
(with-demoted-errors "Core autoload error: %s"
|
||||
(doom-load-autoloads-file doom-autoload-file)))
|
||||
(core-autoloads-p (doom-load-autoloads-file doom-autoload-file))
|
||||
;; Loads `doom-package-autoload-file', which loads a concatenated
|
||||
;; package autoloads file which caches `load-path', `auto-mode-alist',
|
||||
;; `Info-directory-list', and `doom-disabled-packages'. A big
|
||||
;; reduction in startup time.
|
||||
(pkg-autoloads-p
|
||||
(with-demoted-errors "Package autoload error: %s"
|
||||
(doom-load-autoloads-file doom-package-autoload-file))))
|
||||
(pkg-autoloads-p (doom-load-autoloads-file doom-package-autoload-file)))
|
||||
|
||||
(if (and core-autoloads-p pkg-autoloads-p (not force-p))
|
||||
;; In case we want to use package.el or straight via M-x
|
||||
|
@ -524,12 +522,6 @@ to least)."
|
|||
(require 'core-packages)
|
||||
(doom-initialize-packages)))
|
||||
|
||||
;; Eagerly load these libraries because we may be in a session that
|
||||
;; hasn't been fully initialized (e.g. where autoloads files haven't
|
||||
;; been generated or `load-path' populated).
|
||||
(mapc (doom-rpartial #'load 'noerror 'nomessage)
|
||||
(file-expand-wildcards (concat doom-core-dir "autoload/*.el")))
|
||||
|
||||
;; Create all our core directories to quell file errors
|
||||
(dolist (dir (list doom-local-dir
|
||||
doom-etc-dir
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
;;; core/doctor.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun file-size (file &optional dir)
|
||||
(setq file (expand-file-name file dir))
|
||||
(when (file-exists-p file)
|
||||
(/ (nth 7 (file-attributes file))
|
||||
1024.0)))
|
||||
|
||||
;; Check for oversized problem files in cache that may cause unusual/tremendous
|
||||
;; delays or freezing. This shouldn't happen often.
|
||||
(dolist (file (list "savehist"
|
||||
"projectile.cache"))
|
||||
(let* ((path (expand-file-name file doom-cache-dir))
|
||||
(size (file-size path)))
|
||||
(when (and (numberp size) (> size 2000))
|
||||
(warn! "%s is too large (%.02fmb). This may cause freezes or odd startup delays"
|
||||
(file-relative-name path doom-core-dir)
|
||||
(/ size 1024))
|
||||
(explain! "Consider deleting it from your system (manually)"))))
|
||||
|
||||
(unless (ignore-errors (executable-find doom-projectile-fd-binary))
|
||||
(warn! "Couldn't find the `fd' binary; project file searches will be slightly slower")
|
||||
(unless (executable-find "rg")
|
||||
(warn! "Couldn't find the `rg' binary either; project file searches will be even slower")))
|
||||
|
||||
(let ((default-directory "~"))
|
||||
(require 'projectile)
|
||||
(when (cl-find-if #'projectile-file-exists-p projectile-project-root-files-bottom-up)
|
||||
(warn! "Your $HOME is recognized as a project root")
|
||||
(explain! "Doom will disable bottom-up root search, which may reduce the accuracy of project\n"
|
||||
"detection.")))
|
||||
|
||||
;; There should only be one
|
||||
(when (and (file-equal-p doom-private-dir "~/.config/doom")
|
||||
(file-directory-p "~/.doom.d"))
|
||||
(warn! "Both %S and '~/.doom.d' exist on your system"
|
||||
(abbreviate-file-name doom-private-dir))
|
||||
(explain! "Doom will only load one of these (~/.config/doom takes precedence). Possessing\n"
|
||||
"both is rarely intentional; you should one or the other."))
|
||||
|
||||
;; Check for fonts
|
||||
(if (not (fboundp 'find-font))
|
||||
(progn
|
||||
(warn! "Warning: unable to detect font")
|
||||
(explain! "The `find-font' function is missing. This could indicate the incorrect "
|
||||
"version of Emacs is being used!"))
|
||||
;; all-the-icons fonts
|
||||
(let ((font-dest (pcase system-type
|
||||
(`gnu/linux (concat (or (getenv "XDG_DATA_HOME")
|
||||
"~/.local/share")
|
||||
"/fonts/"))
|
||||
(`darwin "~/Library/Fonts/"))))
|
||||
(when (and font-dest (require 'all-the-icons nil t))
|
||||
(dolist (font all-the-icons-font-families)
|
||||
(if (sh "fc-list | grep %s" font)
|
||||
(success! "Found font %s" font)
|
||||
(warn! "Warning: couldn't find %s font in %s"
|
||||
font font-dest)
|
||||
(explain! "You can install it by running `M-x all-the-icons-install-fonts' within Emacs.\n\n"
|
||||
"This could also mean you've installed them in non-standard locations, in which "
|
||||
"case feel free to ignore this warning."))))))
|
|
@ -9,12 +9,6 @@
|
|||
(package! all-the-icons)
|
||||
(package! hide-mode-line)
|
||||
(package! highlight-numbers)
|
||||
;; Some early 26.x builds of Emacs do not have `display-line-numbers' yet, so
|
||||
;; check for it instead of Emacs' version.
|
||||
(unless (locate-library "display-line-numbers")
|
||||
(package! nlinum)
|
||||
(package! nlinum-hl)
|
||||
(package! nlinum-relative))
|
||||
(package! rainbow-delimiters)
|
||||
(package! restart-emacs)
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
;;
|
||||
;;; Buttercup extensions
|
||||
|
||||
(buttercup-define-matcher-for-binary-function :to-equal-file file-equal-p)
|
||||
|
||||
(buttercup-define-matcher :to-expand-into (form expected)
|
||||
(cl-destructuring-bind (form expected)
|
||||
(mapcar #'funcall (list form expected))
|
||||
|
|
|
@ -19,11 +19,23 @@
|
|||
(kill-buffer c)
|
||||
(kill-buffer d))
|
||||
|
||||
(describe "buffer-list"
|
||||
(it "should only see four buffers"
|
||||
(expect (doom-buffer-list) :to-contain-items (list a b c d))))
|
||||
(describe "buffer lists"
|
||||
(describe "doom-buffer-list"
|
||||
(it "should only see four buffers"
|
||||
(expect (doom-buffer-list) :to-contain-items (list a b c d)))))
|
||||
|
||||
(describe "project-buffer-list"
|
||||
;; TODO predicate tests
|
||||
(xdescribe "predicate functions"
|
||||
(describe "doom-dired-buffer-p")
|
||||
(describe "doom-special-buffer-p")
|
||||
(describe "doom-temp-buffer-p")
|
||||
(describe "doom-visible-buffer-p")
|
||||
(describe "doom-buried-buffer-p")
|
||||
(describe "doom-non-file-visiting-buffer-p")
|
||||
(describe "doom-dired-buffer-p")
|
||||
(describe "doom-buffer-frame-predicate"))
|
||||
|
||||
(describe "doom-project-buffer-list"
|
||||
:var (projectile-projects-cache-time projectile-projects-cache)
|
||||
(before-all (require 'projectile))
|
||||
(after-all (unload-feature 'projectile t))
|
||||
|
@ -47,7 +59,7 @@
|
|||
(expect (doom-project-buffer-list)
|
||||
:to-have-same-items-as (buffer-list)))))
|
||||
|
||||
(describe "fallback-buffer"
|
||||
(describe "doom-fallback-buffer"
|
||||
(it "returns a live buffer"
|
||||
(expect (buffer-live-p (doom-fallback-buffer))))
|
||||
|
||||
|
@ -56,12 +68,22 @@
|
|||
|
||||
(describe "real buffers"
|
||||
(before-each
|
||||
(doom-set-buffer-real a t)
|
||||
(with-current-buffer b (setq buffer-file-name "x"))
|
||||
(with-current-buffer c (rename-buffer "*C*")))
|
||||
|
||||
(describe "real-buffer-p"
|
||||
(describe "doom-mark-buffer-as-real-h"
|
||||
(with-current-buffer a
|
||||
(doom-mark-buffer-as-real-h)
|
||||
(expect (buffer-local-value 'doom-real-buffer-p a))))
|
||||
|
||||
(describe "doom-set-buffer-real"
|
||||
(it "sets `doom-real-buffer-p' buffer-locally"
|
||||
(doom-set-buffer-real a t)
|
||||
(expect (buffer-local-value 'doom-real-buffer-p a))))
|
||||
|
||||
(describe "doom-real-buffer-p"
|
||||
(it "returns t for buffers manually marked real"
|
||||
(doom-set-buffer-real a t)
|
||||
(expect (doom-real-buffer-p a)))
|
||||
(it "returns t for file-visiting buffers"
|
||||
(expect (doom-real-buffer-p b)))
|
||||
|
@ -69,7 +91,16 @@
|
|||
(expect (doom-real-buffer-p c) :to-be nil)
|
||||
(expect (doom-real-buffer-p d) :to-be nil)))
|
||||
|
||||
(describe "real-buffer-list"
|
||||
(describe "doom-unreal-buffer-p"
|
||||
(it "returns t for unreal buffers"
|
||||
(expect (doom-unreal-buffer-p c))
|
||||
(expect (doom-unreal-buffer-p d)))
|
||||
(it "returns nil for real buffers"
|
||||
(doom-set-buffer-real a t)
|
||||
(expect (not (doom-unreal-buffer-p a)))
|
||||
(expect (not (doom-unreal-buffer-p b)))))
|
||||
|
||||
(describe "doom-real-buffer-list"
|
||||
(it "returns only real buffers"
|
||||
(expect (doom-real-buffer-list) :to-contain-items (list a b)))))
|
||||
|
||||
|
@ -82,36 +113,48 @@
|
|||
(split-window)
|
||||
(switch-to-buffer b))
|
||||
|
||||
(it "can match buffers by regexp"
|
||||
(expect (doom-matching-buffers "^[ac]$") :to-have-same-items-as (list a c)))
|
||||
(describe "doom-matching-buffers"
|
||||
(it "can match buffers by regexp"
|
||||
(expect (doom-matching-buffers "^[ac]$") :to-have-same-items-as (list a c))))
|
||||
|
||||
(it "can match buffers by major-mode"
|
||||
(expect (doom-buffers-in-mode 'text-mode) :to-have-same-items-as (list b c)))
|
||||
(describe "doom-buffers-in-mode"
|
||||
(it "can match buffers by major-mode"
|
||||
(expect (doom-buffers-in-mode 'text-mode) :to-have-same-items-as (list b c))))
|
||||
|
||||
(it "can find all buried buffers"
|
||||
(expect (doom-buried-buffers) :to-contain-items (list c d)))
|
||||
(describe "doom-buried-buffers"
|
||||
(it "can find all buried buffers"
|
||||
(expect (doom-buried-buffers) :to-contain-items (list c d))))
|
||||
|
||||
(it "can find all visible buffers"
|
||||
(expect (doom-visible-buffers)
|
||||
:to-have-same-items-as (list a b)))
|
||||
(describe "doom-visible-buffers"
|
||||
(it "can find all visible buffers"
|
||||
(expect (doom-visible-buffers)
|
||||
:to-have-same-items-as (list a b))))
|
||||
|
||||
(it "can find all visible windows"
|
||||
(expect (doom-visible-windows)
|
||||
:to-have-same-items-as
|
||||
(mapcar #'get-buffer-window (list a b)))))
|
||||
(describe "doom-visible-windows"
|
||||
(it "can find all visible windows"
|
||||
(expect (doom-visible-windows)
|
||||
:to-have-same-items-as
|
||||
(mapcar #'get-buffer-window (list a b))))))
|
||||
|
||||
(describe "kill-buffer-and-windows"
|
||||
(before-each
|
||||
(split-window) (switch-to-buffer b)
|
||||
(split-window) (switch-to-buffer a))
|
||||
(describe "killing buffers/windows"
|
||||
(describe "doom-kill-buffer-and-windows"
|
||||
(before-each
|
||||
(split-window) (switch-to-buffer b)
|
||||
(split-window) (switch-to-buffer a))
|
||||
|
||||
(it "kills the selected buffers and all its windows"
|
||||
(doom-kill-buffer-and-windows a)
|
||||
(expect (buffer-live-p a) :to-be nil)
|
||||
(expect (length (doom-visible-windows)) :to-be 1)))
|
||||
(it "kills the selected buffers and all its windows"
|
||||
(doom-kill-buffer-and-windows a)
|
||||
(expect (buffer-live-p a) :to-be nil)
|
||||
(expect (length (doom-visible-windows)) :to-be 1)))
|
||||
|
||||
;; TODO
|
||||
(xdescribe "kill-all-buffers")
|
||||
(xdescribe "kill-other-buffers")
|
||||
(xdescribe "kill-matching-buffers")
|
||||
(xdescribe "cleanup-session")))
|
||||
;; TODO
|
||||
(xdescribe "doom-fixup-windows")
|
||||
(xdescribe "doom-kill-buffer-fixup-windows")
|
||||
(xdescribe "doom-kill-buffers-fixup-windows"))
|
||||
|
||||
(xdescribe "commands"
|
||||
(describe "doom/kill-all-buffers")
|
||||
(describe "doom/kill-other-buffers")
|
||||
(describe "doom/kill-matching-buffers")
|
||||
(describe "doom/kill-buried-buffers")
|
||||
(describe "doom/kill-project-buffers"))))
|
||||
|
|
|
@ -5,11 +5,6 @@
|
|||
|
||||
(load! "autoload/files" doom-core-dir)
|
||||
|
||||
(xdescribe "doom-glob")
|
||||
(xdescribe "doom-path")
|
||||
(xdescribe "doom-dir")
|
||||
(xdescribe "doom-files-in")
|
||||
|
||||
(describe "library"
|
||||
(describe "file-exists-p!"
|
||||
(it "is a (quasi) drop-in replacement for `file-exists-p'"
|
||||
|
@ -96,7 +91,16 @@
|
|||
(getfilename))
|
||||
"LICENSE")
|
||||
doom-emacs-dir)
|
||||
:to-equal (expand-file-name "LICENSE" doom-emacs-dir))))))
|
||||
:to-equal (expand-file-name "LICENSE" doom-emacs-dir)))))
|
||||
|
||||
;; TODO
|
||||
(xdescribe "doom-glob")
|
||||
(xdescribe "doom-path")
|
||||
(xdescribe "doom-dir")
|
||||
(xdescribe "doom-files-in")
|
||||
(xdescribe "doom-file-size")
|
||||
(xdescribe "doom-directory-size")
|
||||
(xdescribe "doom-file-cookie-p"))
|
||||
|
||||
(describe "interactive file operations"
|
||||
:var (src dest projectile-projects-cache-time projectile-projects-cache)
|
||||
|
@ -149,4 +153,12 @@
|
|||
(expect (file-exists-p existing) :to-be nil))
|
||||
(it "prompts to delete any existing file"
|
||||
(quiet! (doom/delete-this-file existing))
|
||||
(expect 'y-or-n-p :to-have-been-called-times 1)))))
|
||||
(expect 'y-or-n-p :to-have-been-called-times 1))))
|
||||
|
||||
(xdescribe "sudo {this,find} file"
|
||||
(before-each
|
||||
(spy-on 'find-file :and-return-value nil)
|
||||
(spy-on 'find-alternate-file :and-return-value nil))
|
||||
|
||||
(describe "doom/sudo-find-file")
|
||||
(describe "doom/sudo-this-file")))
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
(describe "core/keybinds"
|
||||
(require 'core-keybinds)
|
||||
|
||||
;; FIXME test against their side effects rather than their implementation
|
||||
(describe "map!"
|
||||
:var (doom--map-evil-p states-alist)
|
||||
(before-each
|
||||
|
|
|
@ -69,13 +69,15 @@
|
|||
(describe "file!"
|
||||
(it "returns the executing file"
|
||||
(expect (eval-and-compile (file!))
|
||||
:to-equal (expand-file-name "test/test-core-lib.el"
|
||||
doom-core-dir))))
|
||||
:to-equal
|
||||
(eval-and-compile load-file-name))))
|
||||
|
||||
(describe "dir!"
|
||||
(it "returns the executing directory"
|
||||
(expect (eval-and-compile (dir!))
|
||||
:to-equal (expand-file-name "test" doom-core-dir))))
|
||||
:to-equal
|
||||
(eval-and-compile
|
||||
(directory-file-name (file-name-directory load-file-name))))))
|
||||
|
||||
(describe "pushnew!"
|
||||
(it "pushes values onto a list symbol, in order"
|
||||
|
@ -234,13 +236,19 @@
|
|||
(it "loads a file relative to the current directory"
|
||||
(load! "path")
|
||||
(expect 'load :to-have-been-called)
|
||||
(expect 'load :to-have-been-called-with (expand-file-name "path" (eval-when-compile (dir!))) nil t))
|
||||
(expect 'load :to-have-been-called-with
|
||||
(expand-file-name "path" (eval-when-compile (dir!))) nil 'nomessage))
|
||||
|
||||
(it "loads a file relative to a specified directory"
|
||||
(load! "path" doom-etc-dir)
|
||||
(expect 'load :to-have-been-called-with (expand-file-name "path" doom-etc-dir) nil t)))
|
||||
(expect 'load :to-have-been-called-with
|
||||
(expand-file-name "path" doom-etc-dir) nil 'nomessage)))
|
||||
|
||||
(describe "quiet!"
|
||||
:var (doom-debug-mode)
|
||||
(before-each
|
||||
(setq doom-debug-mode nil))
|
||||
|
||||
(it "suppresses output from message"
|
||||
(expect (message "hello world") :to-output "hello world\n")
|
||||
(expect (message "hello world") :to-output)
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; core/test/test-core-modules.el
|
||||
;;;###if nil
|
||||
|
||||
;; (require 'core-modules)
|
||||
(xdescribe "core-modules"
|
||||
(require 'core-modules)
|
||||
|
||||
(xdescribe "core-modules")
|
||||
(describe "doom!")
|
||||
(describe "doom-modules")
|
||||
|
||||
(describe "doom-module-p")
|
||||
(describe "doom-module-get")
|
||||
(describe "doom-module-put")
|
||||
(describe "doom-module-set")
|
||||
(describe "doom-module-path")
|
||||
(describe "doom-module-locate-path")
|
||||
(describe "doom-module-from-path")
|
||||
(describe "doom-module-load-path")
|
||||
|
||||
(describe "require!")
|
||||
(describe "featurep!")
|
||||
(describe "after!")
|
||||
(describe "use-package!")
|
||||
(describe "use-package-hook!"))
|
||||
|
|
|
@ -21,14 +21,14 @@
|
|||
|
||||
(describe "project-root"
|
||||
(it "should resolve to the project's root"
|
||||
(expect (doom-project-root doom-core-dir) :to-equal doom-emacs-dir))
|
||||
(expect (doom-project-root doom-core-dir) :to-equal-file doom-emacs-dir))
|
||||
(it "should return nil if not in a project"
|
||||
(expect (doom-project-root (expand-file-name "~")) :to-be nil)))
|
||||
|
||||
(describe "project-expand"
|
||||
(it "expands to a path relative to the project root"
|
||||
(expect (doom-project-expand "init.el" doom-core-dir)
|
||||
:to-equal (expand-file-name "init.el" (doom-project-root doom-core-dir)))))
|
||||
(expect (doom-project-expand "init.el" doom-core-dir) :to-equal-file
|
||||
(expand-file-name "init.el" (doom-project-root doom-core-dir)))))
|
||||
|
||||
(describe "project-file-exists-p!"
|
||||
(let ((default-directory doom-core-dir))
|
||||
|
|
|
@ -48,21 +48,13 @@
|
|||
(spy-on 'doom-load-autoloads-file)
|
||||
(spy-on 'warn :and-return-value t))
|
||||
|
||||
(it "loads autoloads file"
|
||||
(let ((doom-interactive-mode t))
|
||||
(ignore-errors (doom-initialize)))
|
||||
(it "loads autoloads files"
|
||||
(ignore-errors (doom-initialize))
|
||||
(expect 'doom-load-autoloads-file
|
||||
:to-have-been-called-with doom-autoload-file)
|
||||
(expect 'doom-load-autoloads-file
|
||||
:to-have-been-called-with doom-package-autoload-file))
|
||||
|
||||
(it "does not load package autoloads file if noninteractive"
|
||||
(doom-initialize)
|
||||
(expect 'doom-load-autoloads-file
|
||||
:to-have-been-called-with doom-autoload-file)
|
||||
(expect 'doom-load-autoloads-file
|
||||
:not :to-have-been-called-with doom-package-autoload-file))
|
||||
|
||||
(it "throws doom-autoload-error in interactive session where autoload files don't exist"
|
||||
(let ((doom-interactive-mode t)
|
||||
(doom-autoload-file "doesnotexist")
|
||||
|
@ -81,20 +73,37 @@
|
|||
(expect 'require :to-have-been-called-with 'core-editor))))
|
||||
|
||||
(describe "doom-load-autoloads-file"
|
||||
:var (doom-autoload-file doom-alt-autoload-file result)
|
||||
(before-each
|
||||
(spy-on 'load :and-return-value t))
|
||||
(setq doom-autoload-file (make-temp-file "doom-autoload" nil ".el"))
|
||||
(with-temp-file doom-autoload-file)
|
||||
(byte-compile-file doom-autoload-file))
|
||||
(after-each
|
||||
(delete-file doom-autoload-file)
|
||||
(delete-file (byte-compile-dest-file doom-autoload-file)))
|
||||
|
||||
(it "loads the autoloads file"
|
||||
(it "loads the byte-compiled autoloads file if available"
|
||||
(doom-load-autoloads-file doom-autoload-file)
|
||||
(expect 'load :to-have-been-called-with (file-name-sans-extension doom-autoload-file)
|
||||
'noerror 'nomessage)))
|
||||
(expect (caar load-history) :to-equal-file
|
||||
(byte-compile-dest-file doom-autoload-file))
|
||||
|
||||
(delete-file (byte-compile-dest-file doom-autoload-file))
|
||||
(doom-load-autoloads-file doom-autoload-file)
|
||||
(expect (caar load-history) :to-equal-file doom-autoload-file))
|
||||
|
||||
(it "returns non-nil if successful"
|
||||
(expect (doom-load-autoloads-file doom-autoload-file)))
|
||||
|
||||
(it "returns nil on failure or error, non-fatally"
|
||||
(expect (doom-load-autoloads-file "/does/not/exist") :to-be nil)))
|
||||
|
||||
(describe "doom-load-envvars-file"
|
||||
:var (envvarfile process-environment)
|
||||
:var (doom-env-file process-environment)
|
||||
(before-each
|
||||
(setq process-environment (copy-sequence process-environment))
|
||||
(setq process-environment nil
|
||||
doom-env-file (make-temp-file "doom-env"))
|
||||
(with-temp-file doom-env-file
|
||||
(insert "\n\n\nA=1\nB=2\nC=3\n")))
|
||||
(insert "A=1\nB=2\nC=3\n")))
|
||||
(after-each
|
||||
(delete-file doom-env-file))
|
||||
|
||||
|
@ -106,12 +115,14 @@
|
|||
(expect (doom-load-envvars-file "/tmp/envvardoesnotexist" 'noerror)
|
||||
:not :to-throw))
|
||||
|
||||
(it "loads a well-formed envvar file"
|
||||
(expect (getenv "A") :not :to-be-truthy)
|
||||
(it "returns the new value for `process-environment'"
|
||||
(expect (doom-load-envvars-file doom-env-file)
|
||||
:to-equal '(("A" . "1") ("B" . "2") ("C" . "3")))
|
||||
(expect (getenv "A") :to-equal "1"))
|
||||
:to-equal '("A=1" "B=2" "C=3")))
|
||||
|
||||
(it "fails on an invalid envvar file"
|
||||
(with-temp-file doom-env-file (insert "A=1\nB=2\nC=3\n"))
|
||||
(expect (doom-load-envvars-file doom-env-file) :to-throw))))
|
||||
(it "alters environment variables"
|
||||
(dolist (key '("A" "B" "C"))
|
||||
(expect (getenv key) :not :to-be-truthy))
|
||||
(expect (doom-load-envvars-file doom-env-file))
|
||||
(expect (getenv "A") :to-equal "1")
|
||||
(expect (getenv "B") :to-equal "2")
|
||||
(expect (getenv "C") :to-equal "3"))))
|
||||
|
|
70
docs/api.org
70
docs/api.org
|
@ -252,6 +252,76 @@ It is integrated into Helpful, in Doom.
|
|||
:desc "Eval expression" ";" #'eval-expression)
|
||||
#+END_SRC
|
||||
|
||||
These are side-by-side comparisons, showing how to bind keys with and without
|
||||
~map!~:
|
||||
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
;; bind a global key
|
||||
(global-set-key (kbd "C-x y") #'do-something)
|
||||
(map! "C-x y" #'do-something)
|
||||
|
||||
;; bind a key on a keymap
|
||||
(define-key emacs-lisp-mode (kbd "C-c p") #'do-something)
|
||||
(map! :map emacs-lisp-mode "C-c p" #'do-something)
|
||||
|
||||
;; unbind a key defined elsewhere
|
||||
(define-key lua-mode-map (kbd "SPC m b") nil)
|
||||
(map! :map lua-mode-map "SPC m b" nil)
|
||||
|
||||
;; bind multiple keys
|
||||
(global-set-key "C-x x" #'do-something)
|
||||
(global-set-key "C-x y" #'do-something-else)
|
||||
(global-set-key "C-x z" #'do-another-thing)
|
||||
(map! "C-x x" #'do-something
|
||||
"C-x y" #'do-something-else
|
||||
"C-x z" #'do-another-thing)
|
||||
|
||||
;; bind global keys in normal mode
|
||||
(evil-define-key* 'normal 'global
|
||||
(kbd "C-x x") #'do-something
|
||||
(kbd "C-x y") #'do-something-else
|
||||
(kbd "C-x z") #'do-another-thing)
|
||||
(map! :n "C-x x" #'do-something
|
||||
:n "C-x y" #'do-something-else
|
||||
:n "C-x z" #'do-another-thing)
|
||||
|
||||
;; or on a deferred keymap
|
||||
(evil-define-key 'normal emacs-lisp-mode-map
|
||||
(kbd "C-x x") #'do-something
|
||||
(kbd "C-x y") #'do-something-else
|
||||
(kbd "C-x z") #'do-another-thing)
|
||||
(map! :map emacs-lisp-mode-map
|
||||
:n "C-x x" #'do-something
|
||||
:n "C-x y" #'do-something-else
|
||||
:n "C-x z" #'do-another-thing)
|
||||
|
||||
;; or multiple maps
|
||||
(dolist (map (list emacs-lisp-mode go-mode-map ivy-minibuffer-map))
|
||||
(evil-define-key '(normal insert) map
|
||||
"a" #'a
|
||||
"b" #'b
|
||||
"c" #'c))
|
||||
(map! :map (emacs-lisp-mode go-mode-map ivy-minibuffer-map)
|
||||
:ni "a" #'a
|
||||
:ni "b" #'b
|
||||
:ni "c" #'c)
|
||||
|
||||
;; or in multiple states (order of states doesn't matter)
|
||||
(evil-define-key* '(normal visual) emacs-lisp-mode-map (kbd "C-x x") #'do-something)
|
||||
(evil-define-key* 'insert emacs-lisp-mode-map (kbd "C-x x") #'do-something-else)
|
||||
(evil-define-key* '(visual normal insert emacs) emacs-lisp-mode-map (kbd "C-x z") #'do-another-thing)
|
||||
(map! :map emacs-lisp-mode
|
||||
:nv "C-x x" #'do-something ; normal+visual
|
||||
:i "C-x y" #'do-something-else ; insert
|
||||
:vnie "C-x z" #'do-another-thing) ; visual+normal+insert+emacs
|
||||
|
||||
;; You can nest map! calls:
|
||||
(evil-define-key* '(normal visual) emacs-lisp-mode-map (kbd "C-x x") #'do-something)
|
||||
(evil-define-key* 'normal go-lisp-mode-map (kbd "C-x x") #'do-something-else)
|
||||
(map! (:map emacs-lisp-mode :nv "C-x x" #'do-something)
|
||||
(:map go-lisp-mode :n "C-x x" #'do-something-else))
|
||||
#+END_SRC
|
||||
|
||||
*** package!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
;; To install a package that can be found on ELPA or any of the sources
|
||||
|
|
|
@ -59,8 +59,8 @@ things you should try first:
|
|||
|
||||
+ Make sure your configuration (or Doom Emacs) is *not* byte-compiled. Run ~doom
|
||||
clean~ to ensure it isn't. *Byte-compilation interferes with debugging!*
|
||||
+ Run ~bin/doom refresh -f~ to ensure all plugins are installed and autoload
|
||||
files generated.
|
||||
+ 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
|
||||
|
|
163
docs/faq.org
163
docs/faq.org
|
@ -1,7 +1,7 @@
|
|||
#+TITLE: Frequently Asked Questions
|
||||
#+STARTUP: nofold
|
||||
|
||||
* Table of Contents :TOC:
|
||||
* Table of Contents :TOC:
|
||||
- [[#general][General]]
|
||||
- [[#why-is-it-called-doom][Why is it called Doom?]]
|
||||
- [[#does-doom-work-on-windows][Does Doom work on Windows?]]
|
||||
|
@ -392,7 +392,7 @@ What's more, I don't like using more tools than I need. We should not need a
|
|||
second program just to make the first run comfortably.
|
||||
|
||||
** 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%20other%20Emacs%20configs%20(with%20Chemacs)][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]].
|
||||
|
||||
If you only want to try it out without affecting your current config, it is safe
|
||||
|
@ -439,45 +439,7 @@ summons to fight for custody of your kids.
|
|||
Also, Doom's fast yo.
|
||||
|
||||
** What is the meaning behind Doom's naming conventions?
|
||||
Doom has a number of naming conventions that it uses in addition to the standard
|
||||
lisp conventions. Third party packages may use their own conventions as well,
|
||||
but this guide focuses only on what Doom Emacs uses:
|
||||
|
||||
*** Lisp Naming Conventions
|
||||
The lisp conventions are simple. Symbols follow ~NAMESPACE-SYMBOLNAME~ for
|
||||
public variables/functions (e.g. ~bookmark-default-file~ or
|
||||
~electric-indent-mode~) and ~NAMESPACE--SYMBOLNAME~ for private ones (e.g.
|
||||
~byte-compile--lexical-environment~ and ~yas--tables~).
|
||||
|
||||
~NAMESPACE~ is usually the name of the containing file or package. E.g. the
|
||||
~company~ plugin prefixes all its variables/functions with ~company-~.
|
||||
|
||||
*** Doom Naming Conventions
|
||||
+ ~doom/NAME~ or ~+MODULE/NAME~ :: Denotes a public command designed to be used
|
||||
interactively, via =M-x= or a keybinding. e.g. ~doom/info~, ~+popup/other~,
|
||||
~+ivy/rg~.
|
||||
+ ~doom:NAME~ :: A public evil operator, motion or command. e.g. ~+evil:align~,
|
||||
~+ivy:rg~.
|
||||
+ ~doom-[-]NAME-h~ or ~+MODULE-[-]NAME-h~ :: A non-interactive function meant to
|
||||
be used (exclusively) as a hook. e.g. ~+cc-fontify-constants-h~,
|
||||
~+flycheck-buffer-h~.
|
||||
+ ~doom-[-]NAME-a~ or ~+MODULE-[-]NAME-a~ :: Functions designed to be used as
|
||||
advice for other functions. e.g. ~doom-set-jump-a~,
|
||||
~doom--fix-broken-smie-modes-a~, ~+org--babel-lazy-load-library-a~
|
||||
+ ~doom-[-]NAME-fn~ or ~+MODULE-[-]NAME-fn~ :: Indicates an [[https://en.wikipedia.org/wiki/Strategy_pattern][strategy]] function. A
|
||||
good rule of thumb for what makes a strategy function is: is it
|
||||
interchangeable? Can it be replaced with another function with a matching
|
||||
signature? e.g. ~+lookup-dumb-jump-backend-fn~, ~+magit-display-buffer-fn~,
|
||||
~+workspaces-set-project-action-fn~
|
||||
+ ~abc!~ :: A public Doom "autodef" function or macro. An autodef should always
|
||||
be defined, even if its containing module is disabled (i.e. they will not
|
||||
throw a void-function error). The purpose of this is to avoid peppering module
|
||||
configs with conditionals or `after!` blocks before using their APIs. They
|
||||
should noop if their module is disabled, and should be zero-cost in the case
|
||||
their module is disabled.
|
||||
|
||||
Autodefs usually serve to configure Doom or a module. e.g. ~after!~,
|
||||
~set-company-backends!~, ~set-evil-initial-state!~
|
||||
You'll find [[file:contributing.org::*Conventions][an overview of Doom's code conventions]] in the [[file:contributing.org][contributing guide]].
|
||||
|
||||
** How can I contribute to/support Doom?
|
||||
Take a look at the [[file:contributing.org][Contributing guide]].
|
||||
|
@ -503,7 +465,11 @@ Canonically, your private config is kept in =~/.doom.d/= or =~/.config/doom/=.
|
|||
Doom will prioritize =~/.config/doom=, if it exists. This directory is referred
|
||||
to as your ~$DOOMDIR~.
|
||||
|
||||
TL;DR. Put all your private configuration in =$DOOMDIR/config.el=.
|
||||
Your private config is typically comprised of an =init.el=, =config.el= and
|
||||
=packages.el= file. Put all your config in =config.el=, install packages by
|
||||
adding ~package!~ declarations to =packagse.el=, and enable/disable modules in
|
||||
you ~doom!~ block, which should have been created in your =init.el= when you
|
||||
first ran ~doom install~.
|
||||
|
||||
Check out the [[file:getting_started.org::Customize][Customize section]] in the [[file:getting_started.org][Getting Started]] guide for details.
|
||||
|
||||
|
@ -523,7 +489,7 @@ semicolons:
|
|||
Remember to run ~bin/doom refresh~ afterwards, on the command line, to sync your
|
||||
module list with Doom.
|
||||
|
||||
You can find a comprehensive list of modules in the [[file:../modules/README.org][Module Index]].
|
||||
You can find a comprehensive list of modules in the [[file:index.org::*Module list][Module Index]].
|
||||
|
||||
** How do I install a package from ELPA?
|
||||
Add a ~package!~ declaration to =~/.doom.d/packages.el= for each package you
|
||||
|
@ -539,8 +505,8 @@ You'll find more information in the "[[file:getting_started.org::*Installing%20p
|
|||
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:
|
||||
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"))
|
||||
|
@ -562,14 +528,15 @@ You'll find more information in the "[[file:getting_started.org::*Installing%20p
|
|||
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 config have precedence over modules
|
||||
(even your own). Simply add a new one for that package with the new recipe.
|
||||
~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?
|
||||
The ~package!~ macro has a ~:disable~ property:
|
||||
With the ~package!~ macro's ~:disable~ property:
|
||||
|
||||
#+BEGIN_SRC elisp
|
||||
;;; in DOOMDIR/packages.el
|
||||
|
@ -630,8 +597,8 @@ At the moment, the only difference between the two is that ~doom-theme~ is
|
|||
loaded when Emacs has finished initializing at startup and ~load-theme~ loads
|
||||
the theme immediately. Which you choose depends on your needs, but I recommend
|
||||
setting ~doom-theme~ because, if I later discover a better way to load themes, I
|
||||
can easily change how Doom uses ~doom-theme~, but I can't control how you use
|
||||
the ~load-theme~ function.
|
||||
can easily change how Doom uses ~doom-theme~, but I can't (easily) control how
|
||||
you use the ~load-theme~ function.
|
||||
|
||||
*** 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
|
||||
|
@ -670,60 +637,12 @@ e.g.
|
|||
#+END_SRC
|
||||
|
||||
** How do I bind my own keys (or change existing ones)?
|
||||
The ~map!~ macro is recommended; it is a convenience macro that acts as a
|
||||
wrapper around ~define-key~, ~global-set-key~, ~local-set-key~ and
|
||||
~evil-define-key~.
|
||||
The ~map!~ macro is recommended; it is a convenience macro that wraps around
|
||||
Emacs' (and evil's) keybinding API, i.e. ~define-key~, ~global-set-key~,
|
||||
~local-set-key~ and ~evil-define-key~.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
;; bind a global key
|
||||
(global-set-key (kbd "C-x y") #'do-something)
|
||||
(map! "C-x y" #'do-something)
|
||||
|
||||
;; bind a key on a keymap
|
||||
(define-key emacs-lisp-mode (kbd "C-c p") #'do-something)
|
||||
(map! :map emacs-lisp-mode "C-c p" #'do-something)
|
||||
|
||||
;; unbind a key defined elsewhere
|
||||
(define-key lua-mode-map (kbd "SPC m b") nil)
|
||||
(map! :map lua-mode-map "SPC m b" nil)
|
||||
|
||||
;; bind multiple keys
|
||||
(map! "C-x x" #'do-something
|
||||
"C-x y" #'do-something-else
|
||||
"C-x z" #'do-another-thing)
|
||||
#+END_SRC
|
||||
|
||||
Evil users can also define keys in particular evil states:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
;; bind global keys in normal mode
|
||||
(map! :n "C-x x" #'do-something
|
||||
:n "C-x y" #'do-something-else
|
||||
:n "C-x z" #'do-another-thing)
|
||||
|
||||
;; or on a keymap
|
||||
(map! :map emacs-lisp-mode
|
||||
:n "C-x x" #'do-something
|
||||
:n "C-x y" #'do-something-else
|
||||
:n "C-x z" #'do-another-thing)
|
||||
|
||||
;; or multiple maps
|
||||
(map! :map (emacs-lisp-mode go-mode-map ivy-minibuffer-map) ...)
|
||||
|
||||
;; or in multiple states (order of states doesn't matter)
|
||||
(map! :map emacs-lisp-mode
|
||||
:nv "C-x x" #'do-something ; normal+visual
|
||||
:i "C-x y" #'do-something-else ; insert
|
||||
:vnie "C-x z" #'do-another-thing) ; visual+normal+insert+emacs
|
||||
|
||||
;; You can nest map! calls:
|
||||
(map! (:map emacs-lisp-mode :nv "C-x x" #'do-something)
|
||||
(:map go-lisp-mode :n "C-x x" #'do-something-else))
|
||||
#+END_SRC
|
||||
|
||||
~map!~ supports other properties, like ~:after~, ~:when~, ~:prefix~ and ~:desc~.
|
||||
Look at ~map!~'s documentation for more information (=SPC h f map!= for evil
|
||||
users, =C-h f map!= otherwise).
|
||||
You'll find comprehensive examples of ~map!~'s usage in its documentation (via
|
||||
=SPC h f map!= or =C-h f map!= -- also found [[file:api.org][in docs/api]]).
|
||||
|
||||
You'll find a more comprehensive example of ~map!~'s usage in
|
||||
[[file:../modules/config/default/+evil-bindings.el][config/default/+evil-bindings.el]].
|
||||
|
@ -845,10 +764,10 @@ tools for experienced Emacs users to skirt around it (most of the time):
|
|||
Doom provides ~M-x doom/reload~ for your convenience, which will run ~doom
|
||||
refresh~, restart the Doom initialization process, and re-evaluate your
|
||||
personal config, but this won't clear pre-existing state. That may or may not
|
||||
be a problem, this hasn't be thoroughly tested, and Doom cannot anticipate
|
||||
be a problem, this hasn't be thoroughly tested and Doom cannot anticipate
|
||||
complications arising from your private config.
|
||||
|
||||
If you intend to use ~doom/reload~, try to design your config to be
|
||||
If you intend to use ~doom/reload~, you must design your config to be
|
||||
idempotent.
|
||||
- Many ~bin/doom~ commands are available as elisp commands with the ~doom//*~
|
||||
prefix. e.g. ~doom//refresh~, ~doom//update~, etc. Feel free to use them, but
|
||||
|
@ -868,36 +787,38 @@ deprecated. It forwards to ~bin/doom~ anyway.
|
|||
a shell script incapable of sentience and thus incapable of retaining, much less
|
||||
divulging, your secrets to others).
|
||||
|
||||
You can run ~bin/doom help~ to see what it's capable of, but here are the
|
||||
highlights:
|
||||
You can run ~bin/doom help~ to see what it's capable of, but here are some
|
||||
commands that you may find particularly useful:
|
||||
|
||||
+ ~doom doctor~ :: Diagnose common issues in your environment and list missing
|
||||
external dependencies for your enabled modules.
|
||||
+ ~doom install~ :: Install any missing packages.
|
||||
+ ~doom update~ :: Update all packages that Doom's (enabled) modules use.
|
||||
+ ~doom refresh~ :: Ensures that all missing packages are installed, orphaned
|
||||
packages are removed, and metadata properly generated.
|
||||
+ ~doom install~ :: Install any missing packages.
|
||||
+ ~doom update~ :: Update all packages that Doom's (enabled) modules use.
|
||||
+ ~doom env~ :: Regenerates your envvar file, which contains a snapshot of your
|
||||
shell environment for Doom Emacs to load on startup. You need to run this for
|
||||
changes to your shell environment to take effect.
|
||||
+ ~doom purge~ :: Purge orphaned packages (i.e. ones that aren't needed anymore)
|
||||
and regraft your repos.
|
||||
+ ~doom purge -g~ :: Purge orphaned packages (i.e. ones that aren't needed
|
||||
anymore) and regraft your repos.
|
||||
+ ~doom upgrade~ :: Upgrade Doom to the latest version (then update your
|
||||
packages). This is equivalent to:
|
||||
|
||||
#+BEGIN_SRC bash
|
||||
git pull
|
||||
doom refresh
|
||||
doom update
|
||||
#+END_SRC
|
||||
#+BEGIN_SRC bash
|
||||
git pull
|
||||
doom refresh
|
||||
doom update
|
||||
#+END_SRC
|
||||
|
||||
** When to run ~doom refresh~
|
||||
As a rule of thumb you should run ~doom refresh~ whenever you:
|
||||
|
||||
+ Update Doom (with ~git pull~),
|
||||
+ Update Doom with ~git pull~ instead of ~doom upgrade~,
|
||||
+ Change your ~doom!~ block in =$DOOMDIR/init.el=,
|
||||
+ Change the autoload files in any module (or =$DOOMDIR=),
|
||||
+ Change autoload files in any module (or =$DOOMDIR=),
|
||||
+ Or change the packages.el file in any module (or =$DOOMDIR=).
|
||||
+ Install an Emacs package or dependency outside of Emacs (i.e. through your OS
|
||||
package manager).
|
||||
|
||||
If anything is misbehaving, it's a good idea to run ~doom refresh~ first. ~doom
|
||||
refresh~ is responsible for regenerating your autoloads file (which tells Doom
|
||||
|
@ -1066,12 +987,12 @@ manually (e.g. by double-clicking each file in explorer).
|
|||
** ~void-variable~ and ~void-function~ errors on startup
|
||||
The most common culprit for these types of errors are:
|
||||
|
||||
1. An out-of-date autoloads file. To regenerate it, run ~doom refresh -f~.
|
||||
1. An out-of-date autoloads file. To regenerate it, run ~doom refresh~.
|
||||
|
||||
To avoid this issue, remember to run ~doom refresh~ whenever you modify your
|
||||
~doom!~ block in =~/.doom.d/init.el=, or add ~package!~ declarations to
|
||||
=~/.doom.d/packages.el=. If you modify =~/.emacs.d/.local= by hand, for
|
||||
whatever reason, run ~doom refresh -f~ to bypass caches and modify-checks.
|
||||
=~/.doom.d/packages.el=. Or if you modify =~/.emacs.d/.local= by hand, for
|
||||
whatever reason.
|
||||
|
||||
See ~doom help refresh~ for details on what this command does and when you
|
||||
should use it.
|
||||
|
|
|
@ -59,8 +59,8 @@
|
|||
- [[#variables-functions-faces-etc][Variables, functions, faces, etc.]]
|
||||
- [[#for-doom-modules-packages-autodefs-etc][For Doom Modules, packages, autodefs, etc.]]
|
||||
- [[#how-to-extract-a-backtrace-from-an-error][How to extract a backtrace from an error]]
|
||||
- [[#enabling-debug-on-error][Enabling `debug-on-error`]]
|
||||
- [[#a-backtrace-from-bindoom][A backtrace from `bin/doom`]]
|
||||
- [[#enabling-debug-on-error][Enabling ~debug-on-error~]]
|
||||
- [[#a-backtrace-from-bindoom][A backtrace from ~bin/doom~]]
|
||||
- [[#evaluating-elisp-on-the-fly][Evaluating Elisp on-the-fly]]
|
||||
- [[#how-to-determine-the-origin-of-a-bug][How to determine the origin of a bug]]
|
||||
- [[#testing-in-dooms-sandbox][Testing in Doom's sandbox]]
|
||||
|
@ -187,8 +187,8 @@ cause you issues later on. Do not use them:
|
|||
+ XEmacs
|
||||
|
||||
*** On Windows
|
||||
*Support for Windows is immature,* so your mileage will vary. [[https://www.reddit.com/r/emacs/comments/6bw35d/doom_an_emacsd_to_espouse_and_surpass_vim_in_any/dhtw32t/][Some have reported
|
||||
success]] with installing Doom via WSL, chocolatey on git-bash or cygwin.
|
||||
*Support for Windows is immature,* so your mileage will vary. Some have reported
|
||||
success with installing Doom via WSL, chocolatey on git-bash or cygwin.
|
||||
|
||||
#+BEGIN_QUOTE
|
||||
If you manage to get Doom on Windows and found this wasn't enough, or could be
|
||||
|
@ -1080,24 +1080,23 @@ You can also evaluate code with ~eval-expression~ (=M-;= or =SPC ;=).
|
|||
|
||||
** How to extract a backtrace from an error
|
||||
If you encounter an error while using Doom Emacs, you're probably about to head
|
||||
off and file a bug report (or request help on [[[https://discord.gg/bcZ6P3y][our Discord server]]. Before you do,
|
||||
please generate a backtrace to include with it.
|
||||
off and file a bug report (or request help on [[https://discord.gg/bcZ6P3y][our Discord server]]). Before you
|
||||
do, please generate a backtrace to include with it.
|
||||
|
||||
To do so you must enable ~debug-on-error~ then recreate the error.
|
||||
|
||||
*** Enabling `debug-on-error`
|
||||
There are three ways to enable `debug-on-error`:
|
||||
*** Enabling ~debug-on-error~
|
||||
There are three ways to enable ~debug-on-error~:
|
||||
|
||||
1. Start Emacs with `emacs --debug-init`. Use this for errors that occur at
|
||||
1. Start Emacs with ~emacs --debug-init~. Use this for errors that occur at
|
||||
startup.
|
||||
2. Evil users can press <kbd>SPC h d d</kbd> and non-evil users can press
|
||||
=C-h d d=.
|
||||
3. If the above don't work, there's always: `M-x toggle-debug-on-error`
|
||||
2. Evil users can press =SPC h d d= and non-evil users can press =C-h d d=.
|
||||
3. If the above don't work, there's always: ~M-x toggle-debug-on-error~
|
||||
|
||||
Now that `debug-on-error` is on, recreate the error. A window should pop up with
|
||||
Now that ~debug-on-error~ is on, recreate the error. A window should pop up with
|
||||
a backtrace.
|
||||
|
||||
*** A backtrace from `bin/doom`
|
||||
*** A backtrace from ~bin/doom~
|
||||
If the error you've encountered is emitted from ~bin/doom~, you can re-run the
|
||||
same command with the ~-d~ or ~--debug~ switches to force it to emit a backtrace
|
||||
when an error occurs. The ~DEBUG~ environment variable will work to.
|
||||
|
|
|
@ -7,9 +7,10 @@ for your own Emacs configuration or a resource for enthusiasts to learn more
|
|||
about our favorite OS.
|
||||
|
||||
#+begin_quote
|
||||
Doom's documentation can be viewed from within Emacs by pressing =<help> d h=
|
||||
(=<help>= is =SPC h= for evil users and =C-h= for vanilla users), or searched
|
||||
with =<help> d /=.
|
||||
Github fails to render org links to sub-sections, so it is recommended that you
|
||||
view the documentation from within Doom Emacs by pressing =<help> d h= (=<help>=
|
||||
is =SPC h= for evil users and =C-h= for vanilla users) or searching it with
|
||||
=<help> d /=.
|
||||
#+end_quote
|
||||
|
||||
* Table of Contents :TOC:
|
||||
|
|
3
init.el
3
init.el
|
@ -48,7 +48,8 @@
|
|||
|
||||
;; And let 'er rip!
|
||||
(doom-initialize)
|
||||
(unless noninteractive
|
||||
(if noninteractive
|
||||
(doom-initialize-packages)
|
||||
(doom-initialize-core)
|
||||
(doom-initialize-modules)
|
||||
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
|
||||
|
|
|
@ -143,6 +143,7 @@
|
|||
;;qt ; the 'cutest' gui framework ever
|
||||
;;racket ; a DSL for DSLs
|
||||
;;rest ; Emacs as a REST client
|
||||
;;rst ; ReST in peace
|
||||
;;ruby ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
|
||||
;;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
|
||||
;;scala ; java, but good
|
||||
|
@ -154,28 +155,17 @@
|
|||
;;web ; the tubes
|
||||
|
||||
:email
|
||||
;;(mu4e +gmail) ; WIP
|
||||
;;notmuch ; WIP
|
||||
;;(wanderlust +gmail) ; WIP
|
||||
;;(mu4e +gmail)
|
||||
;;notmuch
|
||||
;;(wanderlust +gmail)
|
||||
|
||||
;; Applications are complex and opinionated modules that transform Emacs
|
||||
;; toward a specific purpose. They may have additional dependencies and
|
||||
;; should be loaded late.
|
||||
:app
|
||||
;;calendar
|
||||
;;irc ; how neckbeards socialize
|
||||
;;(rss +org) ; emacs as an RSS reader
|
||||
;;twitter ; twitter client https://twitter.com/vnought
|
||||
;;(write ; emacs for writers (fiction, notes, papers, etc.)
|
||||
;; +wordnut ; wordnet (wn) search
|
||||
;; +langtool) ; a proofreader (grammar/style check) for Emacs
|
||||
;;write ; emacs for writers (fiction, notes, papers, etc.)
|
||||
|
||||
:config
|
||||
;; For literate config users. This will tangle+compile a config.org
|
||||
;; literate config in your `doom-private-dir' whenever it changes.
|
||||
;;literate
|
||||
|
||||
;; 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.
|
||||
(default +bindings +smartparens))
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
|
||||
(use-package! company-box
|
||||
:when (and EMACS26+ (featurep! +childframe))
|
||||
:when (featurep! +childframe)
|
||||
:hook (company-mode . company-box-mode)
|
||||
:config
|
||||
(setq company-box-show-single-candidate t
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
(package! company)
|
||||
(package! company-dict)
|
||||
(package! company-prescient)
|
||||
(when (and EMACS26+ (featurep! +childframe))
|
||||
(when (featurep! +childframe)
|
||||
(package! company-box))
|
||||
|
|
|
@ -1,46 +1,17 @@
|
|||
;;; completion/helm/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! :editor evil)
|
||||
|
||||
;;
|
||||
;; Project searching
|
||||
|
||||
;;;###autoload (autoload '+helm:grep "completion/helm/autoload/evil" nil t)
|
||||
(evil-define-command +helm:grep (all-files-p query)
|
||||
;;;###autoload (autoload '+helm:project-search "completion/helm/autoload/evil" nil t)
|
||||
(evil-define-command +helm:project-search (all-files-p query)
|
||||
"Ex interface for `+helm/grep'"
|
||||
(interactive "<!><a>")
|
||||
(+helm/grep all-files-p query))
|
||||
(+helm/project-search all-files-p query))
|
||||
|
||||
;;;###autoload (autoload '+helm:ag "completion/helm/autoload/evil" nil t)
|
||||
(evil-define-command +helm:ag (all-files-p query)
|
||||
"Ex interface for `+helm/ag'"
|
||||
(interactive "<!><a>")
|
||||
(+helm/ag all-files-p query))
|
||||
|
||||
;;;###autoload (autoload '+helm:rg "completion/helm/autoload/evil" nil t)
|
||||
(evil-define-command +helm:rg (all-files-p query)
|
||||
"Ex interface for `+helm/rg'"
|
||||
(interactive "<!><a>")
|
||||
(+helm/rg all-files-p query))
|
||||
|
||||
|
||||
;;;###autoload (autoload '+helm:grep-from-cwd "completion/helm/autoload/evil" nil t)
|
||||
(evil-define-command +helm:grep-from-cwd (query &optional recurse-p)
|
||||
;;;###autoload (autoload '+helm:project-search-from-cwd "completion/helm/autoload/evil" nil t)
|
||||
(evil-define-command +helm:project-search-from-cwd (query &optional recurse-p)
|
||||
"Ex interface for `+helm/grep-from-cwd'."
|
||||
(interactive "<a><!>")
|
||||
(+helm/grep-from-cwd (not recurse-p) query))
|
||||
|
||||
;;;###autoload (autoload '+helm:ag-from-cwd "completion/helm/autoload/evil" nil t)
|
||||
(evil-define-command +helm:ag-from-cwd (query &optional recurse-p)
|
||||
"Ex interface for `+helm/ag-from-cwd'."
|
||||
(interactive "<a><!>")
|
||||
(+helm/ag-from-cwd (not recurse-p) query))
|
||||
|
||||
;;;###autoload (autoload '+helm:rg-from-cwd "completion/helm/autoload/evil" nil t)
|
||||
(evil-define-command +helm:rg-from-cwd (query &optional recurse-p)
|
||||
"Ex interface for `+helm/rg-from-cwd'."
|
||||
(interactive "<a><!>")
|
||||
(+helm/rg-from-cwd (not recurse-p) query))
|
||||
|
||||
(+helm/project-search-from-cwd (not recurse-p) query))
|
||||
|
||||
;;;###autoload
|
||||
(defun +helm--set-prompt-display (pos)
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
;;; completion/helm/autoload/helm.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +helm/tasks (&optional _arg)
|
||||
(interactive "P")
|
||||
;; TODO Implement `+helm/tasks'
|
||||
(error "Not implemented yet"))
|
||||
|
||||
;;;###autoload
|
||||
(defun +helm/projectile-find-file ()
|
||||
"Call `helm-find-files' if called from HOME, otherwise
|
||||
|
@ -41,70 +35,11 @@ workspace."
|
|||
|
||||
|
||||
;;
|
||||
;; Project search
|
||||
|
||||
(defun +helm-ag-search-args (all-files-p recursive-p)
|
||||
(list (concat "ag " (if IS-WINDOWS "--vimgrep" "--nocolor --nogroup"))
|
||||
"-S"
|
||||
(if all-files-p "-z -a")
|
||||
(unless recursive-p "--depth 1")))
|
||||
|
||||
(defun +helm-rg-search-args (all-files-p recursive-p)
|
||||
(list "rg --no-heading --line-number --color never"
|
||||
"-S"
|
||||
(when all-files-p "-z -uu")
|
||||
(unless recursive-p "--maxdepth 1")))
|
||||
|
||||
;;
|
||||
(defun +helm--grep-source ()
|
||||
(require 'helm-projectile)
|
||||
(helm-build-async-source (capitalize (helm-grep-command t))
|
||||
:header-name (lambda (_name) "Helm Projectile Grep (C-c ? Help)")
|
||||
:candidates-process #'helm-grep-collect-candidates
|
||||
:filter-one-by-one #'helm-grep-filter-one-by-one
|
||||
:candidate-number-limit 9999
|
||||
:nohighlight t
|
||||
:keymap helm-grep-map
|
||||
:history 'helm-grep-history
|
||||
:action (apply #'helm-make-actions helm-projectile-grep-or-ack-actions)
|
||||
:persistent-action 'helm-grep-persistent-action
|
||||
:persistent-help "Jump to line (`C-u' Record in mark ring)"
|
||||
:requires-pattern 2))
|
||||
|
||||
(defun +helm--grep-search (directory query prompt &optional all-files-p recursive-p)
|
||||
(let* ((default-directory directory)
|
||||
(helm-ff-default-directory directory)
|
||||
(helm-grep-in-recurse recursive-p)
|
||||
(helm-grep-ignored-files
|
||||
(unless all-files-p
|
||||
(cl-union (projectile-ignored-files-rel) grep-find-ignored-files)))
|
||||
(helm-grep-ignored-directories
|
||||
(unless all-files-p
|
||||
(cl-union (mapcar 'directory-file-name (projectile-ignored-directories-rel))
|
||||
grep-find-ignored-directories)))
|
||||
(helm-grep-default-command
|
||||
(if (and nil (eq (projectile-project-vcs) 'git))
|
||||
(format "git --no-pager grep --no-color -n%%c -e %%p %s -- %%f"
|
||||
(if recursive-p "" "--max-depth 1 "))
|
||||
(format "grep -si -a%s %%e -n%%cH -e %%p %%f %s"
|
||||
(if recursive-p " -R" "")
|
||||
(if recursive-p "." "./*"))))
|
||||
(helm-grep-default-recurse-command helm-grep-default-command))
|
||||
(setq helm-source-grep (+helm--grep-source))
|
||||
(helm :sources 'helm-source-grep
|
||||
:input query
|
||||
:prompt prompt
|
||||
:buffer "*helm grep*"
|
||||
:default-directory directory
|
||||
:keymap helm-grep-map
|
||||
:history 'helm-grep-history
|
||||
:truncate-lines helm-grep-truncate-lines)))
|
||||
;;; Project search
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun +helm-file-search (engine &key query in all-files (recursive t))
|
||||
"Conduct a file search using ENGINE, which can be any of: rg, ag, pt, and
|
||||
grep. If omitted, ENGINE will default to the first one it detects, in that
|
||||
order.
|
||||
(cl-defun +helm-file-search (&key query in all-files (recursive t))
|
||||
"Conduct a file search using ripgrep.
|
||||
|
||||
:query STRING
|
||||
Determines the initial input to search for.
|
||||
|
@ -114,6 +49,8 @@ order.
|
|||
:recursive BOOL
|
||||
Whether or not to search files recursively from the base directory."
|
||||
(declare (indent defun))
|
||||
(unless (executable-find "rg")
|
||||
(user-error "Couldn't find ripgrep in your PATH"))
|
||||
(require 'helm-ag)
|
||||
(helm-ag--init-state)
|
||||
(let* ((project-root (or (doom-project-root) default-directory))
|
||||
|
@ -121,13 +58,6 @@ order.
|
|||
(default-directory directory)
|
||||
(helm-ag--default-directory directory)
|
||||
(helm-ag--default-target (list directory))
|
||||
(engine (or engine
|
||||
(cl-find-if #'executable-find +helm-project-search-engines
|
||||
:key #'symbol-name)
|
||||
(and (or (executable-find "grep")
|
||||
(executable-find "git"))
|
||||
'grep)
|
||||
(user-error "No search engine specified (is ag, rg, or git installed?)")))
|
||||
(query (or query
|
||||
(when (use-region-p)
|
||||
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
|
||||
|
@ -135,23 +65,20 @@ order.
|
|||
(when (> (abs (- end beg)) 1)
|
||||
(rxt-quote-pcre (buffer-substring-no-properties beg end)))))
|
||||
""))
|
||||
(prompt (format "[%s %s] "
|
||||
(symbol-name engine)
|
||||
(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
|
||||
(pcase engine
|
||||
(`ag (+helm-ag-search-args all-files recursive))
|
||||
(`rg (+helm-rg-search-args all-files recursive))
|
||||
('grep (+helm--grep-search directory query prompt all-files recursive)
|
||||
(cl-return t))))
|
||||
(helm-ag-base-command (string-join 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 "[%s %s] Searching %s"
|
||||
engine
|
||||
(helm-attrset 'name (format "[rg %s] Searching %s"
|
||||
(string-join (delq nil (cdr command)) " ")
|
||||
(abbreviate-file-name directory))
|
||||
helm-source-do-ag)
|
||||
|
@ -159,82 +86,39 @@ order.
|
|||
(cl-letf (((symbol-function 'helm-do-ag--helm)
|
||||
(lambda () (helm :sources '(helm-source-do-ag)
|
||||
:prompt prompt
|
||||
:buffer "*helm-ag*"
|
||||
:buffer "*helm-rg*"
|
||||
:keymap helm-do-ag-map
|
||||
:input query
|
||||
:history 'helm-ag--helm-history))))
|
||||
(helm-do-ag directory))))
|
||||
|
||||
(defun +helm--get-command (format)
|
||||
(cl-loop for tool in (cl-remove-duplicates +helm-project-search-engines :from-end t)
|
||||
if (executable-find (symbol-name tool))
|
||||
return (intern (format format tool))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +helm/project-search (&optional arg initial-query directory)
|
||||
"Performs a project search from the project root.
|
||||
"Performs a project search from the project root with ripgrep.
|
||||
|
||||
Uses the first available search backend from `+helm-project-search-engines'. If
|
||||
ARG (universal argument), include all files, even hidden or compressed ones, in
|
||||
the search."
|
||||
(interactive "P")
|
||||
(funcall (or (+helm--get-command "+helm/%s")
|
||||
#'+helm/grep)
|
||||
arg
|
||||
initial-query
|
||||
directory))
|
||||
(+helm-file-search
|
||||
:query initial-query
|
||||
:in directory
|
||||
:all-files (and (not (null arg))
|
||||
(listp arg))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +helm/project-search-from-cwd (&optional arg initial-query)
|
||||
"Performs a project search recursively from the current directory.
|
||||
|
||||
Uses the first available search backend from `+helm-project-search-engines'. If
|
||||
ARG (universal argument), include all files, even hidden or compressed ones."
|
||||
If ARG (universal argument), include all files, even hidden or compressed ones."
|
||||
(interactive "P")
|
||||
(funcall (or (+helm--get-command "+helm/%s-from-cwd")
|
||||
#'+helm/grep-from-cwd)
|
||||
arg
|
||||
initial-query))
|
||||
(+helm-file-search
|
||||
:query initial-query
|
||||
:in default-directory
|
||||
:all-files (and (not (null arg))
|
||||
(listp arg))))
|
||||
|
||||
|
||||
;;;###autoload (autoload '+helm/rg "completion/helm/autoload/helm" nil t)
|
||||
;;;###autoload (autoload '+helm/rg-from-cwd "completion/helm/autoload/helm" nil t)
|
||||
;;;###autoload (autoload '+helm/ag "completion/helm/autoload/helm" nil t)
|
||||
;;;###autoload (autoload '+helm/ag-from-cwd "completion/helm/autoload/helm" nil t)
|
||||
;;;###autoload (autoload '+helm/grep "completion/helm/autoload/helm" nil t)
|
||||
;;;###autoload (autoload '+helm/grep-from-cwd "completion/helm/autoload/helm" nil t)
|
||||
|
||||
(dolist (engine `(,@(cl-remove-duplicates +helm-project-search-engines :from-end t) grep))
|
||||
(defalias (intern (format "+helm/%s" engine))
|
||||
(lambda (arg &optional query directory)
|
||||
(interactive "P")
|
||||
(+helm-file-search engine
|
||||
:query query
|
||||
:in directory
|
||||
:all-files (and (not (null arg))
|
||||
(listp arg))))
|
||||
(format "Perform a project file search using %s.
|
||||
|
||||
QUERY is a regexp. If omitted, the current selection is used. If no selection is
|
||||
active, the last known search is used.
|
||||
|
||||
ARG is the universal argument. If a number is passed through it, e.g. C-u 3, then
|
||||
|
||||
If ALL-FILES-P, search compressed and hidden files as well."
|
||||
engine))
|
||||
|
||||
(defalias (intern (format "+helm/%s-from-cwd" engine))
|
||||
(lambda (arg &optional query)
|
||||
(interactive "P")
|
||||
(+helm-file-search engine
|
||||
:query query
|
||||
:in default-directory
|
||||
:all-files (and (not (null arg))
|
||||
(listp arg))))
|
||||
(format "Perform a project file search from the current directory using %s.
|
||||
|
||||
QUERY is a regexp. If omitted, the current selection is used. If no selection is
|
||||
active, the last known search is used.
|
||||
|
||||
If ALL-FILES-P, search compressed and hidden files as well."
|
||||
engine)))
|
||||
;;;###autoload
|
||||
(defun +helm/jump-list ()
|
||||
"TODO"
|
||||
(interactive)
|
||||
(error "not implemented yet"))
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
;;; completion/helm/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +helm-project-search-engines '(rg ag)
|
||||
"What search tools for `+helm/project-search' (and `+helm-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.
|
||||
|
||||
This falls back to git-grep (then grep) if none of these available.")
|
||||
|
||||
;; Posframe (requires +childframe)
|
||||
(defvar +helm-posframe-handler #'+helm-poshandler-frame-center-near-bottom-fn
|
||||
"The function that determines the location of the childframe. It should return
|
||||
|
@ -82,7 +72,7 @@ be negative.")
|
|||
(setq helm-default-prompt-display-function #'+helm--set-prompt-display))
|
||||
|
||||
:init
|
||||
(when (and EMACS26+ (featurep! +childframe))
|
||||
(when (featurep! +childframe)
|
||||
(setq helm-display-function #'+helm-posframe-display-fn))
|
||||
|
||||
(let ((fuzzy (featurep! +fuzzy)))
|
||||
|
@ -135,7 +125,6 @@ be negative.")
|
|||
:config (helm-flx-mode +1))
|
||||
|
||||
|
||||
;;;###package helm-ag
|
||||
(after! helm-ag
|
||||
(map! :map helm-ag-edit-map :n "RET" #'compile-goto-error)
|
||||
(define-key helm-ag-edit-map [remap quit-window] #'helm-ag--edit-abort)
|
||||
|
@ -150,14 +139,12 @@ be negative.")
|
|||
(setq helm-bookmark-show-location t)
|
||||
|
||||
|
||||
;;;###package helm-files
|
||||
(after! helm-files
|
||||
(setq helm-boring-file-regexp-list
|
||||
(append (list "\\.projects$" "\\.DS_Store$")
|
||||
helm-boring-file-regexp-list)))
|
||||
|
||||
|
||||
;;;###package helm-locate
|
||||
(defvar helm-generic-files-map (make-sparse-keymap))
|
||||
(after! helm-locate
|
||||
(when (and IS-MAC
|
||||
|
@ -167,7 +154,6 @@ be negative.")
|
|||
(set-keymap-parent helm-generic-files-map helm-map))
|
||||
|
||||
|
||||
;;;###package helm-org
|
||||
(use-package! helm-org
|
||||
:when (featurep! :lang org)
|
||||
:defer t
|
||||
|
@ -178,7 +164,6 @@ be negative.")
|
|||
'(org-set-tags . helm-org-completing-read-tags))))
|
||||
|
||||
|
||||
;;;###package helm-projectile
|
||||
(use-package! helm-projectile
|
||||
:commands (helm-projectile-find-file
|
||||
helm-projectile-recentf
|
||||
|
@ -191,7 +176,6 @@ be negative.")
|
|||
(set-keymap-parent helm-projectile-find-file-map helm-map))
|
||||
|
||||
|
||||
;;;###package swiper-helm
|
||||
(after! swiper-helm
|
||||
(setq swiper-helm-display-function
|
||||
(lambda (buf &optional _resume) (pop-to-buffer buf)))
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
(package! swiper-helm)
|
||||
(when (featurep! +fuzzy)
|
||||
(package! helm-flx))
|
||||
(when (and EMACS26+ (featurep! +childframe))
|
||||
(when (featurep! +childframe)
|
||||
(package! posframe))
|
||||
(when (featurep! :lang org)
|
||||
(package! helm-org))
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
- [[#jump-to-file-project-navigation][Jump-to-file project navigation]]
|
||||
- [[#project-search--replace][Project search & replace]]
|
||||
- [[#in-buffer-searching][In-buffer searching]]
|
||||
- [[#task-lookup][Task lookup]]
|
||||
- [[#ivy-integration-for-various-completing-commands][Ivy integration for various completing commands]]
|
||||
- [[#general][General]]
|
||||
- [[#jump-to-files-buffers-or-projects][Jump to files, buffers or projects)]]
|
||||
|
@ -29,8 +28,7 @@
|
|||
|
||||
* Description
|
||||
This module provides Ivy integration for a variety of Emacs commands, as well as
|
||||
a unified interface for project search and replace, powered by ag, rg,
|
||||
git-grep & grep (whichever is available).
|
||||
a unified interface for project search and replace, powered by ripgrep.
|
||||
|
||||
#+begin_quote
|
||||
I prefer ivy over ido for its flexibility. I prefer ivy over helm because it's
|
||||
|
@ -41,7 +39,6 @@ lighter, simpler and faster in many cases.
|
|||
+ =+fuzzy= Enables fuzzy completion for Ivy searches.
|
||||
+ =+prescient= Enables prescient filtering and sorting for Ivy searches.
|
||||
+ =+childframe= Causes Ivy to display in a floating child frame, above Emacs.
|
||||
*This requires GUI Emacs 26.1+*
|
||||
+ =+icons= Enables file icons for switch-{buffer,project}/find-file counsel
|
||||
commands.
|
||||
|
||||
|
@ -67,32 +64,24 @@ lighter, simpler and faster in many cases.
|
|||
command)
|
||||
|
||||
* Prerequisites
|
||||
This module optionally depends on one of:
|
||||
This module depends on:
|
||||
|
||||
+ [[https://github.com/BurntSushi/ripgrep][ripgrep]] (rg)
|
||||
+ [[https://github.com/ggreer/the_silver_searcher][the_silver_searcher]] (ag)
|
||||
|
||||
Ripgrep is recommended, but the order of its results aren't deterministic and it
|
||||
doesn't support full PCRE (at the time of writing). The_silver_searcher is a
|
||||
good alternative if either of these bother you.
|
||||
|
||||
If none of these are installed, file search commands will use git-grep (falling
|
||||
back to grep, otherwise).
|
||||
|
||||
** Install
|
||||
*** MacOS
|
||||
#+BEGIN_SRC sh
|
||||
brew install ripgrep the_silver_searcher
|
||||
brew install ripgrep
|
||||
#+END_SRC
|
||||
|
||||
*** Arch Linux
|
||||
#+BEGIN_SRC sh :dir /sudo::
|
||||
sudo pacman --needed --noconfirm -S ripgrep the_silver_searcher
|
||||
sudo pacman --needed --noconfirm -S ripgrep
|
||||
#+END_SRC
|
||||
|
||||
*** openSUSE
|
||||
#+BEGIN_SRC sh :dir /sudo::
|
||||
sudo zypper install ripgrep the_silver_searcher
|
||||
sudo zypper install ripgrep
|
||||
#+END_SRC
|
||||
|
||||
* Features
|
||||
|
@ -108,57 +97,38 @@ https://assets.doomemacs.org/completion/ivy/projectile.png
|
|||
|
||||
| Keybind | Description |
|
||||
|----------------------+-------------------------------------|
|
||||
| =SPC f /=, =SPC SPC= | Jump to file in project |
|
||||
| =SPC f .=, =SPC .= | Jump to file from current directory |
|
||||
| =SPC p f=, =SPC SPC= | Jump to file in project |
|
||||
| =SPC f f=, =SPC .= | Jump to file from current directory |
|
||||
|
||||
** Project search & replace
|
||||
This module provides interactive text search and replace using the first search
|
||||
program available on your system (rg, ag, git-grep or grep).
|
||||
This module provides interactive text search and replace using ripgrep.
|
||||
|
||||
| Keybind | Description |
|
||||
|-----------+---------------------------------|
|
||||
| =SPC / b= | Search the current buffer |
|
||||
| =SPC / p= | Search project |
|
||||
| =SPC / d= | Search this directory |
|
||||
| =SPC s b= | Search the current buffer |
|
||||
| =SPC s p= | Search project |
|
||||
| =SPC s d= | Search this directory |
|
||||
| =SPC p t= | List all TODO/FIXMEs in project |
|
||||
|
||||
https://assets.doomemacs.org/completion/ivy/search.png
|
||||
|
||||
The ~+ivy-project-search-engines~ variable is consulted to determine which
|
||||
underlying program to check for (and in what order). It's default value is ~'(rg
|
||||
ag pt)~. If none of these are available, it will resort to =git-grep= (falling
|
||||
back to =grep= after that).
|
||||
|
||||
To use a specific program, the following engine-specific commands are available
|
||||
(but not bound to any key by default) for searching from the project root or the
|
||||
current directory (recursively), respectively:
|
||||
|
||||
+ ~+ivy/ag~ / ~+ivy/ag-from-cwd~
|
||||
+ ~+ivy/rg~ / ~+ivy/rg-from-cwd~
|
||||
+ ~+ivy/grep~ / ~+ivy/grep-from-cwd~
|
||||
|
||||
The universal argument (=SPC u= for evil users; =C-u= otherwise) changes the
|
||||
behavior of these commands, instructing the underlying search engine to include
|
||||
ignored files.
|
||||
|
||||
This module also provides Ex Commands for evil users:
|
||||
|
||||
| Ex command | Description |
|
||||
|-----------------------+------------------------------------------------|
|
||||
| ~:ag[!] [QUERY]~ | Search project w/ ag[fn:1] |
|
||||
| ~:rg[!] [QUERY]~ | Search project w/ rg[fn:1] |
|
||||
| ~:grep[!] [QUERY]~ | Search project w/ git-grep/grep[fn:1] |
|
||||
| ~:agcwd[!] [QUERY]~ | Search this directory w/ the_silver_searcher |
|
||||
| ~:rgcwd[!] [QUERY]~ | Search this directory w/ ripgrep |
|
||||
| ~:grepcwd[!] [QUERY]~ | Search this directory w/ git-grep/grep |
|
||||
| Ex command | Description |
|
||||
|------------------------+------------------------------------------------------------------|
|
||||
| ~:pg[rep][!] [QUERY]~ | Search project (if ~!~, include hidden files) |
|
||||
| ~:pg[rep]d[!] [QUERY]~ | Search from current directory (if ~!~, don't search recursively) |
|
||||
|
||||
The optional BANG functions is equivalent to the universal argument for the
|
||||
previous commands.
|
||||
|
||||
-----
|
||||
|
||||
While in a search (e.g. invoked from ~+ivy:ag~ or ~:rg~), these extra
|
||||
keybindings are available to you:
|
||||
While in a search these extra keybindings are available to you:
|
||||
|
||||
| Keybind | Description |
|
||||
|-----------+-----------------------------------------------|
|
||||
|
@ -176,22 +146,14 @@ https://assets.doomemacs.org/completion/ivy/search-replace.png
|
|||
The =swiper= package provides an interactive buffer search powered by ivy. It
|
||||
can be invoked with:
|
||||
|
||||
+ =SPC / b=
|
||||
+ =SPC s s=
|
||||
+ =SPC s S= (uses thing at point as initial input)
|
||||
+ ~:sw[iper] [QUERY]~
|
||||
|
||||
https://assets.doomemacs.org/completion/ivy/swiper.png
|
||||
|
||||
A wgrep buffer can be opened from swiper with =C-c C-e=.
|
||||
|
||||
** Task lookup
|
||||
Some projects have TODO's and FIXME's littered across them. The ~+ivy/tasks~
|
||||
command allows you to search and jump to them. It can be invoked with:
|
||||
|
||||
+ =SPC p t= (C-u = restrict search to current file)
|
||||
+ ~:todo[!]~ (BANG = restrict search to current file)
|
||||
|
||||
https://assets.doomemacs.org/completion/ivy/todo.png
|
||||
|
||||
** Ivy integration for various completing commands
|
||||
*** General
|
||||
| Keybind | Description |
|
||||
|
@ -200,25 +162,27 @@ https://assets.doomemacs.org/completion/ivy/todo.png
|
|||
| =SPC '= | Resume last ivy session |
|
||||
|
||||
*** Jump to files, buffers or projects)
|
||||
| Keybind | Description |
|
||||
|---------------------------------+---------------------------------------|
|
||||
| =SPC RET= | Find bookmark |
|
||||
| =SPC f .=, =SPC .= | Browse from current directory |
|
||||
| =SPC f /=, =SPC p /=, =SPC SPC= | Find file in project |
|
||||
| =SPC f r= | Find recently opened file |
|
||||
| =SPC p p= | Open another project |
|
||||
| =SPC b b=, =SPC ,= | Switch to buffer in current workspace |
|
||||
| =SPC b B=, =SPC <= | Switch to buffer |
|
||||
| Keybind | Description |
|
||||
|----------------------+---------------------------------------|
|
||||
| =SPC RET= | Find bookmark |
|
||||
| =SPC f f=, =SPC .= | Browse from current directory |
|
||||
| =SPC p f=, =SPC SPC= | Find file in project |
|
||||
| =SPC f r= | Find recently opened file |
|
||||
| =SPC p p= | Open another project |
|
||||
| =SPC b b=, =SPC ,= | Switch to buffer in current workspace |
|
||||
| =SPC b B=, =SPC <= | Switch to buffer |
|
||||
|
||||
*** Search
|
||||
| Keybind | Description |
|
||||
|-----------+------------------------------------------|
|
||||
| =SPC / i= | Search for symbol in current buffer |
|
||||
| =SPC / I= | Search for symbol in all similar buffers |
|
||||
| =SPC / b= | Search the current buffer |
|
||||
| =SPC / p= | Search project |
|
||||
| =SPC / d= | Search this directory |
|
||||
| =SPC p t= | List all TODO/FIXMEs in project |
|
||||
| Keybind | Description |
|
||||
|-----------+-------------------------------------------|
|
||||
| =SPC p t= | List all TODO/FIXMEs in project |
|
||||
| =SPC s b= | Search the current buffer |
|
||||
| =SPC s d= | Search this directory |
|
||||
| =SPC s D= | Search another directory |
|
||||
| =SPC s i= | Search for symbol in current buffer |
|
||||
| =SPC s p= | Search project |
|
||||
| =SPC s P= | Search another project |
|
||||
| =SPC s s= | Search the current buffer (incrementally) |
|
||||
|
||||
* Configuration
|
||||
** TODO Enable fuzzy/non-fuzzy search for specific commands
|
||||
|
|
|
@ -1,55 +1,14 @@
|
|||
;; completion/ivy/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! :editor evil)
|
||||
|
||||
;;;###autoload (autoload '+ivy:swiper "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:swiper (&optional search)
|
||||
"Invoke `swiper' with SEARCH, otherwise with the symbol at point."
|
||||
(interactive "<a>")
|
||||
(swiper search))
|
||||
|
||||
;;;###autoload (autoload '+ivy:todo "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:todo (&optional bang)
|
||||
"An ex wrapper around `+ivy/tasks'."
|
||||
(interactive "<!>")
|
||||
(+ivy/tasks bang))
|
||||
|
||||
|
||||
;;
|
||||
;; Project searching
|
||||
|
||||
;;;###autoload (autoload '+ivy:grep "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:grep (all-files-p query)
|
||||
"Ex interface for `+ivy/grep'"
|
||||
(interactive "<!><a>")
|
||||
(+ivy/grep all-files-p query))
|
||||
|
||||
;;;###autoload (autoload '+ivy:ag "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:ag (all-files-p query)
|
||||
"Ex interface for `+ivy/ag'"
|
||||
(interactive "<!><a>")
|
||||
(+ivy/ag all-files-p query))
|
||||
|
||||
;;;###autoload (autoload '+ivy:rg "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:rg (all-files-p query)
|
||||
"Ex interface for `+ivy/rg'"
|
||||
(interactive "<!><a>")
|
||||
(+ivy/rg all-files-p query))
|
||||
|
||||
|
||||
;;;###autoload (autoload '+ivy:grep-from-cwd "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:grep-from-cwd (query &optional recurse-p)
|
||||
"Ex interface for `+ivy/grep-from-cwd'."
|
||||
;;;###autoload (autoload '+ivy:project-search "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:project-search (query &optional all-files-p)
|
||||
"Ex interface for `+ivy/project-search'."
|
||||
(interactive "<a><!>")
|
||||
(+ivy/grep-from-cwd (not recurse-p) query))
|
||||
(+ivy/project-search all-files-p query))
|
||||
|
||||
;;;###autoload (autoload '+ivy:ag-from-cwd "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:ag-from-cwd (query &optional recurse-p)
|
||||
"Ex interface for `+ivy/ag-from-cwd'."
|
||||
;;;###autoload (autoload '+ivy:project-search-from-cwd "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:project-search-from-cwd (query &optional recurse-p)
|
||||
"Ex interface for `+ivy/project-search-from-cwd'."
|
||||
(interactive "<a><!>")
|
||||
(+ivy/ag-from-cwd (not recurse-p) query))
|
||||
|
||||
;;;###autoload (autoload '+ivy:rg-from-cwd "completion/ivy/autoload/evil" nil t)
|
||||
(evil-define-command +ivy:rg-from-cwd (query &optional recurse-p)
|
||||
"Ex interface for `+ivy/rg-from-cwd'."
|
||||
(interactive "<a><!>")
|
||||
(+ivy/rg-from-cwd (not recurse-p) query))
|
||||
(+ivy/project-search-from-cwd (not recurse-p) query))
|
||||
|
|
|
@ -157,88 +157,6 @@ If ARG (universal argument), open selection in other-window."
|
|||
(interactive)
|
||||
(+ivy--switch-buffer nil t))
|
||||
|
||||
(defun +ivy--tasks-candidates (tasks)
|
||||
"Generate a list of task tags (specified by `+ivy-task-tags') for
|
||||
`+ivy/tasks'."
|
||||
(let* ((max-type-width
|
||||
(cl-loop for task in +ivy-task-tags maximize (length (car task))))
|
||||
(max-desc-width
|
||||
(cl-loop for task in tasks maximize (length (cl-cdadr task))))
|
||||
(max-width (max (+ max-desc-width 3)
|
||||
25)))
|
||||
(cl-loop
|
||||
with fmt = (format "%%-%ds %%-%ds%%s:%%s" max-type-width max-width)
|
||||
for alist in tasks
|
||||
collect
|
||||
(let-alist alist
|
||||
(list (format fmt
|
||||
(propertize .type 'face (cdr (assoc .type +ivy-task-tags)))
|
||||
(substring .desc 0 (min max-desc-width (length .desc)))
|
||||
(propertize (abbreviate-file-name .file) 'face 'font-lock-keyword-face)
|
||||
(propertize .line 'face 'font-lock-constant-face))
|
||||
.type .file .line)))))
|
||||
|
||||
(defun +ivy--tasks (target)
|
||||
(let* (case-fold-search
|
||||
(task-tags (mapcar #'car +ivy-task-tags))
|
||||
(cmd
|
||||
(format "%s -H -S --no-heading -- %s %s"
|
||||
(or (when-let (bin (executable-find "rg"))
|
||||
(concat bin " --line-number"))
|
||||
(when-let (bin (executable-find "ag"))
|
||||
(concat bin " --numbers"))
|
||||
(error "ripgrep & the_silver_searcher are unavailable"))
|
||||
(shell-quote-argument
|
||||
(concat "\\s("
|
||||
(string-join task-tags "|")
|
||||
")([\\s:]|\\([^)]+\\):?)"))
|
||||
target)))
|
||||
(save-match-data
|
||||
(cl-loop with out = (shell-command-to-string cmd)
|
||||
for x in (and out (split-string out "\n" t))
|
||||
when (condition-case-unless-debug ex
|
||||
(string-match
|
||||
(concat "^\\([^:]+\\):\\([0-9]+\\):.+\\("
|
||||
(string-join task-tags "\\|")
|
||||
"\\):?\\s-*\\(.+\\)")
|
||||
x)
|
||||
(error
|
||||
(print! (red "Error matching task in file: (%s) %s")
|
||||
(error-message-string ex)
|
||||
(car (split-string x ":")))
|
||||
nil))
|
||||
collect `((type . ,(match-string 3 x))
|
||||
(desc . ,(match-string 4 x))
|
||||
(file . ,(match-string 1 x))
|
||||
(line . ,(match-string 2 x)))))))
|
||||
|
||||
(defun +ivy--tasks-open-action (x)
|
||||
"Jump to the file and line of the current task."
|
||||
(cl-destructuring-bind (_label type file line) x
|
||||
(with-ivy-window
|
||||
(find-file (expand-file-name file (doom-project-root)))
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- (string-to-number line)))
|
||||
(when (search-forward type (line-end-position) t)
|
||||
(backward-char (length type)))
|
||||
(recenter))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy/tasks (&optional arg)
|
||||
"Search through all TODO/FIXME tags in the current project. If ARG, only
|
||||
search current file. See `+ivy-task-tags' to customize what this searches for."
|
||||
(interactive "P")
|
||||
(ivy-read (format "Tasks (%s): "
|
||||
(if arg
|
||||
(concat "in: " (file-relative-name buffer-file-name))
|
||||
"project"))
|
||||
(let ((tasks (+ivy--tasks (if arg buffer-file-name (doom-project-root)))))
|
||||
(unless tasks
|
||||
(user-error "No tasks in your project! Good job!"))
|
||||
(+ivy--tasks-candidates tasks))
|
||||
:action #'+ivy--tasks-open-action
|
||||
:caller '+ivy/tasks))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy/woccur ()
|
||||
"Invoke a wgrep buffer on the current ivy results, if supported."
|
||||
|
@ -293,7 +211,7 @@ search current file. See `+ivy-task-tags' to customize what this searches for."
|
|||
|
||||
|
||||
;;
|
||||
;; File searching
|
||||
;;; File searching
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy/projectile-find-file ()
|
||||
|
@ -318,25 +236,9 @@ The point of this is to avoid Emacs locking up indexing massive file trees."
|
|||
|
||||
(#'counsel-file-jump))))
|
||||
|
||||
(defvar +ivy-file-search-shell
|
||||
(or (executable-find "dash")
|
||||
(executable-find "sh")
|
||||
shell-file-name)
|
||||
"The SHELL to invoke ag/rg/pt/git-grep/grep searchs from.
|
||||
|
||||
This only affects `+ivy/*' search commands (e.g. `+ivy/rg' and
|
||||
`+ivy/project-search').
|
||||
|
||||
By default, this the most basic, uncustomized shell, to prevent interference
|
||||
caused by slow shell configs at the cost of isolating these programs from
|
||||
envvars that may have been set in the user's shell config to change their
|
||||
behavior. If this bothers you, change this to `shell-file-name'.")
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun +ivy-file-search (engine &key query in all-files (recursive t))
|
||||
"Conduct a file search using ENGINE, which can be any of: rg, ag, pt, and
|
||||
grep. If omitted, ENGINE will default to the first one it detects, in that
|
||||
order.
|
||||
(cl-defun +ivy-file-search (&key query in all-files (recursive t))
|
||||
"Conduct a file search using ripgrep.
|
||||
|
||||
:query STRING
|
||||
Determines the initial input to search for.
|
||||
|
@ -346,131 +248,56 @@ order.
|
|||
:recursive BOOL
|
||||
Whether or not to search files recursively from the base directory."
|
||||
(declare (indent defun))
|
||||
(let* ((project-root (or (doom-project-root) default-directory))
|
||||
(unless (executable-find "rg")
|
||||
(user-error "Couldn't find ripgrep in your PATH"))
|
||||
(require 'counsel)
|
||||
(let* ((ivy-more-chars-alist '((t . 1)))
|
||||
(project-root (or (doom-project-root) default-directory))
|
||||
(directory (or in project-root))
|
||||
(default-directory directory)
|
||||
(engine (or engine
|
||||
(cl-loop for tool in +ivy-project-search-engines
|
||||
if (executable-find (symbol-name tool))
|
||||
return tool)
|
||||
(and (or (executable-find "grep")
|
||||
(executable-find "git"))
|
||||
'grep)
|
||||
(error "No search engine specified (is ag, rg, pt or git installed?)")))
|
||||
(query
|
||||
(or (if query query)
|
||||
(when (use-region-p)
|
||||
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
|
||||
(end (or (bound-and-true-p evil-visual-end) (region-end))))
|
||||
(when (> (abs (- end beg)) 1)
|
||||
(let ((query (buffer-substring-no-properties beg end)))
|
||||
;; Escape characters that are special to ivy searches
|
||||
(replace-regexp-in-string "[! |]" (lambda (substr)
|
||||
(cond ((and (string= substr " ")
|
||||
(not (featurep! +fuzzy)))
|
||||
" ")
|
||||
((and (string= substr "|")
|
||||
(eq engine 'rg))
|
||||
"\\\\\\\\|")
|
||||
((concat "\\\\" substr))))
|
||||
(rxt-quote-pcre query))))))))
|
||||
(prompt
|
||||
(format "%s%%s %s"
|
||||
(symbol-name engine)
|
||||
(cond ((equal directory default-directory)
|
||||
"./")
|
||||
((equal directory project-root)
|
||||
(projectile-project-name))
|
||||
((file-relative-name directory project-root))))))
|
||||
(require 'counsel)
|
||||
(let ((ivy-more-chars-alist
|
||||
(if query '((t . 1)) ivy-more-chars-alist))
|
||||
(shell-file-name +ivy-file-search-shell))
|
||||
(pcase engine
|
||||
(`grep
|
||||
(let ((counsel-projectile-grep-initial-input query))
|
||||
(cl-letf (((symbol-function #'counsel-locate-git-root)
|
||||
(lambda () directory)))
|
||||
(if all-files
|
||||
(cl-letf (((symbol-function #'projectile-ignored-directories-rel)
|
||||
(symbol-function #'ignore))
|
||||
((symbol-function #'projectile-ignored-files-rel)
|
||||
(symbol-function #'ignore)))
|
||||
(counsel-projectile-grep))
|
||||
(counsel-projectile-grep)))))
|
||||
(`ag
|
||||
(let ((args (concat (if all-files " -a")
|
||||
(unless recursive " --depth 1"))))
|
||||
(counsel-ag query directory args (format prompt args))))
|
||||
(`rg
|
||||
(let ((args (concat (if all-files " -uu")
|
||||
(unless recursive " --maxdepth 1"))))
|
||||
(counsel-rg query directory args (format prompt args))))
|
||||
(_ (error "No search engine specified"))))))
|
||||
|
||||
(defun +ivy--get-command (format)
|
||||
(cl-loop for tool in (cl-remove-duplicates +ivy-project-search-engines :from-end t)
|
||||
if (executable-find (symbol-name tool))
|
||||
return (intern (format format tool))))
|
||||
(args (concat (if all-files " -uu")
|
||||
(unless recursive " --maxdepth 1"))))
|
||||
(counsel-rg
|
||||
(or (if query query)
|
||||
(when (use-region-p)
|
||||
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
|
||||
(end (or (bound-and-true-p evil-visual-end) (region-end))))
|
||||
(when (> (abs (- end beg)) 1)
|
||||
(let ((query (buffer-substring-no-properties beg end)))
|
||||
;; Escape characters that are special to ivy searches
|
||||
(replace-regexp-in-string "[! |]" (lambda (substr)
|
||||
(cond ((and (string= substr " ")
|
||||
(not (featurep! +fuzzy)))
|
||||
" ")
|
||||
((string= substr "|")
|
||||
"\\\\\\\\|")
|
||||
((concat "\\\\" substr))))
|
||||
(rxt-quote-pcre query)))))))
|
||||
directory args
|
||||
(format "rg%s %s"
|
||||
args
|
||||
(cond ((equal directory default-directory)
|
||||
"./")
|
||||
((equal directory project-root)
|
||||
(projectile-project-name))
|
||||
((file-relative-name directory project-root)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy/project-search (&optional arg initial-query directory)
|
||||
"Performs a project search from the project root.
|
||||
"Performs a live project search from the project root using ripgrep.
|
||||
|
||||
Uses the first available search backend from `+ivy-project-search-engines'. If
|
||||
ARG (universal argument), include all files, even hidden or compressed ones, in
|
||||
the search."
|
||||
If ARG (universal argument), include all files, even hidden or compressed ones,
|
||||
in the search."
|
||||
(interactive "P")
|
||||
(funcall (or (+ivy--get-command "+ivy/%s")
|
||||
#'+ivy/grep)
|
||||
arg
|
||||
initial-query
|
||||
directory))
|
||||
(+ivy-file-search :query initial-query :in directory :all-files arg))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy/project-search-from-cwd (&optional arg initial-query)
|
||||
"Performs a project search recursively from the current directory.
|
||||
|
||||
Uses the first available search backend from `+ivy-project-search-engines'. If
|
||||
ARG (universal argument), include all files, even hidden or compressed ones."
|
||||
If ARG (universal argument), include all files, even hidden or compressed ones."
|
||||
(interactive "P")
|
||||
(funcall (or (+ivy--get-command "+ivy/%s-from-cwd")
|
||||
#'+ivy/grep-from-cwd)
|
||||
arg
|
||||
initial-query))
|
||||
|
||||
|
||||
;;;###autoload (autoload '+ivy/rg "completion/ivy/autoload/ivy" nil t)
|
||||
;;;###autoload (autoload '+ivy/rg-from-cwd "completion/ivy/autoload/ivy" nil t)
|
||||
;;;###autoload (autoload '+ivy/ag "completion/ivy/autoload/ivy" nil t)
|
||||
;;;###autoload (autoload '+ivy/ag-from-cwd "completion/ivy/autoload/ivy" nil t)
|
||||
;;;###autoload (autoload '+ivy/grep "completion/ivy/autoload/ivy" nil t)
|
||||
;;;###autoload (autoload '+ivy/grep-from-cwd "completion/ivy/autoload/ivy" nil t)
|
||||
|
||||
(dolist (engine `(,@(cl-remove-duplicates +ivy-project-search-engines :from-end t) grep))
|
||||
(defalias (intern (format "+ivy/%s" engine))
|
||||
(lambda (all-files-p &optional query directory)
|
||||
(interactive "P")
|
||||
(+ivy-file-search engine :query query :in directory :all-files all-files-p))
|
||||
(format "Perform a project file search using %s.
|
||||
|
||||
QUERY is a regexp. If omitted, the current selection is used. If no selection is
|
||||
active, the last known search is used.
|
||||
|
||||
If ALL-FILES-P, search compressed and hidden files as well."
|
||||
engine))
|
||||
|
||||
(defalias (intern (format "+ivy/%s-from-cwd" engine))
|
||||
(lambda (all-files-p &optional query)
|
||||
(interactive "P")
|
||||
(+ivy-file-search engine :query query :in default-directory :all-files all-files-p))
|
||||
(format "Perform a project file search from the current directory using %s.
|
||||
|
||||
QUERY is a regexp. If omitted, the current selection is used. If no selection is
|
||||
active, the last known search is used.
|
||||
|
||||
If ALL-FILES-P, search compressed and hidden files as well."
|
||||
engine)))
|
||||
(+ivy/project-search arg initial-query default-directory))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -513,7 +340,7 @@ If ALL-FILES-P, search compressed and hidden files as well."
|
|||
(cons (format "%s:%d: %s"
|
||||
(buffer-name)
|
||||
(line-number-at-pos)
|
||||
(string-trim-right (thing-at-point 'line)))
|
||||
(string-trim-right (or (thing-at-point 'line) "")))
|
||||
(point-marker)))))))
|
||||
(cddr (better-jumper-jump-list-struct-ring
|
||||
(better-jumper-get-jumps (better-jumper--get-current-context))))))))
|
||||
|
|
|
@ -7,16 +7,6 @@ When nil, don't preview anything.
|
|||
When non-nil, preview non-virtual buffers.
|
||||
When 'everything, also preview virtual buffers")
|
||||
|
||||
(defvar +ivy-task-tags
|
||||
'(("TODO" . warning)
|
||||
("FIXME" . error)
|
||||
("HACK" . font-lock-constant-face)
|
||||
("REVIEW" . font-lock-keyword-face)
|
||||
("NOTE" . success)
|
||||
("DEPRECATED" . font-lock-doc-face))
|
||||
"An alist of tags for `+ivy/tasks' to include in its search, whose CDR is the
|
||||
face to render it with.")
|
||||
|
||||
(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.
|
||||
|
@ -69,6 +59,11 @@ results buffer.")
|
|||
[remap persp-switch-to-buffer] #'+ivy/switch-workspace-buffer
|
||||
[remap evil-show-jumps] #'+ivy/jump-list)
|
||||
:config
|
||||
;; Counsel changes a lot of ivy's state at startup; to control for that, we
|
||||
;; need to load it as early as possible. Some packages (like `ivy-prescient')
|
||||
;; require this.
|
||||
(require 'counsel nil t)
|
||||
|
||||
(setq ivy-height 17
|
||||
ivy-wrap t
|
||||
ivy-fixed-height-minibuffer t
|
||||
|
@ -182,7 +177,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
|
||||
|
||||
(use-package! counsel
|
||||
:commands counsel-describe-face
|
||||
:defer t
|
||||
:init
|
||||
(define-key!
|
||||
[remap apropos] #'counsel-apropos
|
||||
|
@ -324,7 +319,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
|
||||
|
||||
(use-package! ivy-posframe
|
||||
:when (and EMACS26+ (featurep! +childframe))
|
||||
:when (featurep! +childframe)
|
||||
:hook (ivy-mode . ivy-posframe-mode)
|
||||
:config
|
||||
(setq ivy-fixed-height-minibuffer nil
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
;;; completion/ivy/doctor.el
|
||||
|
||||
(when (and (not EMACS26+) (featurep! +childframe))
|
||||
(error! "The +childframe feature requires Emacs 26+"))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
(when (featurep! +fuzzy)
|
||||
(package! flx)))
|
||||
|
||||
(when (and EMACS26+ (featurep! +childframe))
|
||||
(when (featurep! +childframe)
|
||||
(package! ivy-posframe))
|
||||
|
||||
(when (featurep! +icons)
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
(:prefix ("p" . "project")
|
||||
:desc "Find file in other project" "F" #'doom/find-file-in-other-project
|
||||
:desc "Search project" "s" #'+default/search-project
|
||||
:desc "List project tasks" "t" #'+default/project-tasks
|
||||
:desc "List project tasks" "t" #'magit-todos-list
|
||||
:desc "Open project scratch buffer" "x" #'doom/open-project-scratch-buffer
|
||||
:desc "Switch to project scratch buffer" "X" #'doom/switch-to-project-scratch-buffer
|
||||
;; later expanded by projectile
|
||||
|
|
|
@ -294,24 +294,6 @@
|
|||
:desc "Find file in project" "SPC" #'projectile-find-file
|
||||
:desc "Jump to bookmark" "RET" #'bookmark-jump
|
||||
|
||||
;;; <leader> / --- search
|
||||
(:prefix-map ("/" . "search")
|
||||
:desc "Search buffer" "/" #'swiper
|
||||
:desc "Search buffer" "b" #'swiper
|
||||
:desc "Search current directory" "d" #'+default/search-cwd
|
||||
:desc "Search other directory" "D" #'+default/search-other-cwd
|
||||
:desc "Locate file" "f" #'locate
|
||||
:desc "Jump to symbol" "i" #'imenu
|
||||
:desc "Jump to link" "l" #'ace-link
|
||||
:desc "Jump list" "j" #'evil-show-jumps
|
||||
:desc "Jump to mark" "m" #'evil-show-marks
|
||||
:desc "Look up online" "o" #'+lookup/online
|
||||
:desc "Look up online (w/ prompt)" "O" #'+lookup/online-select
|
||||
:desc "Look up in local docsets" "k" #'+lookup/in-docsets
|
||||
:desc "Look up in all docsets" "K" #'+lookup/in-all-docsets
|
||||
:desc "Search project" "p" #'+default/search-project
|
||||
:desc "Search other project" "P" #'+default/search-other-project)
|
||||
|
||||
;;; <leader> TAB --- workspace
|
||||
(:when (featurep! :ui workspaces)
|
||||
(:prefix-map ("TAB" . "workspace")
|
||||
|
@ -381,25 +363,20 @@
|
|||
:desc "Send to repl" "s" #'+eval/send-region-to-repl
|
||||
:desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace
|
||||
:desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines
|
||||
:desc "List errors" "x" #'flymake-show-diagnostics-buffer
|
||||
(:when (featurep! :tools flycheck)
|
||||
:desc "List errors" "x" #'flycheck-list-errors)
|
||||
(:unless (featurep! :tools flycheck)
|
||||
:desc "List errors" "x" #'flymake-show-diagnostics-buffer))
|
||||
:desc "List errors" "x" #'flycheck-list-errors))
|
||||
|
||||
;;; <leader> f --- file
|
||||
(:prefix-map ("f" . "file")
|
||||
:desc "Find file" "." #'find-file
|
||||
:desc "Find file from here" "/"
|
||||
(if (featurep! :completion ivy)
|
||||
#'counsel-file-jump
|
||||
(λ! (doom-project-find-file default-directory)))
|
||||
:desc "Open project editorconfig" "c" #'editorconfig-find-current-editorconfig
|
||||
:desc "Copy this file" "C" #'doom/copy-this-file
|
||||
:desc "Find directory" "d" #'dired
|
||||
:desc "Delete this file" "D" #'doom/delete-this-file
|
||||
:desc "Find file in emacs.d" "e" #'+default/find-in-emacsd
|
||||
:desc "Browse emacs.d" "E" #'+default/browse-emacsd
|
||||
:desc "Find file from here" "f" #'find-file
|
||||
:desc "Find file" "f" #'find-file
|
||||
:desc "Find file from here" "F" #'+default/find-file-under-here
|
||||
:desc "Locate file" "l" #'locate
|
||||
:desc "Move/rename file" "m" #'doom/move-this-file
|
||||
:desc "Find file in private config" "p" #'doom/find-file-in-private-config
|
||||
|
@ -468,15 +445,16 @@
|
|||
|
||||
;;; <leader> i --- insert
|
||||
(:prefix-map ("i" . "insert")
|
||||
:desc "From clipboard" "y" #'+default/yank-pop
|
||||
:desc "Current file name" "f" #'+default/insert-file-path
|
||||
:desc "Current file path" "F" (λ!! #'+default/insert-file-path t)
|
||||
:desc "Evil ex path" "p" (λ! (evil-ex "R!echo "))
|
||||
:desc "From evil register" "r" #'evil-ex-registers
|
||||
:desc "Snippet" "s" #'yas-insert-snippet
|
||||
:desc "Unicode" "u" #'unicode-chars-list-chars)
|
||||
:desc "Unicode" "u" #'unicode-chars-list-chars
|
||||
:desc "From clipboard" "y" #'+default/yank-pop)
|
||||
|
||||
;;; <leader> n --- notes
|
||||
(:prefix-map ("n" . "notes")
|
||||
:desc "Browse notes" "." #'+default/browse-notes
|
||||
:desc "Search notes" "/" #'+default/org-notes-search
|
||||
:desc "Search notes for symbol" "*" #'+default/search-notes-for-symbol-at-point
|
||||
:desc "Org agenda" "a" #'org-agenda
|
||||
:desc "Org capture" "c" #'org-capture
|
||||
|
@ -487,6 +465,7 @@
|
|||
:desc "Find file in notes" "n" #'+default/find-in-notes
|
||||
:desc "Browse notes" "N" #'+default/browse-notes
|
||||
:desc "Todo list" "t" #'org-todo-list
|
||||
:desc "Search notes" "s" #'+default/org-notes-search
|
||||
:desc "View search" "v" #'org-search-view
|
||||
:desc "Org export to clipboard" "y" #'+org/export-to-clipboard
|
||||
:desc "Org export to clipboard as RTF" "Y" #'+org/export-to-clipboard-as-rich-text
|
||||
|
@ -542,8 +521,6 @@
|
|||
(:prefix-map ("p" . "project")
|
||||
:desc "Browse project" "." #'+default/browse-project
|
||||
:desc "Browse other project" ">" #'doom/browse-in-other-project
|
||||
:desc "Find file in project" "/" #'projectile-find-file
|
||||
:desc "Find file in other project" "?" #'doom/find-file-in-other-project
|
||||
:desc "Run cmd in project root" "!" #'projectile-run-shell-command-in-root
|
||||
:desc "Add new project" "a" #'projectile-add-known-project
|
||||
:desc "Switch to project buffer" "b" #'projectile-switch-to-buffer
|
||||
|
@ -552,7 +529,7 @@
|
|||
:desc "Remove known project" "d" #'projectile-remove-known-project
|
||||
:desc "Edit project .dir-locals" "e" #'projectile-edit-dir-locals
|
||||
:desc "Find file in project" "f" #'projectile-find-file
|
||||
:desc "Browse project" "F" #'+default/browse-project
|
||||
:desc "Find file in other project" "F" #'doom/find-file-in-other-project
|
||||
:desc "Configure project" "g" #'projectile-configure-project
|
||||
:desc "Invalidate project cache" "i" #'projectile-invalidate-cache
|
||||
:desc "Kill project buffers" "k" #'projectile-kill-buffers
|
||||
|
@ -563,7 +540,7 @@
|
|||
:desc "Save project files" "s" #'projectile-save-project-buffers
|
||||
:desc "Pop up scratch buffer" "x" #'doom/open-project-scratch-buffer
|
||||
:desc "Switch to scratch buffer" "X" #'doom/switch-to-project-scratch-buffer
|
||||
:desc "List project tasks" "t" #'+default/project-tasks
|
||||
:desc "List project tasks" "t" #'magit-todos-list
|
||||
:desc "Test project" "T" #'projectile-test-project)
|
||||
|
||||
;;; <leader> q --- quit/session
|
||||
|
@ -591,27 +568,31 @@
|
|||
:desc "Browse remote files" "." #'ssh-deploy-browse-remote-handler
|
||||
:desc "Detect remote changes" ">" #'ssh-deploy-remote-changes-handler))
|
||||
|
||||
;;; <leader> s --- snippets
|
||||
(:when (featurep! :editor snippets)
|
||||
(:prefix-map ("s" . "snippets")
|
||||
:desc "View snippet for mode" "/" #'+snippets/find-for-current-mode
|
||||
:desc "View snippet (global)" "?" #'+snippets/find
|
||||
:desc "Edit snippet" "c" #'+snippets/edit
|
||||
:desc "View private snippet" "f" #'+snippets/find-private
|
||||
:desc "Insert snippet" "i" #'yas-insert-snippet
|
||||
:desc "New snippet" "n" #'+snippets/new
|
||||
:desc "New snippet alias" "N" #'+snippets/new-alias
|
||||
:desc "Reload snippets" "r" #'yas-reload-all
|
||||
:desc "Create temporary snippet" "s" #'aya-create
|
||||
:desc "Expand temporary snippet" "e" #'aya-expand))
|
||||
;;; <leader> s --- search
|
||||
(:prefix-map ("s" . "search")
|
||||
:desc "Search buffer" "b" #'swiper
|
||||
:desc "Search current directory" "d" #'+default/search-cwd
|
||||
:desc "Search other directory" "D" #'+default/search-other-cwd
|
||||
:desc "Locate file" "f" #'locate
|
||||
:desc "Jump to symbol" "i" #'imenu
|
||||
:desc "Jump to link" "l" #'ace-link
|
||||
:desc "Jump list" "j" #'evil-show-jumps
|
||||
:desc "Jump to mark" "m" #'evil-show-marks
|
||||
:desc "Look up online" "o" #'+lookup/online
|
||||
:desc "Look up online (w/ prompt)" "O" #'+lookup/online-select
|
||||
:desc "Look up in local docsets" "k" #'+lookup/in-docsets
|
||||
:desc "Look up in all docsets" "K" #'+lookup/in-all-docsets
|
||||
:desc "Search project" "p" #'+default/search-project
|
||||
:desc "Search other project" "P" #'+default/search-other-project
|
||||
:desc "Search buffer" "s" #'swiper-isearch
|
||||
:desc "Search buffer for thing at point" "S" #'swiper-isearch-thing-at-point)
|
||||
|
||||
;;; <leader> t --- toggle
|
||||
(:prefix-map ("t" . "toggle")
|
||||
:desc "Big mode" "b" #'doom-big-font-mode
|
||||
:desc "Flymake" "f" #'flymake-mode
|
||||
(:when (featurep! :tools flycheck)
|
||||
:desc "Flycheck" "f" #'flycheck-mode)
|
||||
(:unless (featurep! :tools flycheck)
|
||||
:desc "Flymake" "f" #'flymake-mode)
|
||||
:desc "Frame fullscreen" "F" #'toggle-frame-fullscreen
|
||||
:desc "Evil goggles" "g" #'evil-goggles-mode
|
||||
(:when (featurep! :ui indent-guides)
|
||||
|
|
|
@ -73,15 +73,6 @@ If ARG (universal argument), runs `compile' from the current directory."
|
|||
(with-current-buffer buffer
|
||||
(funcall (default-value 'major-mode))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/project-tasks ()
|
||||
"Invokes `+ivy/tasks' or `+helm/tasks', depending on which is available."
|
||||
(interactive)
|
||||
(cond ((featurep! :tools magit)
|
||||
(call-interactively #'magit-todos-list))
|
||||
((featurep! :completion ivy) (+ivy/tasks))
|
||||
((featurep! :completion helm) (+helm/tasks))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/newline-above ()
|
||||
"Insert an indented new line before the current one."
|
||||
|
@ -120,7 +111,7 @@ languages)."
|
|||
(interactive)
|
||||
(if (and (sp-point-in-comment)
|
||||
comment-line-break-function)
|
||||
(funcall comment-line-break-function)
|
||||
(funcall comment-line-break-function nil)
|
||||
(delete-horizontal-space t)
|
||||
(newline nil t)
|
||||
(indent-according-to-mode)))
|
||||
|
@ -333,3 +324,22 @@ ARG is set, prompt for a known project to search from."
|
|||
(while (server-running-p)
|
||||
(sit-for 1))
|
||||
(server-start))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/find-file-under-here ()
|
||||
"Perform a recursive file search from the current directory."
|
||||
(interactive)
|
||||
(if (featurep! :completion ivy)
|
||||
(call-interactively #'counsel-file-jump)
|
||||
(λ! (doom-project-find-file default-directory))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +default/insert-file-path (arg)
|
||||
"Insert the file name (absolute path if prefix ARG).
|
||||
If `buffer-file-name' isn't set, uses `default-directory'."
|
||||
(interactive "P")
|
||||
(let ((path (or buffer-file-name default-directory)))
|
||||
(insert
|
||||
(if arg
|
||||
(abbreviate-file-name path)
|
||||
(file-name-nondirectory path)))))
|
||||
|
|
|
@ -18,7 +18,7 @@ byte-compiled from.")
|
|||
+literate-config-cache-file)
|
||||
force-p)
|
||||
(message "Compiling your literate config...")
|
||||
(let* ((org (file-truename +literate-config-file))
|
||||
(let* ((org (expand-file-name +literate-config-file))
|
||||
(dest (concat (file-name-sans-extension +literate-config-file) ".el"))
|
||||
(output (get-buffer-create "*org-tangle*")))
|
||||
(unwind-protect
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
;;; Custom commands
|
||||
;; Editing
|
||||
(evil-ex-define-cmd "@" #'+evil:macro-on-all-lines) ; TODO Test me
|
||||
(evil-ex-define-cmd "R[ead]" #'+evil:read)
|
||||
(evil-ex-define-cmd "al[ign]" #'+evil:align)
|
||||
(evil-ex-define-cmd "ral[ign]" #'+evil:align-right)
|
||||
(evil-ex-define-cmd "enhtml" #'+web:encode-html-entities)
|
||||
|
@ -56,25 +57,19 @@
|
|||
(evil-ex-define-cmd "cd" #'+evil:cd)
|
||||
(evil-ex-define-cmd "pwd" #'+evil:pwd)
|
||||
|
||||
(evil-define-command +evil:swiper (&optional search)
|
||||
"Invoke `swiper' with SEARCH, otherwise with the symbol at point."
|
||||
(interactive "<a>")
|
||||
(swiper-isearch search))
|
||||
(evil-ex-define-cmd "sw[iper]" #'+evil:swiper)
|
||||
|
||||
(cond ((featurep! :completion ivy)
|
||||
(evil-ex-define-cmd "ag" #'+ivy:ag)
|
||||
(evil-ex-define-cmd "agc[wd]" #'+ivy:ag-from-cwd)
|
||||
(evil-ex-define-cmd "rg" #'+ivy:rg)
|
||||
(evil-ex-define-cmd "rgc[wd]" #'+ivy:rg-from-cwd)
|
||||
(evil-ex-define-cmd "grep" #'+ivy:grep)
|
||||
(evil-ex-define-cmd "grepc[wd]" #'+ivy:grep-from-cwd)
|
||||
(evil-ex-define-cmd "sw[iper]" #'+ivy:swiper)
|
||||
(evil-ex-define-cmd "todo" #'+ivy:todo))
|
||||
(evil-ex-define-cmd "pg[rep]" #'+ivy:project-search)
|
||||
(evil-ex-define-cmd "pg[grep]d" #'+ivy:project-search-from-cwd))
|
||||
|
||||
((featurep! :completion helm)
|
||||
(evil-ex-define-cmd "ag" #'+helm:ag)
|
||||
(evil-ex-define-cmd "agc[wd]" #'+helm:ag-from-cwd)
|
||||
(evil-ex-define-cmd "rg" #'+helm:rg)
|
||||
(evil-ex-define-cmd "rgc[wd]" #'+helm:rg-from-cwd)
|
||||
(evil-ex-define-cmd "grep" #'+helm:grep)
|
||||
(evil-ex-define-cmd "grepc[wd]" #'+helm:grep-from-cwd)
|
||||
;; (evil-ex-define-cmd "todo" #'+helm:todo) TODO implement `+helm:todo'
|
||||
))
|
||||
(evil-ex-define-cmd "pg[rep]" #'+helm:project-search)
|
||||
(evil-ex-define-cmd "pg[grep]d" #'+helm:project-search-from-cwd)))
|
||||
|
||||
;;; Project tools
|
||||
(evil-ex-define-cmd "compile" #'+evil:compile)
|
||||
|
|
|
@ -220,7 +220,7 @@ and complains if a module is loaded too early (during startup)."
|
|||
(add-transient-hook! 'emacs-lisp-mode
|
||||
(+evil-collection-init 'elisp-mode))
|
||||
(add-transient-hook! 'occur-mode
|
||||
(+evil-collection-init (if EMACS26+ 'replace "replace")))
|
||||
(+evil-collection-init 'replace))
|
||||
|
||||
(evil-define-key* 'normal process-menu-mode-map
|
||||
"q" #'kill-current-buffer
|
||||
|
|
|
@ -80,9 +80,10 @@ more information on modifiers."
|
|||
(when (and (not (string= path "")) (equal (substring path -1) "/"))
|
||||
(setq path (substring path 0 -1))))
|
||||
(setq file-name
|
||||
(replace-regexp-in-string (format "\\(?:^\\|[^\\\\]\\)\\(%s\\)"
|
||||
(regexp-quote (string-trim-left (car match))))
|
||||
path file-name t t 1))))
|
||||
(replace-regexp-in-string
|
||||
(format "\\(?:^\\|[^\\\\]\\)\\(%s\\)"
|
||||
(regexp-quote (string-trim-left (car match))))
|
||||
path file-name t t 1))))
|
||||
(replace-regexp-in-string regexp "\\1" file-name t)))
|
||||
|
||||
(defun +evil--insert-newline (&optional above _noextranewline)
|
||||
|
@ -99,7 +100,7 @@ more information on modifiers."
|
|||
;; FIXME oh god why
|
||||
(save-excursion
|
||||
(if comment-line-break-function
|
||||
(funcall comment-line-break-function)
|
||||
(funcall comment-line-break-function nil)
|
||||
(comment-indent-new-line))
|
||||
(when (and (derived-mode-p 'c-mode 'c++-mode 'objc-mode 'java-mode 'js2-mode)
|
||||
(eq (char-after) ?/))
|
||||
|
|
|
@ -182,3 +182,9 @@ non-nil, a search is preformed against Doom's manual (wiht `doom/help-search')."
|
|||
(evil-ex-completed-binding (match-string 1 query))))
|
||||
((message "Searching for %S, this may take a while..." query)
|
||||
(apropos query t))))))
|
||||
|
||||
;;;###autoload (autoload '+evil:read "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:read (count file)
|
||||
"Alternative version of `evil-read' that replaces filename modifiers in FILE."
|
||||
(interactive "P<fsh>")
|
||||
(evil-read count (evil-ex-replace-special-filenames file)))
|
||||
|
|
|
@ -479,7 +479,20 @@ To change these keys see `+evil-repeat-keys'."
|
|||
(:when (featurep! :tools eval)
|
||||
:nv "gr" #'+eval:region
|
||||
:n "gR" #'+eval/buffer
|
||||
:v "gR" #'+eval:replace-region)
|
||||
:v "gR" #'+eval:replace-region
|
||||
;; Restore these keybinds, since the blacklisted/overwritten gr/gR will
|
||||
;; undo them:
|
||||
(:after dired
|
||||
:map dired-mode-map
|
||||
:n "gr" #'revert-buffer)
|
||||
(:after notmuch
|
||||
:map notmuch-common-keymap
|
||||
:n "gr" #'notmuch-refresh-this-buffer
|
||||
:n "gR" #'notmuch-poll-and-refresh-this-buffer)
|
||||
(:after elfeed
|
||||
:map elfeed-search-update--force
|
||||
:n "gr" #'elfeed-search-update--force
|
||||
:n "gR" #'elfeed-search-fetch))
|
||||
|
||||
:nv "z=" #'flyspell-correct-word-generic
|
||||
;; custom evil keybinds
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
(setq ibuffer-show-empty-filter-groups nil
|
||||
ibuffer-filter-group-name-face '(:inherit (success bold))
|
||||
ibuffer-formats
|
||||
`((mark modified read-only ,(if EMACS26+ 'locked "")
|
||||
`((mark modified read-only locked
|
||||
,@(if (featurep! +icons)
|
||||
`(;; Here you may adjust by replacing :right with :center
|
||||
;; or :left According to taste, if you want the icon
|
||||
|
|
|
@ -66,14 +66,3 @@ otherwise in default state."
|
|||
(when (and (bound-and-true-p evil-mode)
|
||||
(bobp) (eolp))
|
||||
(evil-insert-state)))))
|
||||
|
||||
|
||||
(after! smerge-mode
|
||||
(unless EMACS26+
|
||||
(with-no-warnings
|
||||
(defalias #'smerge-keep-upper #'smerge-keep-mine)
|
||||
(defalias #'smerge-keep-lower #'smerge-keep-other)
|
||||
(defalias #'smerge-diff-base-upper #'smerge-diff-base-mine)
|
||||
(defalias #'smerge-diff-upper-lower #'smerge-diff-mine-other)
|
||||
(defalias #'smerge-diff-base-lower #'smerge-diff-base-other))))
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
(interactive)
|
||||
(let* ((msg-path (car (plist-get (notmuch-tree-get-message-properties) :filename)))
|
||||
(temp (make-temp-file "notmuch-message-" nil ".eml")))
|
||||
(shell-command-to-string (format "cp '%s' '%s'" msg-path temp))
|
||||
(doom-call-process "cp" msg-path temp)
|
||||
(start-process-shell-command "email" nil (format "xdg-open '%s'" temp))))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -108,7 +108,7 @@
|
|||
(interactive)
|
||||
(let* ((msg-path (car (plist-get (notmuch-show-get-message-properties) :filename)))
|
||||
(temp (make-temp-file "notmuch-message-" nil ".eml")))
|
||||
(shell-command-to-string (format "cp '%s' '%s'" msg-path temp))
|
||||
(doom-call-process "cp" msg-path temp)
|
||||
(start-process-shell-command "email" nil (format "xdg-open '%s'" temp))))
|
||||
|
||||
|
||||
|
|
|
@ -160,6 +160,10 @@ This is ignored by ccls.")
|
|||
;;
|
||||
;; Major modes
|
||||
|
||||
(use-package! cmake-mode
|
||||
:defer t
|
||||
:config (set-docsets! 'cmake-mode "CMake"))
|
||||
|
||||
(use-package! company-cmake ; for `cmake-mode'
|
||||
:when (featurep! :completion company)
|
||||
:after cmake-mode
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
;; tries to load `proof-site'. We prevent this by defining these two variables
|
||||
;; early, in our own autoloads file.
|
||||
(setq pg-init--script-full-path (locate-library "proof-general")
|
||||
pg-init--pg-root (file-name-directory pg-init--script-full-path))
|
||||
pg-init--pg-root (file-name-directory pg-init--script-full-path)
|
||||
proof-splash-enable nil)
|
||||
|
||||
|
||||
;;;###package coq
|
||||
|
@ -73,14 +74,15 @@
|
|||
:references #'company-coq-grep-symbol
|
||||
:documentation #'company-coq-doc)
|
||||
|
||||
(if (not (featurep! :completion company))
|
||||
(setq company-coq-disabled-features '(company company-defaults))
|
||||
(setq company-coq-disabled-features '(hello company-defaults))
|
||||
|
||||
(if (featurep! :completion company)
|
||||
(map! :map coq-mode-map [remap company-complete-common]
|
||||
#'company-indent-or-complete-common)
|
||||
;; `company-coq''s company defaults impose idle-completion on folks, so
|
||||
;; we'll set up company ourselves.
|
||||
(add-to-list 'company-coq-disabled-features 'company-defaults)
|
||||
;; See https://github.com/cpitclaudel/company-coq/issues/42
|
||||
(map! :map coq-mode-map [remap company-complete-common]
|
||||
#'company-indent-or-complete-common))
|
||||
(add-to-list 'company-coq-disabled-features 'company))
|
||||
|
||||
(map! :map coq-mode-map
|
||||
:localleader
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
:commands omnisharp-install-server
|
||||
:preface
|
||||
(setq omnisharp-auto-complete-want-documentation nil
|
||||
omnisharp-cache-directory (concat doom-cache-dir "omnisharp"))
|
||||
omnisharp-cache-directory (concat doom-etc-dir "omnisharp"))
|
||||
:config
|
||||
(defun +csharp-cleanup-omnisharp-server-h ()
|
||||
"Clean up the omnisharp server once you kill the last csharp-mode buffer."
|
||||
|
|
|
@ -7,8 +7,5 @@
|
|||
(package! yaml-mode)
|
||||
(package! csv-mode)
|
||||
(package! dhall-mode)
|
||||
(package! protobuf-mode :recipe (:host github :repo "emacsmirror/protobuf-mode" :files (:defaults "*")))
|
||||
|
||||
;; DEPRECATED `conf-toml-mode' exists in Emacs 26+
|
||||
(unless (fboundp 'conf-toml-mode)
|
||||
(package! toml-mode))
|
||||
(package! protobuf-mode
|
||||
:recipe (:host github :repo "emacsmirror/protobuf-mode" :files (:defaults "*")))
|
||||
|
|
|
@ -36,7 +36,7 @@ This module adds [[https://golang.org][Go]] support.
|
|||
+ [[https://github.com/syohex/emacs-go-eldoc][go-eldoc]]
|
||||
+ [[https://github.com/dominikh/go-mode.el][go-guru]]
|
||||
+ [[https://github.com/manute/gorepl-mode][gorepl-mode]]
|
||||
+ [[https://github.com/syohex/emacs-go-add-tags][go-add-tags]]
|
||||
+ [[https://github.com/brantou/emacs-go-tag][go-tag]]
|
||||
+ [[https://github.com/mdempsky/gocode][company-go]]*
|
||||
+ [[https://github.com/s-kostyaev/go-gen-test][go-gen-test]]
|
||||
|
||||
|
@ -69,6 +69,7 @@ This module requires a valid ~GOPATH~, and the following Go packages:
|
|||
+ ~guru~ (for code navigation & refactoring commands)
|
||||
+ ~goimports~ (optional: for auto-formatting code on save & fixing imports)
|
||||
+ ~gotests~ (for generate test code)
|
||||
+ ~gomodifytags~ (for manipulating tags)
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
export GOPATH=~/work/go
|
||||
|
@ -80,6 +81,7 @@ go get -u golang.org/x/tools/cmd/goimports
|
|||
go get -u golang.org/x/tools/cmd/gorename
|
||||
go get -u golang.org/x/tools/cmd/guru
|
||||
go get -u github.com/cweill/gotests/...
|
||||
go get -u github.com/fatih/gomodifytags
|
||||
#+END_SRC
|
||||
|
||||
* TODO Features
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
|
||||
(map! :map go-mode-map
|
||||
:localleader
|
||||
"a" #'go-add-tags
|
||||
"a" #'go-tag-add
|
||||
"d" #'go-tag-remove
|
||||
"e" #'+go/play-buffer-or-region
|
||||
"i" #'go-goto-imports ; Go to imports
|
||||
(:prefix ("h" . "help")
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
(unless (executable-find "gotests")
|
||||
(warn! "Couldn't find gotests. Generating tests will not work"))
|
||||
|
||||
(unless (executable-find "gomodifytags")
|
||||
(warn! "Couldn't find gomodifytags. Manipulating struct tags will not work"))
|
||||
|
||||
(when (featurep! :completion company)
|
||||
(require 'company-go)
|
||||
(unless (executable-find company-go-gocode-command)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
(package! go-guru)
|
||||
(package! go-mode)
|
||||
(package! gorepl-mode)
|
||||
(package! go-add-tags)
|
||||
(package! go-tag)
|
||||
(package! go-gen-test)
|
||||
|
||||
(when (featurep! :completion company)
|
||||
|
|
|
@ -188,7 +188,7 @@ to tide."
|
|||
:map tide-mode-map
|
||||
"R" #'tide-restart-server
|
||||
"f" #'tide-format
|
||||
"rs" #'tide-rename-symbol
|
||||
"rrs" #'tide-rename-symbol
|
||||
"roi" #'tide-organize-imports))
|
||||
|
||||
|
||||
|
@ -205,7 +205,25 @@ to tide."
|
|||
:config
|
||||
(when (featurep! :editor evil +everywhere)
|
||||
(let ((js2-refactor-mode-map (evil-get-auxiliary-keymap js2-refactor-mode-map 'normal t t)))
|
||||
(js2r-add-keybindings-with-prefix (format "%s r" doom-localleader-key)))))
|
||||
(js2r-add-keybindings-with-prefix (format "%s r" doom-localleader-key))))
|
||||
(map! :map js2-mode-map
|
||||
:localleader
|
||||
(:prefix ("r" . "refactor")
|
||||
(:prefix ("a" . "add/arguments"))
|
||||
(:prefix ("b" . "barf"))
|
||||
(:prefix ("c" . "contract"))
|
||||
(:prefix ("d" . "debug"))
|
||||
(:prefix ("e" . "expand/extract"))
|
||||
(:prefix ("i" . "inject/inline/introduce"))
|
||||
(:prefix ("l" . "localize/log"))
|
||||
(:prefix ("o" . "organize"))
|
||||
(:prefix ("r" . "rename"))
|
||||
(:prefix ("s" . "slurp/split/string"))
|
||||
(:prefix ("t" . "toggle"))
|
||||
(:prefix ("u" . "unwrap"))
|
||||
(:prefix ("v" . "var"))
|
||||
(:prefix ("w" . "wrap"))
|
||||
(:prefix ("3" . "ternary")))))
|
||||
|
||||
|
||||
(use-package! eslintd-fix
|
||||
|
@ -234,6 +252,9 @@ to tide."
|
|||
(:after skewer-html
|
||||
:map skewer-html-mode-map
|
||||
"e" #'skewer-html-eval-tag))
|
||||
(map! :map js2-mode-map
|
||||
:localleader
|
||||
(:prefix ("s" . "skewer")))
|
||||
|
||||
|
||||
;;;###package npm-mode
|
||||
|
@ -242,7 +263,10 @@ to tide."
|
|||
:config
|
||||
(map! :localleader
|
||||
:map npm-mode-keymap
|
||||
"n" npm-mode-command-keymap))
|
||||
"n" npm-mode-command-keymap)
|
||||
(map! :map js2-mode-map
|
||||
:localleader
|
||||
(:prefix ("n" . "npm"))))
|
||||
|
||||
|
||||
;;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
;;; lang/ocaml/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +ocaml/comment-indent-new-line ()
|
||||
(defun +ocaml/comment-indent-new-line (&optional _)
|
||||
"Break line at point and indent, continuing comment if within one."
|
||||
(interactive)
|
||||
(comment-indent-new-line)
|
||||
|
|
|
@ -21,12 +21,12 @@ Make sure your src block has a :session param.")
|
|||
(defun +org--ob-ipython-generate-local-path-from-remote (session host params)
|
||||
"Given a remote SESSION with PARAMS and corresponding HOST, copy remote config to local, start a jupyter console to generate a new one."
|
||||
(let* ((runtime-dir
|
||||
(substring (shell-command-to-string (concat "ssh " host " jupyter --runtime-dir")) 0 -1))
|
||||
(cdr
|
||||
(doom-call-process "ssh " host "jupyter" "--runtime-dir")))
|
||||
(runtime-file (concat runtime-dir "/" "kernel-" session ".json"))
|
||||
(tramp-path (concat "/ssh:" host ":" runtime-file))
|
||||
(tramp-copy (concat (or +ob-ipython-local-runtime-dir
|
||||
(substring (shell-command-to-string "jupyter --runtime-dir")
|
||||
0 -1))
|
||||
(cdr (doom-call-process "jupyter" "--runtime-dir")))
|
||||
"/remote-" host "-kernel-" session ".json"))
|
||||
(local-path
|
||||
(concat
|
||||
|
|
|
@ -1,23 +1,5 @@
|
|||
;;; lang/org/autoload/org.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; HACK A necessary hack because org requires a compilation step after being
|
||||
;; cloned, and during that compilation a org-version.el is generated with these
|
||||
;; two functions, which return the output of a 'git describe ...' call in the
|
||||
;; repo's root. Of course, this command won't work in a sparse clone, and more
|
||||
;; than that, initiating these compilation step is a hassle, so...
|
||||
;;;###autoload (defun +org--release-a () "9.3")
|
||||
;;;###autoload (fset 'org-release #'+org--release-a)
|
||||
;;;###autoload (fset 'org-git-version #'ignore)
|
||||
|
||||
;; Org itself may override the above if it's loaded too early by packages that
|
||||
;; depend on it, so we have to advise it once again:
|
||||
;;;###autoload (advice-add #'org-release :override #'+org--release-a)
|
||||
;;;###autoload (advice-add #'org-git-version :override #'ignore)
|
||||
;;;###autoload (add-to-list 'load-path (dir!))
|
||||
|
||||
;;;###autoload (provide 'org-version)
|
||||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
|
@ -90,24 +72,19 @@
|
|||
org-insert-heading-respect-content)
|
||||
(goto-char (line-end-position))
|
||||
(org-end-of-subtree)
|
||||
(insert (concat "\n"
|
||||
(when (= level 1)
|
||||
(if at-eol
|
||||
(ignore (cl-incf level))
|
||||
"\n"))
|
||||
(make-string level ?*)
|
||||
" "))))
|
||||
(insert "\n" (make-string level ?*) " ")))
|
||||
(`above
|
||||
(org-back-to-heading)
|
||||
(insert (make-string level ?*) " ")
|
||||
(save-excursion
|
||||
(insert "\n")
|
||||
(if (= level 1) (insert "\n")))))
|
||||
(when-let (todo-keyword (org-element-property :todo-keyword context))
|
||||
(org-todo (or (car (+org-get-todo-keywords-for todo-keyword))
|
||||
'todo)))))
|
||||
(save-excursion (insert "\n"))))
|
||||
(when-let* ((todo-keyword (org-element-property :todo-keyword context))
|
||||
(todo-type (org-element-property :todo-type context)))
|
||||
(org-todo (cond ((eq todo-type 'done)
|
||||
(car (+org-get-todo-keywords-for todo-keyword)))
|
||||
(todo-keyword)
|
||||
('todo))))))
|
||||
|
||||
(t (user-error "Not a valid list, heading or table")))
|
||||
((user-error "Not a valid list, heading or table")))
|
||||
|
||||
(when (org-invisible-p)
|
||||
(org-show-hidden-entry))
|
||||
|
|
|
@ -207,19 +207,7 @@ background (and foreground) match the current theme."
|
|||
|
||||
;; Fix 'require(...).print is not a function' error from `ob-js' when
|
||||
;; executing JS src blocks
|
||||
(setq org-babel-js-function-wrapper "console.log(require('util').inspect(function(){\n%s\n}()));")
|
||||
|
||||
;; Fix #2010: ob-async needs to initialize Doom Emacs at least minimally for
|
||||
;; its async babel sessions to run correctly. This cannot be a named function
|
||||
;; because it is interpolated directly into a closure to be evaluated on the
|
||||
;; async session.
|
||||
(defadvice! +org-init-doom-during-async-executation-a (orig-fn &rest args)
|
||||
:around #'ob-async-org-babel-execute-src-block
|
||||
(let ((ob-async-pre-execute-src-block-hook
|
||||
;; Ensure our hook is always first
|
||||
(cons `(lambda () (load ,(concat doom-emacs-dir "init.el")))
|
||||
ob-async-pre-execute-src-block-hook)))
|
||||
(apply orig-fn args))))
|
||||
(setq org-babel-js-function-wrapper "console.log(require('util').inspect(function(){\n%s\n}()));"))
|
||||
|
||||
|
||||
(defun +org-init-babel-lazy-loader-h ()
|
||||
|
@ -633,6 +621,7 @@ between the two."
|
|||
(:when (featurep! :completion helm)
|
||||
"." #'helm-org-in-buffer-headings
|
||||
"/" #'helm-org-agenda-files-headings)
|
||||
"A" #'org-archive-subtree
|
||||
"d" #'org-deadline
|
||||
"e" #'org-export-dispatch
|
||||
"f" #'org-footnote-new
|
||||
|
@ -648,26 +637,29 @@ between the two."
|
|||
"s" #'org-schedule
|
||||
"t" #'org-todo
|
||||
"T" #'org-todo-list
|
||||
(:prefix ("r" . "refile")
|
||||
"." #'+org/refile-to-current-file
|
||||
"c" #'+org/refile-to-running-clock
|
||||
"l" #'+org/refile-to-last-location
|
||||
"o" #'+org/refile-to-other-window
|
||||
"O" #'+org/refile-to-other-buffers
|
||||
"r" #'org-refile) ; to all `org-refile-targets'
|
||||
(:prefix ("a" . "attachments")
|
||||
"a" #'+org-attach/file
|
||||
"u" #'+org-attach/uri
|
||||
"f" #'+org-attach/find-file
|
||||
"s" #'+org-attach/sync)
|
||||
(:prefix ("b" . "tables")
|
||||
"-" #'org-table-insert-hline
|
||||
"a" #'org-table-align
|
||||
"c" #'org-table-create-or-convert-from-region
|
||||
"e" #'org-table-edit-field
|
||||
"h" #'org-table-field-info
|
||||
(:when (featurep! +gnuplot)
|
||||
"p" #'org-plot/gnuplot))
|
||||
(:prefix ("c" . "clock")
|
||||
"c" #'org-clock-in
|
||||
"C" #'org-clock-out
|
||||
"d" #'org-clock-mark-default-task
|
||||
"e" #'org-clock-modify-effort-estimate
|
||||
"E" #'org-set-effort
|
||||
"l" #'org-clock-in-last
|
||||
"g" #'org-clock-goto
|
||||
"G" (λ! (org-clock-goto 'select))
|
||||
"r" #'org-clock-report
|
||||
"x" #'org-clock-cancel
|
||||
"=" #'org-clock-timestamps-up
|
||||
"-" #'org-clock-timestamps-down)
|
||||
|
@ -676,21 +668,18 @@ between the two."
|
|||
(:when (featurep! :completion ivy)
|
||||
"g" #'counsel-org-goto
|
||||
"G" #'counsel-org-goto-all)
|
||||
"a" #'org-agenda-goto
|
||||
"A" #'org-agenda-clock-goto
|
||||
"c" #'org-clock-goto
|
||||
"C" (λ! (org-clock-goto 'select))
|
||||
"i" #'org-id-goto
|
||||
"r" #'org-refile-goto-last-stored
|
||||
"x" #'org-capture-goto-last-stored)
|
||||
(:prefix ("b" . "tables")
|
||||
"-" #'org-table-insert-hline
|
||||
"a" #'org-table-align
|
||||
"c" #'org-table-create-or-convert-from-region
|
||||
"e" #'org-table-edit-field
|
||||
"h" #'org-table-field-info
|
||||
(:when (featurep! +gnuplot)
|
||||
"p" #'org-plot/gnuplot)))
|
||||
(:prefix ("r" . "refile")
|
||||
"." #'+org/refile-to-current-file
|
||||
"c" #'+org/refile-to-running-clock
|
||||
"l" #'+org/refile-to-last-location
|
||||
"o" #'+org/refile-to-other-window
|
||||
"O" #'+org/refile-to-other-buffers
|
||||
"r" #'org-refile)) ; to all `org-refile-targets'
|
||||
|
||||
(map! :after org-agenda
|
||||
:map org-agenda-mode-map
|
||||
|
@ -699,6 +688,13 @@ between the two."
|
|||
[remap org-agenda-Quit] #'org-agenda-exit
|
||||
:localleader
|
||||
"d" #'org-agenda-deadline
|
||||
(:prefix ("c" . "clock")
|
||||
"c" #'org-agenda-clock-in
|
||||
"C" #'org-agenda-clock-out
|
||||
"g" #'org-agenda-clock-goto
|
||||
"r" #'org-agenda-clockreport-mode
|
||||
"s" #'org-agenda-show-clocking-issues
|
||||
"x" #'org-agenda-clock-cancel)
|
||||
"q" #'org-agenda-set-tags
|
||||
"r" #'org-agenda-refile
|
||||
"s" #'org-agenda-schedule
|
||||
|
|
|
@ -6,7 +6,23 @@
|
|||
(when-let (orglib (locate-library "org" nil doom--initial-load-path))
|
||||
(setq load-path (delete (substring (file-name-directory orglib) 0 -1)
|
||||
load-path)))
|
||||
(package! org-plus-contrib) ; install cutting-edge version of org-mode
|
||||
|
||||
;; HACK A necessary hack because org requires a compilation step after being
|
||||
;; cloned, and during that compilation a org-version.el is generated with
|
||||
;; these two functions, which return the output of a 'git describe ...'
|
||||
;; call in the repo's root. Of course, this command won't work in a sparse
|
||||
;; clone, and more than that, initiating these compilation step is a
|
||||
;; hassle, so...
|
||||
(setq straight-fix-org nil)
|
||||
(add-hook! 'straight-use-package-pre-build-functions
|
||||
(defun +org-fix-package-h (package &rest _)
|
||||
(when (member package '("org" "org-plus-contrib"))
|
||||
(with-temp-file (expand-file-name "org-version.el" (straight--repos-dir "org"))
|
||||
(insert "(fset 'org-release (lambda () \"9.3\"))\n"
|
||||
"(fset 'org-git-version #'ignore)\n"
|
||||
"(provide 'org-version)\n")))))
|
||||
|
||||
(package! org-plus-contrib) ; install cutting-edge version of org-mode
|
||||
|
||||
(package! htmlize)
|
||||
(package! org-bullets :recipe (:host github :repo "Kaligule/org-bullets"))
|
||||
|
@ -14,12 +30,29 @@
|
|||
(package! org-yt :recipe (:host github :repo "TobiasZawada/org-yt"))
|
||||
(package! ox-clip)
|
||||
(package! toc-org)
|
||||
|
||||
(when (featurep! :editor evil +everywhere)
|
||||
(package! evil-org :recipe (:host github :repo "hlissner/evil-org-mode")))
|
||||
(when (featurep! :tools pdf)
|
||||
(package! org-pdfview))
|
||||
(when (featurep! :tools magit)
|
||||
(package! orgit))
|
||||
(when (featurep! +dragndrop)
|
||||
(package! org-download))
|
||||
(when (featurep! +gnuplot)
|
||||
(package! gnuplot)
|
||||
(package! gnuplot-mode))
|
||||
(when (featurep! +ipython)
|
||||
(package! ob-ipython))
|
||||
(when (featurep! +pomodoro)
|
||||
(package! org-pomodoro))
|
||||
(when (featurep! +present)
|
||||
(package! centered-window
|
||||
:recipe (:host github :repo "anler/centered-window-mode"))
|
||||
(package! org-tree-slide)
|
||||
(package! org-re-reveal))
|
||||
(when (featurep! +journal)
|
||||
(package! org-journal))
|
||||
|
||||
;;; Babel
|
||||
(package! ob-async)
|
||||
|
@ -36,25 +69,11 @@
|
|||
(when (featurep! :lang rust)
|
||||
(package! ob-rust))
|
||||
|
||||
;;; Modules
|
||||
(when (featurep! +dragndrop)
|
||||
(package! org-download))
|
||||
(when (featurep! +gnuplot)
|
||||
(package! gnuplot)
|
||||
(package! gnuplot-mode))
|
||||
(when (featurep! +ipython)
|
||||
(package! ob-ipython))
|
||||
;;; Export
|
||||
(when (featurep! +pandoc)
|
||||
(package! ox-pandoc))
|
||||
(when (featurep! +pomodoro)
|
||||
(package! org-pomodoro))
|
||||
(when (featurep! +present)
|
||||
(package! centered-window
|
||||
:recipe (:host github :repo "anler/centered-window-mode"))
|
||||
(package! org-tree-slide)
|
||||
(package! org-re-reveal))
|
||||
(when (featurep! +journal)
|
||||
(package! org-journal))
|
||||
(when (featurep! +hugo)
|
||||
(package! ox-hugo
|
||||
:recipe (:host github :repo "kaushalmodi/ox-hugo" :nonrecursive t)))
|
||||
(when (featurep! :lang rst)
|
||||
(package! ox-rst))
|
||||
|
|
|
@ -18,31 +18,19 @@
|
|||
(kill-buffer (get-buffer "org")))
|
||||
|
||||
(describe "headlines"
|
||||
(it "appends first-level headlines with an extra newline"
|
||||
(it "opens new headline below"
|
||||
(insert!! "* {0}Header")
|
||||
(+org/insert-item-below 1)
|
||||
(expect (eobp))
|
||||
(expect (buffer-substring-no-properties (point-min) (point-max))
|
||||
:to-equal "* Header\n\n* "))
|
||||
(it "prepends first-level headlines with an extra newline"
|
||||
(insert!! "* {0}Header")
|
||||
(+org/insert-item-above 1)
|
||||
(expect (eolp))
|
||||
(expect (buffer-substring-no-properties (point-min) (point-max))
|
||||
:to-equal "* \n\n* Header"))
|
||||
:to-equal "* Header\n* "))
|
||||
|
||||
(it "appends second-level headlines with an no extra newline"
|
||||
(insert!! "** {0}Header")
|
||||
(+org/insert-item-below 1)
|
||||
(expect (eobp))
|
||||
(expect (buffer-substring-no-properties (point-min) (point-max))
|
||||
:to-equal "** Header\n** "))
|
||||
(it "prepends second-level headlines with an no extra newline"
|
||||
(insert!! "** {0}Header")
|
||||
(it "opens new headline above"
|
||||
(insert!! "* {0}Header")
|
||||
(+org/insert-item-above 1)
|
||||
(expect (eolp))
|
||||
(expect (buffer-substring-no-properties (point-min) (point-max))
|
||||
:to-equal "** \n** Header"))
|
||||
:to-equal "* \n* Header"))
|
||||
|
||||
(it "appends headlines, skipping subtrees"
|
||||
(insert!! "** {0}First\n"
|
||||
|
|
|
@ -20,6 +20,9 @@ called.")
|
|||
:init
|
||||
(setq python-environment-directory doom-cache-dir
|
||||
python-indent-guess-indent-offset-verbose nil)
|
||||
|
||||
(when (featurep! +lsp)
|
||||
(add-hook 'python-mode-local-vars-hook #'lsp!))
|
||||
:config
|
||||
(set-repl-handler! 'python-mode #'+python/open-repl :persist t)
|
||||
(set-docsets! 'python-mode "Python 3" "NumPy" "SciPy")
|
||||
|
@ -45,9 +48,6 @@ called.")
|
|||
;; Stop the spam!
|
||||
(setq python-indent-guess-indent-offset-verbose nil)
|
||||
|
||||
(when (featurep! +lsp)
|
||||
(add-hook 'python-mode-local-vars-hook #'lsp!))
|
||||
|
||||
;; Default to Python 3. Prefer the versioned Python binaries since some
|
||||
;; systems stupidly make the unversioned one point at Python 2.
|
||||
(when (and (executable-find "python3")
|
||||
|
@ -88,10 +88,17 @@ called.")
|
|||
|
||||
|
||||
(use-package! anaconda-mode
|
||||
:after python
|
||||
:defer t
|
||||
:init
|
||||
(setq anaconda-mode-installation-directory (concat doom-etc-dir "anaconda/")
|
||||
anaconda-mode-eldoc-as-single-line t)
|
||||
|
||||
(add-hook! 'python-mode-local-vars-hook
|
||||
(defun +python-init-anaconda-mode-maybe-h ()
|
||||
"Enable `anaconda-mode' if `lsp-mode' isn't."
|
||||
(unless (or (bound-and-true-p lsp-mode)
|
||||
(bound-and-true-p lsp--buffer-deferred))
|
||||
(anaconda-mode +1))))
|
||||
:config
|
||||
(add-hook 'anaconda-mode-hook #'anaconda-eldoc-mode)
|
||||
(set-company-backend! 'anaconda-mode '(company-anaconda))
|
||||
|
@ -101,13 +108,6 @@ called.")
|
|||
:documentation #'anaconda-mode-show-doc)
|
||||
(set-popup-rule! "^\\*anaconda-mode" :select nil)
|
||||
|
||||
(add-hook! 'python-mode-local-vars-hook :append
|
||||
(defun +python-init-anaconda-mode-maybe-h ()
|
||||
"Enable `anaconda-mode' if `lsp-mode' isn't."
|
||||
(unless (or (bound-and-true-p lsp-mode)
|
||||
(bound-and-true-p lsp--buffer-deferred))
|
||||
(anaconda-mode +1))))
|
||||
|
||||
(defun +python-auto-kill-anaconda-processes-h ()
|
||||
"Kill anaconda processes if this buffer is the last python buffer."
|
||||
(when (and (eq major-mode 'python-mode)
|
||||
|
@ -115,7 +115,8 @@ called.")
|
|||
(doom-buffers-in-mode 'python-mode (buffer-list)))))
|
||||
(anaconda-mode-stop)))
|
||||
(add-hook! 'python-mode-hook
|
||||
(add-hook 'kill-buffer-hook #'+python-auto-kill-anaconda-processes-h nil t))
|
||||
(add-hook 'kill-buffer-hook #'+python-auto-kill-anaconda-processes-h
|
||||
nil 'local))
|
||||
|
||||
(when (featurep 'evil)
|
||||
(add-hook 'anaconda-mode-hook #'evil-normalize-keymaps))
|
||||
|
@ -130,9 +131,10 @@ called.")
|
|||
|
||||
|
||||
(use-package! pyimport
|
||||
:after python
|
||||
:config
|
||||
(map! :map python-mode-map
|
||||
:defer t
|
||||
:init
|
||||
(map! :after python
|
||||
:map python-mode-map
|
||||
:localleader
|
||||
(:prefix ("i" . "imports")
|
||||
:desc "Insert missing imports" "i" #'pyimport-insert-missing
|
||||
|
@ -193,7 +195,18 @@ called.")
|
|||
(_ (pipenv-project-p)))
|
||||
(format "PIPENV_MAX_DEPTH=9999 %s run %%c %%o %%s %%a" bin)
|
||||
"%c %o %s %a")))
|
||||
(:description . "Run Python script"))))
|
||||
(:description . "Run Python script")))
|
||||
(map! :map python-mode-map
|
||||
:localleader
|
||||
:prefix "e"
|
||||
:desc "activate" "a" #'pipenv-activate
|
||||
:desc "deactivate" "d" #'pipenv-deactivate
|
||||
:desc "install" "i" #'pipenv-install
|
||||
:desc "lock" "l" #'pipenv-lock
|
||||
:desc "open module" "o" #'pipenv-open
|
||||
:desc "run" "r" #'pipenv-run
|
||||
:desc "shell" "s" #'pipenv-shell
|
||||
:desc "uninstall" "u" #'pipenv-uninstall))
|
||||
|
||||
|
||||
(use-package! pyvenv
|
||||
|
@ -206,18 +219,7 @@ called.")
|
|||
(add-hook 'python-mode-local-vars-hook #'pyvenv-track-virtualenv)
|
||||
(add-to-list 'global-mode-string
|
||||
'(pyvenv-virtual-env-name (" venv:" pyvenv-virtual-env-name " "))
|
||||
'append)
|
||||
(map! :map python-mode-map
|
||||
:localleader
|
||||
:prefix "e"
|
||||
:desc "activate" "a" #'pipenv-activate
|
||||
:desc "deactivate" "d" #'pipenv-deactivate
|
||||
:desc "install" "i" #'pipenv-install
|
||||
:desc "lock" "l" #'pipenv-lock
|
||||
:desc "open module" "o" #'pipenv-open
|
||||
:desc "run" "r" #'pipenv-run
|
||||
:desc "shell" "s" #'pipenv-shell
|
||||
:desc "uninstall" "u" #'pipenv-uninstall))
|
||||
'append))
|
||||
|
||||
|
||||
|
||||
|
@ -243,19 +245,19 @@ called.")
|
|||
;; If none of these work for you, `conda-anaconda-home' must be set
|
||||
;; explicitly. Afterwards, run M-x `conda-env-activate' to switch between
|
||||
;; environments
|
||||
(unless (cl-loop for dir in (list conda-anaconda-home
|
||||
"~/.anaconda"
|
||||
"~/.miniconda"
|
||||
"~/.miniconda3"
|
||||
"~/miniconda3"
|
||||
"/usr/bin/anaconda3"
|
||||
"/usr/local/anaconda3"
|
||||
"/usr/local/miniconda3"
|
||||
"/usr/local/Caskroom/miniconda/base")
|
||||
if (file-directory-p dir)
|
||||
return (setq conda-anaconda-home dir
|
||||
conda-env-home-directory dir))
|
||||
(message "Cannot find Anaconda installation"))
|
||||
(or (cl-loop for dir in (list conda-anaconda-home
|
||||
"~/.anaconda"
|
||||
"~/.miniconda"
|
||||
"~/.miniconda3"
|
||||
"~/miniconda3"
|
||||
"/usr/bin/anaconda3"
|
||||
"/usr/local/anaconda3"
|
||||
"/usr/local/miniconda3"
|
||||
"/usr/local/Caskroom/miniconda/base")
|
||||
if (file-directory-p dir)
|
||||
return (setq conda-anaconda-home dir
|
||||
conda-env-home-directory dir))
|
||||
(message "Cannot find Anaconda installation"))
|
||||
|
||||
;; integration with term/eshell
|
||||
(conda-env-initialize-interactive-shells)
|
||||
|
@ -297,5 +299,6 @@ called.")
|
|||
|
||||
|
||||
(use-package! flycheck-cython
|
||||
:when (featurep! +cython)
|
||||
:when (featurep! :tools flycheck)
|
||||
:after cython-mode)
|
||||
|
|
|
@ -24,10 +24,8 @@
|
|||
|
||||
(add-hook! 'racket-mode-hook
|
||||
#'rainbow-delimiters-mode
|
||||
#'highlight-quoted-mode)
|
||||
|
||||
(map! :map (racket-mode-map racket-repl-mode-map)
|
||||
:i "[" #'racket-smart-open-bracket)
|
||||
#'highlight-quoted-mode
|
||||
#'racket-smart-open-bracket-mode)
|
||||
|
||||
(map! :localleader
|
||||
:map racket-mode-map
|
||||
|
|
18
modules/lang/rst/config.el
Normal file
18
modules/lang/rst/config.el
Normal file
|
@ -0,0 +1,18 @@
|
|||
;;; lang/rst/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package! sphinx-mode
|
||||
:hook (rst-mode . sphinx-mode))
|
||||
|
||||
(use-package! rst
|
||||
:defer t
|
||||
:config
|
||||
(map! :localleader
|
||||
:map rst-mode-map
|
||||
(:prefix ("a" . "adjust")
|
||||
"a" #'rst-adjust
|
||||
"r" #'rst-adjust-region)
|
||||
(:prefix ("t" . "table of contents")
|
||||
"t" #'rst-toc
|
||||
"i" #'rst-toc-insert
|
||||
"u" #'rst-toc-update
|
||||
"f" #'rst-toc-follow-link)))
|
4
modules/lang/rst/packages.el
Normal file
4
modules/lang/rst/packages.el
Normal file
|
@ -0,0 +1,4 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; lang/rst/packages.el
|
||||
|
||||
(package! sphinx-mode)
|
|
@ -7,43 +7,13 @@
|
|||
;;
|
||||
;;; Packages
|
||||
|
||||
(use-package! rust-mode
|
||||
:defer t
|
||||
:config
|
||||
(setq rust-indent-method-chain t)
|
||||
(add-hook 'rust-mode-hook #'rainbow-delimiters-mode)
|
||||
|
||||
;; This is necessary because both plugins are fighting for supremacy in
|
||||
;; `auto-mode-alist', so rustic-mode *must* load second. It only needs to
|
||||
;; happen once.
|
||||
;;
|
||||
;; rust-mode is still required for `racer'.
|
||||
(add-hook! 'rust-mode-hook
|
||||
(defun +rust-init-h ()
|
||||
"Switch to `rustic-mode', if it's available."
|
||||
(when (require 'rustic nil t)
|
||||
(rustic-mode))))
|
||||
|
||||
(set-docsets! '(rust-mode rustic-mode) "Rust")
|
||||
(when (featurep! +lsp)
|
||||
(add-hook 'rust-mode-local-vars-hook #'lsp!)))
|
||||
|
||||
|
||||
(use-package! racer
|
||||
:unless (featurep! +lsp)
|
||||
:hook ((rust-mode rustic-mode) . racer-mode)
|
||||
:config
|
||||
(set-lookup-handlers! 'rust-mode
|
||||
:definition '(racer-find-definition :async t)
|
||||
:documentation '+rust-racer-lookup-documentation))
|
||||
|
||||
|
||||
(use-package! rustic
|
||||
:when EMACS26+
|
||||
:after rust-mode
|
||||
:mode ("\\.rs$" . rustic-mode)
|
||||
:preface
|
||||
(setq rustic-rls-pkg (if (featurep! +lsp) 'lsp-mode))
|
||||
:config
|
||||
(set-docsets! 'rustic-mode "Rust")
|
||||
|
||||
(setq rustic-indent-method-chain t
|
||||
rustic-flycheck-setup-mode-line-p nil
|
||||
;; use :editor format instead
|
||||
|
@ -52,38 +22,35 @@
|
|||
;; buffers, so we disable it, but only for evil users, because it
|
||||
;; affects `forward-sexp' and its ilk. See
|
||||
;; https://github.com/rust-lang/rust-mode/issues/288.
|
||||
rustic-match-angle-brackets (not (featurep! :editor evil)))
|
||||
rustic-match-angle-brackets (not (featurep! :editor evil))
|
||||
;; `rustic-setup-rls' uses `package-installed-p' to determine if
|
||||
;; lsp-mode/elgot are available. This breaks because Doom doesn't use
|
||||
;; package.el to begin with (and lazy loads it). This is already handled
|
||||
;; by the :tools lsp module, so...
|
||||
rustic-lsp-setup-p nil)
|
||||
|
||||
(add-hook 'rustic-mode-hook #'rainbow-delimiters-mode)
|
||||
|
||||
(defadvice! +rust--dont-install-packages-p (orig-fn &rest args)
|
||||
:around #'rustic-setup-rls
|
||||
(cl-letf (;; `rustic-setup-rls' uses `package-installed-p' to determine if
|
||||
;; lsp-mode/elgot are available. This breaks because Doom doesn't
|
||||
;; use package.el to begin with (and lazy loads it).
|
||||
((symbol-function #'package-installed-p)
|
||||
(lambda (pkg)
|
||||
(require pkg nil t)))
|
||||
;; If lsp/elgot isn't available, it attempts to install lsp-mode
|
||||
;; via package.el. Doom manages its own dependencies so we disable
|
||||
;; that behavior.
|
||||
((symbol-function #'rustic-install-rls-client-p)
|
||||
(lambda (&rest _)
|
||||
(message "No RLS server running"))))
|
||||
(apply orig-fn args))))
|
||||
(when (featurep! +lsp)
|
||||
(add-hook 'rustic-mode-local-vars-hook #'lsp!)))
|
||||
|
||||
|
||||
(use-package! racer
|
||||
:unless (featurep! +lsp)
|
||||
:hook (rustic-mode . racer-mode)
|
||||
:config
|
||||
(set-lookup-handlers! 'rustic-mode
|
||||
:definition '(racer-find-definition :async t)
|
||||
:documentation '+rust-racer-lookup-documentation))
|
||||
|
||||
|
||||
;;
|
||||
;;; Tools
|
||||
|
||||
(use-package! cargo
|
||||
:after rust-mode
|
||||
:after rustic-mode
|
||||
:config
|
||||
(defvar +rust-keymap
|
||||
(if (boundp 'rustic-mode-map)
|
||||
rustic-mode-map
|
||||
rust-mode-map))
|
||||
(map! :map +rust-keymap
|
||||
(map! :map rustic-mode-map
|
||||
:localleader
|
||||
(:prefix ("b" . "build")
|
||||
:desc "cargo add" "a" #'cargo-process-add
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; lang/rust/packages.el
|
||||
|
||||
(when EMACS26+
|
||||
(package! rustic))
|
||||
(package! rust-mode)
|
||||
(package! rustic)
|
||||
(unless (featurep! +lsp)
|
||||
(package! racer))
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
;;; lang/scala/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +scala-comment-indent-new-line (&rest _)
|
||||
(defun +scala-comment-indent-new-line (&optional _)
|
||||
"Continue the commnt on the current line.
|
||||
|
||||
Meant to be used for `scala-mode's `comment-line-break-function'."
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
(use-package! lsp-sourcekit
|
||||
:when (featurep! +lsp)
|
||||
:after swift-mode
|
||||
:init (add-hook 'swift-mode-hook #'lsp!)
|
||||
:init (add-hook 'swift-mode-local-vars-hook #'lsp!)
|
||||
:config
|
||||
(unless (getenv "SOURCEKIT_TOOLCHAIN_PATH")
|
||||
(setenv "SOURCEKIT_TOOLCHAIN_PATH" "/Library/Developer/Toolchains/swift-latest.xctoolchain"))
|
||||
|
|
|
@ -28,12 +28,6 @@
|
|||
(after! css-mode
|
||||
;; css-mode hooks apply to scss and less-css modes
|
||||
(add-hook 'css-mode-hook #'rainbow-delimiters-mode)
|
||||
(set-company-backend! '(css-mode scss-mode)
|
||||
(if EMACS26+
|
||||
;; DEPRECATED css-mode's built in completion is superior in 26+
|
||||
'company-capf
|
||||
'company-css))
|
||||
|
||||
(map! :localleader
|
||||
:map scss-mode-map
|
||||
"b" #'+css/scss-build
|
||||
|
|
|
@ -42,11 +42,8 @@
|
|||
(cl-loop for pair in (cdr alist)
|
||||
unless (string-match-p "^[a-z-]" (cdr pair))
|
||||
collect (cons (car pair)
|
||||
;; TODO Replace with `string-trim-right' (Emacs 26+)
|
||||
(let ((string (cdr pair)))
|
||||
(if (string-match "\\(?:>\\|]\\|}\\)+\\'" string)
|
||||
(replace-match "" t t string)
|
||||
string))))))
|
||||
(string-trim-right (cdr pair)
|
||||
"\\(?:>\\|]\\|}\\)+\\'")))))
|
||||
(delq! nil web-mode-engines-auto-pairs))
|
||||
|
||||
(map! :map web-mode-map
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
(+css--toggle-inline-or-block beg end))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +css/comment-indent-new-line ()
|
||||
(defun +css/comment-indent-new-line (&optional _)
|
||||
"Continues the comment in an indented new line.
|
||||
|
||||
Meant for `comment-line-break-function' in `css-mode' and `scss-mode'."
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
;; +css.el
|
||||
(package! css-mode :built-in t)
|
||||
(package! less-css-mode :built-in (not (version< emacs-version "26.1")))
|
||||
(package! less-css-mode :built-in t)
|
||||
|
||||
(package! sass-mode)
|
||||
(package! stylus-mode)
|
||||
|
|
|
@ -22,9 +22,9 @@ buffer.")
|
|||
(defvar +eshell-aliases
|
||||
'(("q" "exit") ; built-in
|
||||
("f" "find-file $1")
|
||||
("d" "dired $1")
|
||||
("bd" "eshell-up $1")
|
||||
("rg" "rg --color=always $*")
|
||||
("ag" "ag --color=always $*")
|
||||
("l" "ls -lh")
|
||||
("ll" "ls -lah")
|
||||
("clear" "clear-scrollback")) ; more sensible than default
|
||||
|
@ -132,7 +132,7 @@ You should use `set-eshell-alias!' to change this.")
|
|||
:n "C" #'+eshell/evil-change-line
|
||||
:n "d" #'+eshell/evil-delete
|
||||
:n "D" #'+eshell/evil-delete-line
|
||||
:ig "C-d" #'+eshell/quit-or-delete-char
|
||||
:ig "C-d" #'+eshell/quit-or-delete-char
|
||||
"TAB" #'+eshell/pcomplete
|
||||
[tab] #'+eshell/pcomplete
|
||||
"C-s" #'+eshell/search-history
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
;;; tools/ein/autoload/hydra.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! :ui hydra)
|
||||
|
||||
;;;###autoload (autoload '+ein/hydra/body "tools/ein/autoload" nil t)
|
||||
;;;###autoload (autoload '+ein/hydra/body "tools/ein/autoload/hydra" nil t)
|
||||
(defhydra +ein/hydra (:hint t :color red)
|
||||
"
|
||||
Operations on Cells^^^^^^ Other
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue