doom-emacs/lisp/doom-cli.el
Henrik Lissner 422baedad7
refactor(cli): load cli libs from doom.el
This simplifies the entry point for loading Doom (and/or its CLI
framework).
2022-08-07 19:43:28 +02:00

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