#!/usr/bin/env sh :; set -e # -*- mode: emacs-lisp; lexical-binding: t -*- :; case "$EMACS" in *term*) EMACS=emacs ;; *) EMACS="${EMACS:-emacs}" ;; esac :; $EMACS --version >/dev/null 2>&1 || { >&2 echo "Can't find emacs in your PATH"; exit 1; } :; $EMACS --no-site-file --script "$0" -- "$@" || __DOOMCODE=$? :; [ "${__DOOMCODE:-0}" -eq 128 ] && { "`$EMACS -Q --batch --eval '(princ temporary-file-directory)'`/doom.sh" "$0" "$@" && true; __DOOMCODE=$?; } :; exit $__DOOMCODE ;; The garbage collector isn't important during CLI ops. A higher threshold ;; makes it 15-30% faster, but set it too high and we risk spiralling memory ;; usage in longer sessions. (setq gc-cons-threshold 134217728) ; 128mb ;; Prioritize non-byte-compiled source files in non-interactive sessions to ;; prevent loading stale byte-code. (setq load-prefer-newer t) ;; Ensure Doom runs out of this file's parent directory, where Doom is ;; presumably installed. EMACSDIR is set in the shell script preamble earlier in ;; this file. (setq user-emacs-directory (if (getenv "EMACSDIR") (file-name-as-directory (expand-file-name (getenv "EMACSDIR"))) (expand-file-name "../" (file-name-directory (file-truename load-file-name))))) ;; Handle some potential issues early (when (version< emacs-version "26.1") (error (concat "Detected Emacs %s (at %s).\n\n" "Doom only supports Emacs 26.1 and newer. 27.1 is highly recommended. A guide\n" "to install a newer version of Emacs can be found at:\n\n " (cond ((eq system-type 'darwin) "https://github.com/hlissner/doom-emacs/blob/develop/docs/getting_started.org#on-macos") ((memq system-type '(cygwin windows-nt ms-dos)) "https://github.com/hlissner/doom-emacs/blob/develop/docs/getting_started.org#on-windows") ("https://github.com/hlissner/doom-emacs/blob/develop/docs/getting_started.org#on-linux")) "Aborting...") emacs-version (car command-line-args))) (unless (file-exists-p (expand-file-name "core/core.el" user-emacs-directory)) (error (concat "Couldn't find Doom Emacs in %S.\n\n" "This is likely because this script (or its parent directory) is a symlink.\n" "If you must use a symlink, you'll need to specify an EMACSDIR so Doom knows\n" "where to find itself. e.g.\n\n " (if (string-match-p "/fish$" (getenv "SHELL")) "env EMACSDIR=~/.emacs.d doom" "EMACSDIR=~/.emacs.d doom sync") "\n\n" "Aborting...") (abbreviate-file-name (file-truename user-emacs-directory)) (abbreviate-file-name load-file-name))) (when (and (equal (user-real-uid) 0) (not (file-in-directory-p user-emacs-directory "/root"))) (error (concat "This script is running as root. This likely wasn't intentional and\n" "will cause file permissions errors later if this Doom install is\n" "ever used on a non-root account.\n\n" "Aborting..."))) ;; Load the heart of the beast and its CLI processing library (load (expand-file-name "core/core.el" user-emacs-directory) nil t) (require 'core-cli) ;; Use our own home-grown debugger to display and log errors + backtraces. ;; Control over its formatting is important, because Emacs produces ;; difficult-to-read debug information otherwise. By making its errors more ;; presentable (and storing them somewhere users can access later) we go a long ;; way toward making it easier for users to write better bug reports. (setq debugger #'doom-cli--debugger debug-on-error t debug-ignored-errors nil) ;; HACK Load `cl' and site files manually to prevent polluting logs and stdout ;; with deprecation and/or file load messages. (quiet! (if EMACS27+ (require 'cl)) (load "site-start" t t)) (kill-emacs (pcase (catch 'exit ;; Process the arguments passed to this script. `doom-cli-execute' should ;; return a boolean, integer (error code) or throw an 'exit event, which ;; we handle specially. (apply #'doom-cli-execute :doom (cdr (member "--" argv)))) ;; Any non-zero integer is treated as an error code. ((and (pred integerp) code) code) ;; If, instead, we were given a list or string, copy these as shell script ;; commands to a temp script file which this script will execute after this ;; session finishes. Also accepts special keywords, like `:restart', to rerun ;; the current command. ((and (or (pred consp) (pred stringp) (pred keywordp)) command) (let ((script (expand-file-name "doom.sh" temporary-file-directory)) (coding-system-for-write 'utf-8-unix) (coding-system-for-read 'utf-8-unix)) (with-temp-file script (insert "#!/usr/bin/env sh\n" "_postscript() {\n" " rm -f " (shell-quote-argument script) "\n " (cond ((eq command :restart) "$@") ((stringp command) command) ((string-join (if (listp (car-safe command)) (cl-loop for line in (doom-enlist command) collect (mapconcat #'shell-quote-argument (remq nil line) " ")) (list (mapconcat #'shell-quote-argument (remq nil command) " "))) "\n "))) "\n}\n" (save-match-data (cl-loop for env in (cl-set-difference process-environment doom--initial-process-environment :test #'equal) if (string-match "^\\([a-zA-Z0-9_]+\\)=\\(.+\\)$" env) concat (format "%s=%s \\\n" (match-string 1 env) (shell-quote-argument (match-string 2 env))))) (format "PATH=\"%s%s$PATH\" \\\n" (concat doom-emacs-dir "bin/") path-separator) "_postscript $@\n")) (set-file-modes script #o700)) ;; Error code 128 is special: it means run the post-script after this ;; session ends. 128) ;; Anything else (e.g. booleans) is treated as a successful run. Yes, a `nil' ;; indicates a successful run too! (_ 0)))