134 lines
5.3 KiB
EmacsLisp
134 lines
5.3 KiB
EmacsLisp
;;; lisp/doom-cli.el --- The heart of Doom's CLI framework -*- lexical-binding: t; no-byte-compile: t; -*-
|
|
;;; Commentary:
|
|
;;
|
|
;; The bootstrapper for Doom's CLI. This is *not* safe to load in interactive
|
|
;; sessions as it has many side-effects. Loads `doom-cli-lib' instead for API
|
|
;; access and syntax highlighting.
|
|
;;
|
|
;;; Code:
|
|
|
|
(when (version< emacs-version "27.1")
|
|
(message
|
|
(concat
|
|
"Error: detected Emacs " emacs-version ", but 27.1 or newer is required.\n\n"
|
|
"The version of Emacs in use is located at:\n\n " (car command-line-args) "\n\n"
|
|
"A guide for installing a newer version of Emacs can be found at:\n\n "
|
|
(format "https://doomemacs.org/docs/getting_started.org#%s\n"
|
|
(cond ((eq system-type 'darwin) "on-macos")
|
|
((memq system-type '(cygwin windows-nt ms-dos)) "on-windows")
|
|
("on-linux"))) "\n"
|
|
"Alternatively, alter the EMACS environment variable to temporarily change what\n"
|
|
"command this script uses to invoke Emacs. For example:\n\n"
|
|
(let ((command (file-name-nondirectory (cadr (member "--load" command-line-args)))))
|
|
(concat " $ EMACS=/path/to/valid/emacs " command " ...\n"
|
|
" $ EMACS=\"/Applications/Emacs.app/Contents/MacOS/Emacs\" " command " ...\n"
|
|
" $ EMACS=\"snap run emacs\" " command " ...\n"))
|
|
"\nAborting..."))
|
|
(kill-emacs 2))
|
|
|
|
|
|
;;
|
|
;;; Setup CLI session
|
|
|
|
;; The garbage collector isn't so important during CLI ops. A higher threshold
|
|
;; makes it 15-30% faster, but set it too high and we risk runaway memory usage
|
|
;; in longer sessions.
|
|
(setq gc-cons-threshold 134217728 ; 128mb
|
|
gc-cons-percentage 1.0)
|
|
|
|
;; Ensure errors are sufficiently detailed from this point on.
|
|
(setq debug-on-error t)
|
|
;; Be more verbose if debug mode is on.
|
|
(when (setq init-file-debug (getenv "DEBUG"))
|
|
(message "Debug mode enabled"))
|
|
|
|
;;; Initialize profile
|
|
(let ((profile (getenv "DOOMPROFILE")))
|
|
(when profile
|
|
(with-temp-buffer
|
|
(let ((coding-system-for-read 'utf-8-auto)
|
|
(profiles-file (expand-file-name "profiles.el" user-emacs-directory)))
|
|
(condition-case e
|
|
(progn
|
|
(insert-file-contents profiles-file)
|
|
(dolist (var (or (cdr (assq (intern profile) (read (current-buffer))))
|
|
(progn (message "No %S profile found" profile)
|
|
(kill-emacs 3))))
|
|
(if (eq (car var) 'env)
|
|
(dolist (env (cdr var)) (setenv (car env) (cdr env)))
|
|
(set (car var) (cdr var)))))
|
|
(file-missing
|
|
(message "No $EMACSDIR/%s file to look up %S in."
|
|
(file-name-nondirectory profiles-file)
|
|
profile)
|
|
(kill-emacs 3))
|
|
(end-of-file (signal 'end-of-file (list profiles-file)))
|
|
(error (error "Parser error in profiles.el: %s" (error-message-string e))))))))
|
|
|
|
;; HACK Load `cl' and site files manually to prevent polluting logs and stdout
|
|
;; with deprecation and/or file load messages.
|
|
(let ((inhibit-message (not init-file-debug)))
|
|
(require 'cl)
|
|
(unless site-run-file
|
|
(let ((site-run-file "site-start")
|
|
(tail load-path)
|
|
(lispdir (expand-file-name "../lisp" data-directory))
|
|
dir)
|
|
(while tail
|
|
(setq dir (car tail))
|
|
(let ((default-directory dir))
|
|
(load (expand-file-name "subdirs.el") t inhibit-message t))
|
|
(unless (string-prefix-p lispdir dir)
|
|
(let ((default-directory dir))
|
|
(load (expand-file-name "leim-list.el") t inhibit-message t)))
|
|
(setq tail (cdr tail)))
|
|
(load site-run-file t inhibit-message))))
|
|
|
|
;; Just the... bear necessities~
|
|
(require 'doom (expand-file-name "doom" (file-name-directory load-file-name)))
|
|
|
|
;; Don't generate superfluous files when writing temp buffers.
|
|
(setq make-backup-files nil)
|
|
;; Stop user configuration from interfering with package management.
|
|
(setq enable-dir-local-variables nil)
|
|
;; Reduce ambiguity, embrace specificity, enjoy predictability.
|
|
(setq-default case-fold-search nil)
|
|
;; Don't clog the user's trash with anything we clean up during this session.
|
|
(setq delete-by-moving-to-trash nil)
|
|
|
|
|
|
;;
|
|
;;; Bootstrap
|
|
|
|
;; Use our own home-grown debugger so we can capture backtraces, make them more
|
|
;; presentable, and write them to a file. Cleaner backtraces are better UX than
|
|
;; the giant wall of text the default debugger throws up.
|
|
(setq debugger #'doom-cli-debugger)
|
|
|
|
;; Create all our core directories to quell file errors.
|
|
(mapc (doom-rpartial #'make-directory 'parents)
|
|
(list doom-local-dir
|
|
doom-etc-dir
|
|
doom-cache-dir))
|
|
|
|
;; Load standard :help and :version handlers.
|
|
(load! "cli/help")
|
|
|
|
;; When __DOOMDUMP is set, doomscripts trigger this special handler.
|
|
(defcli! (:root :dump)
|
|
((pretty? ("--pretty") "Pretty print output")
|
|
&context context
|
|
&args commands)
|
|
"Dump metadata to stdout for other commands to read."
|
|
(let* ((prefix (doom-cli-context-prefix context))
|
|
(command (cons prefix commands)))
|
|
(funcall (if pretty? #'pp #'prin1)
|
|
(cond ((equal commands '("-")) (hash-table-values doom-cli--table))
|
|
(commands (doom-cli-find command))
|
|
((doom-cli-find (list prefix)))))
|
|
(terpri)
|
|
;; Kill manually so we don't save output to logs.
|
|
(let (kill-emacs) (kill-emacs 0))))
|
|
|
|
(provide 'doom-cli)
|
|
;;; doom-cli.el ends here
|