dev: merge branch 'master' of github.com:doomemacs

This commit is contained in:
Matt Nish-Lapidus 2024-09-03 10:24:32 -04:00
commit 4a8987bcce
34 changed files with 2915 additions and 2919 deletions

View file

@ -62,17 +62,14 @@
;; Put together, plus a strategically placed exit call, the shell will read
;; one part of this file and ignore the rest, while the elisp interpreter will
;; do the opposite.
;; - I intentionally avoid loading site files, so lisp/doom-cli.el can load them
;; by hand later. There, I can suppress and deal with unhelpful warnings (e.g.
;; "package cl is deprecated"), "Loading X...DONE" spam, and any other
;; disasterous side-effects.
;;
;; But be careful not to use -Q! It implies --no-site-lisp, which omits the
;; site-lisp directory from `load-path'.
;; - I intentionally suppress loading site files (must be done with '-q
;; --no-site-file' NOT '-Q', as the latter omits the site-lisp dir from
;; `load-path' too), so lisp/doom-cli.el can load them manually later (early
;; in lisp/doom-cli.el). Look there for an explanation why I do this.
;; - POSIX-compliancy is paramount: there's no guarantee what /bin/sh will be
;; symlinked to in the esoteric OSes/distros Emacs users use.
;; - The user may have a noexec flag set on /tmp, so pass the exit script to
;; /bin/sh rather than executing them directly.
;; - The user may have mounted /tmp with a noexec flag, so pass the exit script
;; to /bin/sh rather than executing them directly.
;; In CLI sessions, prefer correctness over performance.
(setq load-prefer-newer t)

View file

@ -1,25 +0,0 @@
:: Forward the ./doom script to Emacs
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
PUSHD "%~dp0" >NUL
SET args=
SET command=%1
:LOOP
SHIFT /1
IF NOT [%1]==[] (
SET args=%args% %1
GOTO :LOOP
)
IF [%command%]==[run] (
start runemacs -Q %args% -l ..\init.el -f "doom-run-all-startup-hooks-h"
) ELSE (
emacs --quick --script .\doom -- %*
)
POPD >NUL
ECHO ON

View file

@ -1,159 +0,0 @@
#!/usr/bin/env sh
":"; exec emacs --quick --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-
;;; bin/org-tangle
;; Tangles source blocks from org files. Also expands #+INCLUDE directives,
;; unlike vanilla `ob-tangle'. Debug/info messages are directed to stderr and
;; can be ignored.
;;
;; -l/--lang LANG
;; Only include blocks in the specified language (e.g. emacs-lisp).
;; -a/--all
;; Tangle all blocks by default (unless it has :tangle nil set or a
;; :notangle: tag)
;; -t/--tag TAG
;; --and TAG
;; --or TAG
;; Only include blocks in trees that have these tags. Combine multiple --and
;; and --or's, or just use --tag (implicit --and).
;; -p/--print
;; Prints tangled code to stdout instead of to files
;;
;; Usage: org-tangle [[-l|--lang] LANG] some-file.org another.org
;; Examples:
;; org-tangle -l sh modules/some/module/README.org > install_module.sh
;; org-tangle -l sh modules/lang/go/README.org | sh
;; org-tangle --and tagA --and tagB my/literate/config.org
(require 'cl-lib)
(require 'ox)
(require 'ob-tangle)
(defun usage ()
(with-temp-buffer
(insert (format "%s %s [OPTIONS] [TARGETS...]\n"
"Usage:"
(file-name-nondirectory load-file-name))
"\n"
"A command line interface for tangling org-mode files. TARGETS can be\n"
"files or folders (which are searched for org files recursively).\n"
"\n"
"This is useful for literate configs that rely on command line\n"
"workflows to build it.\n"
"\n"
"Example:\n"
" org-tangle some-file.org\n"
" org-tangle literate/config/\n"
" org-tangle -p -l sh scripts.org > do_something.sh\n"
" org-tangle -p -l python -t tagA -t tagB file.org | python\n"
"\n"
"Options:\n"
" -a --all\t\tTangle all blocks by default\n"
" -l --lang LANG\tOnly tangle blocks written in LANG\n"
" -p --print\t\tPrint tangled output to stdout than to files\n"
" -t --tag TAG\n"
" --and TAG\n"
" --or TAG\n"
" Lets you tangle org blocks by tag. You may have more than one\n"
" of these options.\n")
(princ (buffer-string))))
(defun *org-babel-tangle (fn &rest args)
"Don't write tangled blocks to files, print them to stdout."
(cl-letf (((symbol-function 'write-region)
(lambda (start end filename &optional append visit lockname mustbenew)
(princ (buffer-string)))))
(apply fn args)))
(defun *org-babel-tangle-collect-blocks (&optional language tangle-file)
"Like `org-babel-tangle-collect-blocks', but will ignore blocks that are in
trees with the :notangle: tag."
(let ((counter 0) last-heading-pos blocks)
(org-babel-map-src-blocks (buffer-file-name)
(let ((current-heading-pos
(org-with-wide-buffer
(org-with-limited-levels (outline-previous-heading)))))
(if (eq last-heading-pos current-heading-pos) (cl-incf counter)
(setq counter 1)
(setq last-heading-pos current-heading-pos)))
(unless (org-in-commented-heading-p)
(require 'org)
(let* ((tags (org-get-tags-at))
(info (org-babel-get-src-block-info 'light))
(src-lang (nth 0 info))
(src-tfile (cdr (assq :tangle (nth 2 info)))))
(cond ((member "notangle" tags))
((and (or or-tags and-tags)
(or (not and-tags)
(let ((a (cl-intersection and-tags tags :test #'string=))
(b and-tags))
(not (or (cl-set-difference a b :test #'equal)
(cl-set-difference b a :test #'equal)))))
(or (not or-tags)
(cl-intersection or-tags tags :test #'string=))
t))
((or (not (or all-blocks src-tfile))
(string= src-tfile "no") ; tangle blocks by default
(and tangle-file (not (equal tangle-file src-tfile)))
(and language (not (string= language src-lang)))))
;; Add the spec for this block to blocks under its language.
((let ((by-lang (assoc src-lang blocks))
(block (org-babel-tangle-single-block counter)))
(if by-lang
(setcdr by-lang (cons block (cdr by-lang)))
(push (cons src-lang (list block)) blocks))))))))
;; Ensure blocks are in the correct order.
(mapcar (lambda (b) (cons (car b) (nreverse (cdr b)))) blocks)))
(advice-add #'org-babel-tangle-collect-blocks
:override #'*org-babel-tangle-collect-blocks)
(defvar all-blocks nil)
(defvar and-tags nil)
(defvar or-tags nil)
(let (lang srcs and-tags or-tags)
(pop argv)
(while argv
(let ((arg (pop argv)))
(pcase arg
((or "-h" "--help")
(usage)
(error ""))
((or "-a" "--all")
(setq all-blocks t))
((or "-l" "--lang")
(setq lang (pop argv)))
((or "-p" "--print")
(advice-add #'org-babel-tangle :around #'*org-babel-tangle))
((or "-t" "--tag" "--and")
(push (pop argv) and-tags))
("--or"
(push (pop argv) or-tags))
((guard (string-match-p "^--lang=" arg))
(setq lang (cadr (split-string arg "=" t t))))
((guard (file-directory-p arg))
(setq srcs
(append (directory-files-recursively arg "\\.org$")
srcs)))
((guard (file-exists-p arg))
(push arg srcs))
(_ (error "Unknown option or file: %s" arg)))))
(dolist (file srcs)
(let ((backup (make-temp-file (file-name-base file) nil ".backup.org")))
(unwind-protect
;; Prevent slow hooks from interfering
(let (org-mode-hook org-confirm-babel-evaluate)
;; We do the ol' switcheroo because `org-babel-tangle' writes
;; changes to the current file, which would be imposing on the user.
(copy-file file backup t)
(with-current-buffer (find-file-noselect file)
;; Tangling doesn't expand #+INCLUDE directives, so we do it
;; ourselves, since includes are so useful for literate configs!
(org-export-expand-include-keyword)
(org-babel-tangle nil nil lang)))
(ignore-errors (copy-file backup file t))
(ignore-errors (delete-file backup)))))
(kill-emacs 0))

View file

@ -1,519 +0,0 @@
;;; lisp/cli/meta.el -*- lexical-binding: t; -*-
;;; Commentary:
;;
;; This file defines special commands that the Doom CLI will invoke when a
;; command is passed with -?, --help, or --version. They can also be aliased to
;; a sub-command to make more of its capabilities accessible to users, with:
;;
;; (defcli-alias! (myscript (help h)) (:help))
;;
;; You can define your own command-specific help handlers, e.g.
;;
;; (defcli! (:help myscript subcommand) () ...)
;;
;; And it will be invoked instead of the generic one.
;;
;;; Code:
;;
;;; Variables
(defvar doom-help-commands '("%p %c {-?,--help}")
"A list of help commands recognized for the running script.
Recognizes %p (for the prefix) and %c (for the active command).")
;;
;;; Commands
;; 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))))
(defcli! (:root :help)
((localonly? ("-g" "--no-global") "Hide global options")
(manpage? ("--manpage") "Generate in manpage format")
(commands? ("--commands") "List all known commands")
&multiple
(sections ("--synopsis" "--subcommands" "--similar" "--envvars"
"--postamble")
"Show only the specified sections.")
&context context
&args command)
"Show documentation for a Doom CLI command.
OPTIONS:
--synopsis, --subcommands, --similar, --envvars, --postamble
TODO"
(doom-cli-load-all)
(when (doom-cli-context-error context)
(terpri))
(let* ((command (cons (doom-cli-context-prefix context) command))
(cli (doom-cli-get command t))
(rcli (doom-cli-get cli))
(fallbackcli (cl-loop with targets = (doom-cli--command-expand (butlast command) t)
for cmd in (cons command targets)
if (doom-cli-get cmd t)
return it)))
(cond (commands?
(let ((cli (or cli (doom-cli-get (doom-cli-context-prefix context)))))
(print! "Commands under '%s':\n%s"
(doom-cli-command-string cli)
(indent (doom-cli-help--render-commands
(or (doom-cli-subcommands cli)
(user-error "No commands found"))
:prefix (doom-cli-command cli)
:inline? t
:docs? t)))))
((null sections)
(if (null cli)
(signal 'doom-cli-command-not-found-error command)
(doom-cli-help--print cli context manpage? localonly?)
(exit! :pager?)))
((dolist (section sections)
(unless (equal section (car sections)) (terpri))
(pcase section
("--synopsis"
(print! "%s" (doom-cli-help--render-synopsis
(doom-cli-help--synopsis cli)
"Usage: ")))
("--subcommands"
(print! "%s\n%s" (bold "Available commands:")
(indent (doom-cli-help--render-commands
(doom-cli-subcommands rcli 1)
:prefix command
:grouped? t
:docs? t)
doom-print-indent-increment)))
("--similar"
(unless command
(user-error "No command specified"))
(let ((similar (doom-cli-help-similar-commands command 0.4)))
(print! "Similar commands:")
(if (not similar)
(print! (indent (warn "Can't find any!")))
(dolist (command (seq-take similar 10))
(print! (indent (item "(%d%%) %s"))
(* (car command) 100)
(doom-cli-command-string (cdr command)))))))
("--envvars"
(let* ((key "ENVIRONMENT VARIABLES")
(clis (if command (doom-cli-find command) (hash-table-values doom-cli--table)))
(clis (seq-remove #'doom-cli-alias clis))
(clis (seq-filter (fn! (cdr (assoc key (doom-cli-docs %)))) clis))
(clis (seq-group-by #'doom-cli-command clis)))
(print! "List of environment variables for %s:\n" command)
(if (null clis)
(print! (indent "None!"))
(dolist (group clis)
(print! (bold "%s%s:"
(doom-cli-command-string (car group))
(if (doom-cli-fn (doom-cli-get (car group)))
"" " *")))
(dolist (cli (cdr group))
(print! (indent "%s") (markup (cdr (assoc key (doom-cli-docs cli))))))))))
("--postamble"
(print! "See %s for documentation."
(join (cl-loop with spec =
`((?p . ,(doom-cli-context-prefix context))
(?c . ,(doom-cli-command-string (cdr (doom-cli-command (or cli fallbackcli))))))
for cmd in doom-help-commands
for formatted = (trim (format-spec cmd spec))
collect (replace-regexp-in-string
" +" " " (format "'%s'" formatted)))
" or ")))))))))
(defcli! (:root :version)
((simple? ("--simple"))
&context context)
"Show installed versions of Doom, Doom modules, and Emacs."
(doom/version)
(unless simple?
(terpri)
(with-temp-buffer
(insert-file-contents (doom-path doom-emacs-dir "LICENSE"))
(re-search-forward "^Copyright (c) ")
(print! "%s\n" (trim (thing-at-point 'line t)))
(print! (p "Doom Emacs uses the MIT license and is provided without warranty "
"of any kind. You may redistribute and modify copies if "
"given proper attribution. See the LICENSE file for details.")))))
;;
;;; Helpers
(defun doom-cli-help (cli)
"Return an alist of documentation summarizing CLI (a `doom-cli')."
(let* ((rcli (doom-cli-get cli))
(docs (doom-cli-docs rcli)))
`((command . ,(doom-cli-command-string cli))
(summary . ,(or (cdr (assoc "SUMMARY" docs)) "TODO"))
(description . ,(or (cdr (assoc "MAIN" docs)) "TODO"))
(synopsis . ,(doom-cli-help--synopsis cli))
(arguments . ,(doom-cli-help--arguments rcli))
(options . ,(doom-cli-help--options rcli))
(commands . ,(doom-cli-subcommands cli 1))
(sections . ,(seq-filter #'cdr (cddr docs))))))
(defun doom-cli-help-similar-commands (command &optional maxscore)
"Return N commands that are similar to COMMAND."
(seq-take-while
(fn! (>= (car %) (or maxscore 0.0)))
(seq-sort-by
#'car #'>
(cl-loop with prefix = (seq-find #'doom-cli-get (nreverse (doom-cli--command-expand command t)))
with input = (doom-cli-command-string (cdr (doom-cli--command command t)))
for command in (hash-table-keys doom-cli--table)
if (doom-cli-fn (doom-cli-get command))
if (equal prefix (seq-take command (length prefix)))
collect (cons (doom-cli-help--similarity
input (doom-cli-command-string (cdr command)))
command)))))
(defun doom-cli-help--similarity (a b)
(- 1 (/ (float (doom-cli-help--string-distance a b))
(max (length a) (length b)))))
(defun doom-cli-help--string-distance (a b)
"Calculate the Restricted Damerau-Levenshtein distance between A and B.
This is also known as the Optimal String Alignment algorithm.
It is assumed that A and B are both strings, and before processing both are
converted to lowercase.
This returns the minimum number of edits required to transform A
to B, where each edit is a deletion, insertion, substitution, or
transposition of a character, with the restriction that no
substring is edited more than once."
(let ((a (downcase a))
(b (downcase b))
(alen (length a))
(blen (length b))
(start 0))
(when (> alen blen)
(let ((c a)
(clen alen))
(setq a b alen blen
b c blen clen)))
(while (and (< start (min alen blen))
(= (aref a start) (aref b start)))
(cl-incf start))
(cl-decf start)
(if (= (1+ start) alen)
(- blen start)
(let ((v0 (make-vector (- blen start) 0))
(v1 (make-vector (- blen start) 0))
(a_i (aref a (max 0 start)))
(current 0)
a_i-1 b_j b_j-1
left transition-next
above this-transition)
(dotimes (vi (length v0))
(aset v0 vi (1+ vi)))
(dolist (i (number-sequence (1+ start) (1- alen)))
(setq a_i-1 a_i
a_i (aref a i)
b_j (aref b (max 0 start))
left (- i start 1)
current (- i start)
transition-next 0)
(dolist (j (number-sequence (1+ start) (1- blen)))
(setq b_j-1 b_j
b_j (aref b j)
above current
current left
this-transition transition-next
transition-next (aref v1 (- j start)))
(aset v1 (- j start) current)
(setq left (aref v0 (- j start)))
(unless (= a_i b_j)
;; Minimum between substitution, deletion, and insertion
(setq current (min (1+ current) (1+ above) (1+ left)))
(when (and (> i (1+ start)) (> j (1+ start)) (= a_i b_j-1) (= a_i-1 b_j))
(setq current (min current (cl-incf this-transition)))))
(aset v0 (- j start) current)))
current))))
;;; Help: printers
;; TODO Parameterize optional args with `cl-defun'
(defun doom-cli-help--print (cli context &optional manpage? noglobal?)
"Write CLI's documentation in a manpage-esque format to stdout."
(let-alist (doom-cli-help cli)
(let* ((alist
`(,@(if manpage?
`((nil . ,(let* ((title (cadr (member "--load" command-line-args)))
(width (floor (/ (- (doom-cli-context-width context)
(length title))
2.0))))
;; FIXME Who am I fooling?
(format (format "%%-%ds%%s%%%ds" width width)
"DOOM(1)" title "DOOM(1)")))
("NAME" . ,(concat .command " - " .summary))
("SYNOPSIS" . ,(doom-cli-help--render-synopsis .synopsis nil t))
("DESCRIPTION" . ,.description))
`((nil . ,(doom-cli-help--render-synopsis .synopsis "Usage: "))
(nil . ,(string-join (seq-remove #'string-empty-p (list .summary .description))
"\n\n"))))
("ARGUMENTS" . ,(doom-cli-help--render-arguments .arguments))
("COMMANDS"
. ,(doom-cli-help--render-commands
.commands :prefix (doom-cli-command cli) :grouped? t :docs? t))
("OPTIONS"
. ,(doom-cli-help--render-options
(if (or (not (doom-cli-fn cli)) noglobal?)
`(,(assq 'local .options))
.options)
cli))))
(command (doom-cli-command cli)))
(letf! (defun printsection (section)
(print! "%s\n"
(if (null section)
(dark "TODO")
(markup
(format-spec
section `((?p . ,(car command))
(?c . ,(doom-cli-command-string (cdr command))))
'ignore)))))
(pcase-dolist (`(,label . ,contents) alist)
(when (and contents (not (string-blank-p contents)))
(when label
(print! (bold "%s%s") label (if manpage? "" ":")))
(print-group! :if label (printsection contents))))
(pcase-dolist (`(,label . ,contents) .sections)
(when (and contents (not (assoc label alist)))
(print! (bold "%s:") label)
(print-group! (printsection contents))))))))
;;; Help: synopsis
(defun doom-cli-help--synopsis (cli &optional all-options?)
(let* ((rcli (doom-cli-get cli))
(opts (doom-cli-help--options rcli))
(opts (mapcar #'car (if all-options? (mapcan #'cdr opts) (alist-get 'local opts))))
(opts (cl-loop for opt in opts
for args = (cdar opt)
for switches = (mapcar #'car opt)
for multi? = (member "..." args)
if args
collect (format (if multi? "[%s %s]..." "[%s %s]")
(string-join switches "|")
(string-join (remove "..." args) "|"))
else collect (format "[%s]" (string-join switches "|"))))
(args (doom-cli-arguments rcli))
(subcommands? (doom-cli-subcommands rcli 1 :predicate? t)))
`((command . ,(doom-cli-command cli))
(options ,@opts)
(required ,@(mapcar (fn! (upcase (format "`%s'" %))) (if subcommands? '(command) (alist-get '&required args))))
(optional ,@(mapcar (fn! (upcase (format "[`%s']" %)))(alist-get '&optional args)))
(rest ,@(mapcar (fn! (upcase (format "[`%s'...]" %))) (if subcommands? '(args) (alist-get '&args args)))))))
(defun doom-cli-help--render-synopsis (synopsis &optional prefix)
(let-alist synopsis
(let ((doom-print-indent 0)
(prefix (or prefix ""))
(command (doom-cli-command-string .command)))
(string-trim-right
(format! "%s\n\n"
(fill (concat (bold prefix)
(format "%s " command)
(markup
(join (append .options
(and .options
(or .required
.optional
.rest)
(list (dark "[--]")))
.required
.optional
.rest))))
80 (1+ (length (concat prefix command)))))))))
;;; Help: arguments
(defun doom-cli-help--arguments (cli &optional all?)
(doom-cli-help--parse-docs (doom-cli-find cli t) "ARGUMENTS"))
(defun doom-cli-help--render-arguments (arguments)
(mapconcat (lambda (arg)
(format! "%-20s\n%s"
(underscore (car arg))
(indent (if (equal (cdr arg) "TODO")
(dark (cdr arg))
(cdr arg))
doom-print-indent-increment)))
arguments
"\n"))
;;; Help: commands
(cl-defun doom-cli-help--render-commands (commands &key prefix grouped? docs? (inline? t))
(with-temp-buffer
(let* ((doom-print-indent 0)
(commands (seq-group-by (fn! (if grouped? (doom-cli-prop (doom-cli-get % t) :group)))
(nreverse commands)))
(toplevel (assq nil commands))
(rest (remove toplevel commands))
(drop (if prefix (length prefix) 0))
(minwidth
(apply
#'max (or (cl-loop for cmd in (apply #'append (mapcar #'cdr commands))
for cmd = (seq-drop cmd drop)
collect (length (doom-cli-command-string cmd)))
(list 15))))
(ellipsis (doom-print--style 'dark " […]"))
(ellipsislen (- (length ellipsis) (if (eq doom-print-backend 'ansi) 2 4))))
(dolist (group (cons toplevel rest))
(let ((label (if (car-safe group) (cdr commands))))
(when label
(insert! ((bold "%s:") (car group)) "\n"))
(print-group! :if label
(dolist (command (cdr group))
(let* ((cli (doom-cli-get command t))
(rcli (doom-cli-get command))
(summary (doom-cli-short-docs rcli))
(subcommands? (doom-cli-subcommands cli 1 :predicate? t)))
(insert! ((format "%%-%ds%%s%%s"
(+ (- minwidth doom-print-indent)
doom-print-indent-increment
(if subcommands? ellipsislen 0)))
(concat (doom-cli-command-string (seq-drop command drop))
(if subcommands? ellipsis))
(if inline? " " "\n")
(indent (if (and (doom-cli-alias cli)
(not (doom-cli-type rcli)))
(dark "-> %s" (doom-cli-command-string cli))
(when docs?
(if summary (markup summary) (dark "TODO"))))))
"\n")))
(when (cdr rest)
(insert "\n")))))
(string-trim-right (buffer-string)))))
;;; Help: options
(defun doom-cli-help--options (cli &optional noformatting?)
"Return an alist summarizing CLI's options.
The alist's CAR are lists of formatted switches plus their arguments, e.g.
'((\"`--foo'\" \"`BAR'\") ...). Their CDR is their formatted documentation."
(let* ((docs (doom-cli-help--parse-docs (doom-cli-find cli t) "OPTIONS"))
(docs (mapcar (fn! (cons (split-string (car %) ", ")
(cdr %)))
docs))
(strfmt (if noformatting? "%s" "`%s'"))
local-options
global-options
seen)
(dolist (neighbor (nreverse (doom-cli-find cli)))
(dolist (option (doom-cli-options neighbor))
(when-let* ((switches (cl-loop for sw in (doom-cli-option-switches option)
if (and (doom-cli-option-flag-p option)
(string-prefix-p "--" sw))
collect (format "--[no-]%s" (substring sw 2))
else collect sw))
(switches (seq-difference switches seen)))
(dolist (switch switches) (push switch seen))
(push (cons (cl-loop for switch in switches
if (doom-cli-option-arguments option)
collect (cons (format strfmt switch)
(append (doom-cli-help--parse-args it noformatting?)
(when (doom-cli-option-multiple-p option)
(list "..."))))
else collect (list (format strfmt switch)))
(string-join
(or (delq
nil (cons (when-let (docs (doom-cli-option-docs option))
(concat docs "."))
(cl-loop for (flags . docs) in docs
unless (equal (seq-difference flags switches) flags)
collect docs)))
'("TODO"))
"\n\n"))
(if (equal (doom-cli-command neighbor)
(doom-cli-command cli))
local-options
global-options)))))
`((local . ,(nreverse local-options))
(global . ,(nreverse global-options)))))
(defun doom-cli-help--render-options (options &optional cli)
(let ((doom-print-indent 0)
(local (assq 'local options))
(global (assq 'global options)))
(when (or (cdr local) (cdr global))
(letf! (defun printopts (opts)
(pcase-dolist (`(,switches . ,docs) (cdr opts))
(let (multiple?)
(insert!
("%s%s\n%s"
(mapconcat
(fn! (when (member "..." (cdr %))
(setq multiple? t))
(string-trim-right
(format "%s %s"
(doom-print--cli-markup (car %))
(doom-print--cli-markup
(string-join (remove "..." (cdr %)) "|")))))
switches
", ")
(if multiple? ", ..." "")
(indent (fill (markup docs)) doom-print-indent-increment))
"\n\n"))))
(with-temp-buffer
(if (null (cdr local))
(insert (if global "This command has no local options.\n" "") "\n")
(printopts local))
(when (cdr global)
(insert! ((bold "Global options:\n")))
(print-group! (printopts global)))
(string-trim-right (buffer-string)))))))
;;; Help: internal
(defun doom-cli-help--parse-args (args &optional noformatting?)
(cl-loop for arg in args
if (listp arg)
collect (string-join (doom-cli-help--parse-args arg noformatting?) "|")
else if (symbolp arg)
collect (format (if noformatting? "%s" "`%s'") (upcase (symbol-name arg)))
else collect arg))
(defun doom-cli-help--parse-docs (cli-list section-name)
(cl-check-type section-name string)
(let (alist)
(dolist (cli cli-list (nreverse alist))
(when-let (section (cdr (assoc section-name (doom-cli-docs cli))))
(with-temp-buffer
(save-excursion (insert section))
(let ((lead (current-indentation))
(buffer (current-buffer)))
(while (not (eobp))
(let ((heading (string-trim (buffer-substring (point-at-bol) (point-at-eol))))
(beg (point-at-bol 2))
end)
(forward-line 1)
(while (and (not (eobp))
(/= (current-indentation) lead)
(forward-line 1)))
(setf (alist-get heading alist nil nil #'equal)
(string-join
(delq
nil (list (alist-get heading alist nil nil #'equal)
(let ((end (point)))
(with-temp-buffer
(insert-buffer-substring buffer beg end)
(goto-char (point-min))
(indent-rigidly (point-min) (point-max) (- (current-indentation)))
(string-trim-right (buffer-string))))))
"\n\n"))))))))))
(provide 'doom-cli-meta)
;;; meta.el ends here

View file

@ -23,16 +23,15 @@
(noelpa-p ("-p" "--no-elpa") "Don't purge ELPA packages")
(norepos-p ("-r" "--no-repos") "Don't purge unused straight repos")
(noeln-p ("-e" "--no-eln") "Don't purge old ELN bytecode")
(noregraft-p ("-g" "--no-regraft") "Regraft git repos (ie. compact them)"))
(noregraft-p ("-g" "--no-regraft") "Don't regraft git repos (ie. compact them)"))
"Deletes orphaned packages & repos, and compacts them.
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.
all orphaned package repos and builds. Also regrafts and compacts package repos
to ensure they are as small as possible.
It is a good idea to occasionally run this doom purge -g to ensure your package
list remains lean."
It is a good idea to occasionally run this command to ensure your package list
remains lean."
:benchmark t
(require 'comp nil t)
(doom-initialize-core-packages)
@ -352,7 +351,8 @@ list remains lean."
(error
(signal 'doom-package-error (list package e)))))))
(progn
(when (featurep 'native-compile)
(when (and (featurep 'native-compile)
straight--native-comp-available)
(doom-packages--compile-site-files)
(doom-packages--wait-for-native-compile-jobs)
(doom-packages--write-missing-eln-errors))
@ -677,7 +677,7 @@ If ELPA-P, include packages installed with package.el (M-x package-install)."
(defvar doom-cli--straight-auto-options
'(("has diverged from"
. "^Reset [^ ]+ to branch")
. "^Reset [^ ]+ to ")
("but recipe specifies a URL of"
. "Delete remote \"[^\"]+\", re-create it with correct URL")
("has a merge conflict:"

2320
lisp/doom-cli-lib.el Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -151,20 +151,17 @@ If NOERROR, don't throw an error if PATH doesn't exist."
(signal (car e) (cdr e)))
(error
(setq path (locate-file path load-path (get-load-suffixes)))
(signal (cond ((not (and path (featurep 'doom)))
'error)
((file-in-directory-p path (expand-file-name "cli" doom-core-dir))
'doom-cli-error)
((file-in-directory-p path doom-core-dir)
'doom-core-error)
((file-in-directory-p path doom-user-dir)
'doom-user-error)
((file-in-directory-p path doom-profile-dir)
'doom-profile-error)
((file-in-directory-p path doom-modules-dir)
'doom-module-error)
('doom-error))
(list path e)))))
(if (not (and path (featurep 'doom)))
(signal (car e) (cdr e))
(cl-loop for (err . dir)
in `((doom-cli-error . ,(expand-file-name "cli" doom-core-dir))
(doom-core-error . ,doom-core-dir)
(doom-user-error . ,doom-user-dir)
(doom-profile-error . ,doom-profile-dir)
(doom-module-error . ,doom-modules-dir))
if (file-in-directory-p path dir)
do (signal err (list (file-relative-name path (expand-file-name "../" dir))
e)))))))
(defun doom-require (feature &optional filename noerror)
"Like `require', but handles and enhances Doom errors.

View file

@ -150,7 +150,8 @@
;;; Support for Doom-specific file extensions
(add-to-list 'auto-mode-alist '("/\\.doom\\(?:rc\\|project\\|module\\|profile\\)\\'" . emacs-lisp-mode))
(add-to-list 'auto-mode-alist '("/\\.doom\\(?:project\\|module\\|profile\\)\\'" . lisp-data-mode))
(add-to-list 'auto-mode-alist '("/\\.doomrc\\'" . emacs-lisp-mode))
;;

View file

@ -202,7 +202,7 @@
"Current version of Doom Emacs core.")
;; DEPRECATED: Remove these when the modules are moved out of core.
(defconst doom-modules-version "24.09.0-pre"
(defconst doom-modules-version "24.10.0-pre"
"Current version of Doom Emacs.")
(defvar doom-init-time nil
@ -384,8 +384,6 @@ users).")
(locate-file-internal "calc-loaddefs.el" load-path))
nil
(list (rassq 'jka-compr-handler old-value))))
;; Make sure the new value survives any current let-binding.
(set-default-toplevel-value 'file-name-handler-alist file-name-handler-alist)
;; Remember it so it can be reset where needed.
(put 'file-name-handler-alist 'initial-value old-value)
;; COMPAT: Eventually, Emacs will process any files passed to it via the
@ -502,10 +500,10 @@ users).")
;; PERF,UX: site-lisp files are often obnoxiously noisy (emitting output
;; that isn't useful to end-users, like load messages, deprecation
;; notices, and linter warnings. Displaying these in the minibuffer causes
;; unnecessary redraws at startup which can impact startup time
;; drastically and cause flashes of white. It also pollutes the logs. By
;; suppressing it here, I load it myself, later, in a more controlled way
;; notices, and linter warnings). Displaying these in the minibuffer
;; causes unnecessary redraws at startup which can impact startup time
;; drastically and cause flashes of white. It also pollutes the logs. I
;; suppress it here and load it myself, later, in a more controlled way
;; (see `startup--load-user-init-file@undo-hacks').
(put 'site-run-file 'initial-value site-run-file)
(setq site-run-file nil)

View file

@ -8,4 +8,6 @@
(package! flycheck-posframe :pin "19896b922c76a0f460bf3fe8d8ebc2f9ac9028d8")))
(when (modulep! +flymake)
(package! flymake-popon :recipe (:repo "https://codeberg.org/akib/emacs-flymake-popon")))
(package! flymake-popon
:recipe (:host github :repo "doomelpa/flymake-popon")
:pin "99ea813346f3edef7220d8f4faeed2ec69af6060"))

View file

@ -1,7 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; completion/company/packages.el
(package! company :pin "1a0fc12a9c3d25e28c22f319e7b097f435b1c27d")
(package! company :pin "e1d331a64ec39fe28c5be28cabf812e3eaab5b0f")
(package! company-dict :pin "cd7b8394f6014c57897f65d335d6b2bd65dab1f4")
(when (modulep! +childframe)
(package! company-box :pin "c4f2e243fba03c11e46b1600b124e036f2be7691"))

View file

@ -193,9 +193,13 @@ A few variables may be set to change behavior of this module:
- [[var:corfu-preview-current]] ::
Configures current candidate preview.
- [[var:+corfu-want-ret-to-confirm]] ::
Enables commiting with [[RET]] when the popup is visible. Default is ~t~, may be set to
~'minibuffer~ if you want to commit both the completion and the minibuffer when
active. When ~nil~, it is always passed-through.
Controls the behavior of [[kbd:][RET]] when the popup is visible - whether it confirms
the selected candidate, and whether [[kbd:][RET]] is passed through (ie. the normal
behavior of [[kbd:][RET]] is performed). The default value of ~t~ enables confirmation
and disables pass-through. Other variations are ~nil~ for pass-through and no
confirmation and ~both~ for confirmation followed by pass-through. Finally,
the value of ~minibuffer~ will both confirm and pass-through (like ~both~)
when in the minibuffer, and only confirm (like ~t~) otherwise.
- [[var:+corfu-buffer-scanning-size-limit]] ::
Sets the maximum buffer size to be scanned by ~cape-dabbrev~. Defaults to 1 MB.
Set this if you are having performance problems using the CAPF.

View file

@ -4,9 +4,9 @@
"Configure how the user expects RET to behave.
Possible values are:
- t (default): Insert candidate if one is selected, pass-through otherwise;
- `minibuffer': Insert candidate if one is selected, pass-through otherwise,
and immediatelly exit if in the minibuffer;
- nil: Pass-through without inserting.")
- nil: Pass-through without inserting;
- `both': Insert candidate if one is selected, then pass-through;
- `minibuffer': Behaves like `both` in the minibuffer and `t` otherwise.")
(defvar +corfu-buffer-scanning-size-limit (* 1 1024 1024) ; 1 MB
"Size limit for a buffer to be scanned by `cape-dabbrev'.")
@ -28,41 +28,31 @@ TAB/S-TAB.")
"If non-nil, prefer navigating org tables over cycling candidates with
TAB/S-TAB.")
(defvar +corfu-inhibit-auto-functions ()
"A list of predicate functions that take no arguments.
If any return non-nil, `corfu-auto' will not invoke as-you-type completion.")
;;
;;; Packages
(use-package! corfu
:hook (doom-first-input . global-corfu-mode)
:init
(add-hook! 'minibuffer-setup-hook
(defun +corfu-enable-in-minibuffer ()
"Enable Corfu in the minibuffer."
(when (pcase +corfu-want-minibuffer-completion
('aggressive
(not (or (bound-and-true-p mct--active)
(bound-and-true-p vertico--input)
(and (featurep 'auth-source)
(eq (current-local-map) read-passwd-map))
(and (featurep 'helm-core) (helm--alive-p))
(and (featurep 'ido) (ido-active))
(where-is-internal 'minibuffer-complete
(list (current-local-map)))
(memq #'ivy--queue-exhibit post-command-hook))))
('nil nil)
(_ (where-is-internal #'completion-at-point
(list (current-local-map)))))
(setq-local corfu-echo-delay nil)
(corfu-mode +1))))
:config
(setq corfu-auto t
corfu-auto-delay 0.24
corfu-auto-prefix 2
global-corfu-modes '((not erc-mode
global-corfu-modes
'((not erc-mode
circe-mode
help-mode
gud-mode
vterm-mode)
vterm-mode
;; Needed for `+corfu-want-minibuffer-completion' to be
;; respected. See #7977.
minibuffer-mode
minibuffer-inactive-mode)
t)
corfu-cycle t
corfu-preselect 'prompt
@ -80,6 +70,37 @@ TAB/S-TAB.")
(add-to-list 'corfu-continue-commands #'+corfu/smart-sep-toggle-escape)
(add-hook 'evil-insert-state-exit-hook #'corfu-quit)
(defun +corfu-enable-in-minibuffer-p ()
"Return non-nil if Corfu should be enabled in the minibuffer.
See `+corfu-want-minibuffer-completion'."
(pcase +corfu-want-minibuffer-completion
('nil nil)
('aggressive
(not (or (bound-and-true-p mct--active)
(bound-and-true-p vertico--input)
(and (featurep 'auth-source)
(eq (current-local-map) read-passwd-map))
(and (featurep 'helm-core) (helm--alive-p))
(and (featurep 'ido) (ido-active))
(where-is-internal 'minibuffer-complete
(list (current-local-map)))
(memq #'ivy--queue-exhibit post-command-hook))))
(_ (where-is-internal #'completion-at-point
(list (current-local-map))))))
(setq global-corfu-minibuffer #'+corfu-enable-in-minibuffer-p)
;; HACK: Augments Corfu to respect `+corfu-inhibit-auto-functions'.
(defadvice! +corfu--post-command-a (fn &rest args)
"Refresh Corfu after last command."
(let ((corfu-auto
(if corfu-auto
(not (run-hook-with-args-until-success '+corfu-inhibit-auto-functions)))))
(apply fn args)))
(when (modulep! :editor evil)
;; Modifying the buffer while in replace mode can be janky.
(add-to-list '+corfu-inhibit-auto-functions #'evil-replace-state-p))
;; HACK: If you want to update the visual hints after completing minibuffer
;; commands with Corfu and exiting, you have to do it manually.
(defadvice! +corfu--insert-before-exit-minibuffer-a ()

View file

@ -1,8 +1,8 @@
;; -*- no-byte-compile: t; -*-
;;; completion/corfu/packages.el
(package! corfu :pin "cdc3e13ad312f5f12b3f78f842fff0b398eb4473")
(package! cape :pin "f61da109a9e4491614938c300291060fd8855c1b")
(package! corfu :pin "921dd7c97ec41fe8ef81dd5f5a08b0f717586c86")
(package! cape :pin "9110956a5155d5e3c460160fa1b4dac59322c229")
(when (modulep! +icons)
(package! nerd-icons-corfu :pin "7077bb76fefc15aed967476406a19dc5c2500b3c"))
(when (and (not (modulep! :completion vertico))
@ -14,4 +14,4 @@
(when (modulep! :os tty)
(package! corfu-terminal :pin "501548c3d51f926c687e8cd838c5865ec45d03cc"))
(when (modulep! :editor snippets)
(package! yasnippet-capf :pin "744dedb7837d0c7e07817d36ec752a0cd813f55c"))
(package! yasnippet-capf :pin "4c2e33d70cd1d95cf1e08d134b058a6dd90a99c9"))

View file

@ -1,7 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; completion/helm/packages.el
(package! helm :pin "f8949afd9b44de4a8149874ef40e1250826d40bd")
(package! helm :pin "06e0cf01486a430b1f6792af78297837d3d77d97")
(package! helm-company :pin "4622b82353220ee6cc33468f710fa5b6b253b7f1")
(package! helm-c-yasnippet :pin "c5880e740da101fde7a995e94a7b16c330e57583")
(package! helm-descbinds :pin "ca03f02da4e54a1d0a2d5498b86e1639aa808d8c")

View file

@ -1,7 +1,7 @@
;; -*- no-byte-compile: t; -*-
;;; completion/ivy/packages.el
(package! swiper :pin "2a25a6fb5b081cb141c5eccac8ee58ab1feeb747")
(package! swiper :pin "8dc02d5b725f78d1f80904807b46f5406f129674")
(package! ivy)
(package! ivy-hydra)
(package! ivy-avy)
@ -13,7 +13,7 @@
(package! wgrep :pin "208b9d01cfffa71037527e3a324684b3ce45ddc4")
(if (modulep! +prescient)
(package! ivy-prescient :pin "0765418e4362099db8788fcb745ce9b7602aa001")
(package! ivy-prescient :pin "2b8a8b41228bddb2e11eb1c200e98a9edd04797c")
(when (modulep! +fuzzy)
(package! flx :pin "4b1346eb9a8a76ee9c9dede69738c63ad97ac5b6")))

View file

@ -1,24 +1,24 @@
;; -*- no-byte-compile: t; -*-
;;; completion/vertico/packages.el
(package! vertico :pin "ba650a7ab90d66686ba787937ac9e71f749c598e")
(package! vertico :pin "c682ef50e62237435e9fc287927ce4181b49be90")
(package! orderless :pin "53f5204ad3f541e11eb6eeb9b86584964b7a3678")
(package! orderless :pin "49d1fdfb80b55699a00b11bc916ad29c0447039b")
(package! consult :pin "fe4852280006e61be7f1374d021ee06155ce5a26")
(package! consult :pin "0c3f53916ea0db0c472c0a0c620a85cc1b00caf2")
(package! consult-dir :pin "15891383f34d43acc5bb82bda92239b1f54cf178")
(when (and (modulep! :checkers syntax)
(not (modulep! :checkers syntax +flymake)))
(package! consult-flycheck :pin "754f5497d827f7d58009256a21af614cc44378a3"))
(package! embark :pin "9c166c4b96a0b1e85401bcc6fb95ce021e7b5013")
(package! embark-consult :pin "9c166c4b96a0b1e85401bcc6fb95ce021e7b5013")
(package! consult-flycheck :pin "3b999ae983900c16c0b5b5c30b7eca640d386a76"))
(package! embark :pin "19a13e344e04bbf861eaa74491b23da52b398672")
(package! embark-consult :pin "19a13e344e04bbf861eaa74491b23da52b398672")
(package! marginalia :pin "da72da4622c7b38741e6968678028f7e0564816c")
(package! marginalia :pin "50a51c69f006ec8b3ba1c570555d279d4cff6d99")
(package! wgrep :pin "208b9d01cfffa71037527e3a324684b3ce45ddc4")
(when (modulep! +icons)
(package! nerd-icons-completion :pin "c2db8557a3c1a9588d111f8c8e91cae96ee85010"))
(package! nerd-icons-completion :pin "426a1d7c29a04ae8e6ae9b55b0559f11a1e8b420"))
(when (modulep! +childframe)
(package! vertico-posframe

View file

@ -1,26 +0,0 @@
;;; config/default/+emacs.el -*- lexical-binding: t; -*-
(require 'projectile) ; we need its keybinds immediately
;;
;;; Reasonable defaults
(setq shift-select-mode t)
(delete-selection-mode +1)
(use-package! expand-region
:commands (er/contract-region er/mark-symbol er/mark-word)
:config
(defadvice! doom--quit-expand-region-a (&rest _)
"Properly abort an expand-region region."
:before '(evil-escape doom/escape)
(when (memq last-command '(er/expand-region er/contract-region))
(er/contract-region 0))))
;;
;;; Keybinds
(when (modulep! +bindings)
(load! "+emacs-bindings"))

View file

@ -159,8 +159,9 @@
;;; :completion (in-buffer)
(map! (:when (modulep! :completion company)
(:unless (bound-and-true-p evil-disable-insert-state-bindings)
:i "C-@" (cmds! (not (minibufferp)) #'company-complete-common)
:i "C-SPC" (cmds! (not (minibufferp)) #'company-complete-common)
:i "C-SPC" (cmds! (not (minibufferp)) #'company-complete-common))
(:after company
(:map company-active-map
"C-w" nil ; don't interfere with `evil-delete-backward-word'
@ -189,15 +190,18 @@
(:when (modulep! :completion corfu)
(:after corfu
(:map corfu-mode-map
(:unless (bound-and-true-p evil-disable-insert-state-bindings)
:i "C-@" #'completion-at-point
:i "C-SPC" #'completion-at-point
:i "C-n" #'+corfu/dabbrev-or-next
:i "C-p" #'+corfu/dabbrev-or-last
:i "C-p" #'+corfu/dabbrev-or-last)
:n "C-SPC" (cmd! (call-interactively #'evil-insert-state)
(call-interactively #'completion-at-point))
:v "C-SPC" (cmd! (call-interactively #'evil-change)
(call-interactively #'completion-at-point)))
(:map corfu-map
:i "C-SPC" #'corfu-insert-separator
(:unless (bound-and-true-p evil-disable-insert-state-bindings)
:i "C-SPC" #'corfu-insert-separator)
"C-k" #'corfu-previous
"C-j" #'corfu-next
"C-u" (cmd! (let (corfu-cycle)
@ -506,8 +510,6 @@
:desc "Copy link to remote" "y" #'+vc/browse-at-remote-kill
:desc "Copy link to homepage" "Y" #'+vc/browse-at-remote-kill-homepage
:desc "Git time machine" "t" #'git-timemachine-toggle
(:when (modulep! :ui hydra)
:desc "SMerge" "m" #'+vc/smerge-hydra/body)
(:when (modulep! :ui vc-gutter)
:desc "Revert hunk at point" "r" #'+vc-gutter/revert-hunk
:desc "stage hunk at point" "s" #'+vc-gutter/stage-hunk

View file

@ -1,21 +0,0 @@
;;; config/default/+evil.el -*- lexical-binding: t; -*-
(defun +default-disable-delete-selection-mode-h ()
(delete-selection-mode -1))
(add-hook 'evil-insert-state-entry-hook #'delete-selection-mode)
(add-hook 'evil-insert-state-exit-hook #'+default-disable-delete-selection-mode-h)
;;
;;; Keybindings
;; This section is dedicated to "fixing" certain keys so that they behave
;; sensibly (and consistently with similar contexts).
;; Make SPC u SPC u [...] possible (#747)
(map! :map universal-argument-map
:prefix doom-leader-key "u" #'universal-argument-more
:prefix doom-leader-alt-key "u" #'universal-argument-more)
(when (modulep! +bindings)
(load! "+evil-bindings"))

View file

@ -466,28 +466,21 @@ Continues comments if executed from a commented line."
(let ((cmds-del
`(menu-item "Reset completion" corfu-reset
:filter ,(lambda (cmd)
(cond
((and (>= corfu--index 0)
(when (and (>= corfu--index 0)
(eq corfu-preview-current 'insert))
cmd)))))
cmd))))
(cmds-ret
`(menu-item "Insert completion DWIM" corfu-insert
:filter ,(lambda (cmd)
(cond
((null +corfu-want-ret-to-confirm)
(corfu-quit)
nil)
((eq +corfu-want-ret-to-confirm 'minibuffer)
(funcall-interactively cmd)
nil)
((and (or (not (minibufferp nil t))
(eq +corfu-want-ret-to-confirm t))
(>= corfu--index 0))
cmd)
((or (not (minibufferp nil t))
(eq +corfu-want-ret-to-confirm t))
nil)
(t cmd)))))
(pcase +corfu-want-ret-to-confirm
('nil (corfu-quit) nil)
('t (if (>= corfu--index 0) cmd))
('both (funcall-interactively cmd) nil)
('minibuffer
(if (minibufferp nil t)
(ignore (funcall-interactively cmd)) ; 'both' behavior
(if (>= corfu--index 0) cmd))) ; 't' behavior
(_ cmd)))))
(cmds-tab
`(menu-item "Select next candidate or expand/traverse snippet" corfu-next
:filter (lambda (cmd)
@ -572,6 +565,42 @@ Continues comments if executed from a commented line."
;;
;;; Bootstrap configs
(if (featurep 'evil)
(load! "+evil")
(load! "+emacs"))
(cond
((modulep! :editor evil)
(defun +default-disable-delete-selection-mode-h ()
(delete-selection-mode -1))
(add-hook 'evil-insert-state-entry-hook #'delete-selection-mode)
(add-hook 'evil-insert-state-exit-hook #'+default-disable-delete-selection-mode-h)
;; Make SPC u SPC u [...] possible (#747)
(map! :map universal-argument-map
:prefix doom-leader-key "u" #'universal-argument-more
:prefix doom-leader-alt-key "u" #'universal-argument-more)
(when (modulep! +bindings)
(load! "+evil-bindings")))
(t
(add-hook 'doom-first-buffer-hook #'delete-selection-mode)
(setq shift-select-mode t)
(use-package! drag-stuff
:defer t
:init
(map! "<M-up>" #'drag-stuff-up
"<M-down>" #'drag-stuff-down
"<M-left>" #'drag-stuff-left
"<M-right>" #'drag-stuff-right))
(use-package! expand-region
:commands (er/contract-region er/mark-symbol er/mark-word)
:config
(defadvice! doom--quit-expand-region-a (&rest _)
"Properly abort an expand-region region."
:before '(evil-escape doom/escape)
(when (memq last-command '(er/expand-region er/contract-region))
(er/contract-region 0))))
(when (modulep! +bindings)
(require 'projectile nil t) ; we need its keybinds immediately
(load! "+emacs-bindings"))))

View file

@ -2,8 +2,8 @@
;;; config/default/packages.el
(package! avy :pin "be612110cb116a38b8603df367942e2bb3d9bdbe")
(package! drag-stuff :pin "6d06d846cd37c052d79acd0f372c13006aa7e7c8")
(package! link-hint :pin "9153eafc776549376bb85d9ff555fef83aca8285")
(unless (modulep! :editor evil)
(package! drag-stuff :pin "6d06d846cd37c052d79acd0f372c13006aa7e7c8")
(package! expand-region :pin "e8f4e0fe9c9a80a6a26e2b438502aba9a799d580"))

View file

@ -41,10 +41,19 @@
(org-confirm-babel-evaluate nil)
;; Say a little more
(doom-print-message-level 'info))
(if-let (files (org-babel-tangle-file target dest))
(cond ((not (file-exists-p target))
(print! (warn "No org file at %s. Skipping...") (path target))
nil)
((with-temp-buffer
(insert-file-contents target)
(let ((case-fold-search t))
(not (re-search-forward "^ *#\\+begin_src e\\(?:macs-\\)?lisp" nil t))))
(print! (warn "No src blocks to tangle in %s. Skipping...") (path target))
nil)
((if-let (files (org-babel-tangle-file target dest))
(always (print! (success "Done tangling %d file(s)!" (length files))))
(print! (error "Failed to tangle any blocks from your config."))
nil))))))
nil))))))))
(defun +literate-tangle--sync ()
"Tangles `+literate-config-file' if it has changed."
@ -176,7 +185,7 @@ We assume any org file in `doom-user-dir' is connected to your literate
config, and should trigger a recompile if changed."
(and (file-in-directory-p
(buffer-file-name (buffer-base-buffer))
(file-name-directory +literate-config-file))
(file-name-directory (file-truename +literate-config-file)))
(+literate-tangle-h)))
;;; autoload.el ends here

View file

@ -3,10 +3,6 @@
#+created: October 13, 2021
#+since: 21.12.0
#+begin_quote
*This module is deprecated.* ~god-mode~ is EOL and no longer maintained.
#+end_quote
* Description :unfold:
Adds [[doom-package:god-mode]] support to Doom Emacs, allowing for entering commands without
modifier keys, similar to Vim's modality, separating command mode and insert

View file

@ -45,6 +45,38 @@
(set-evil-initial-state! 'vc-dir-mode 'emacs))
(use-package! smerge-mode
:defer t
:init
(add-hook! 'find-file-hook
(defun +vc-init-smerge-mode-h ()
(unless (bound-and-true-p smerge-mode)
(save-excursion
(goto-char (point-min))
(when (re-search-forward "^<<<<<<< " nil t)
(smerge-mode 1))))))
:config
(map! :map smerge-mode-map
:localleader
"n" #'smerge-next
"p" #'smerge-prev
"r" #'smerge-resolve
"a" #'smerge-keep-all
"b" #'smerge-keep-base
"o" #'smerge-keep-lower
"l" #'smerge-keep-lower
"m" #'smerge-keep-upper
"u" #'smerge-keep-upper
"E" #'smerge-ediff
"C" #'smerge-combine-with-next
"R" #'smerge-refine
"C-m" #'smerge-keep-current
(:prefix "="
"<" #'smerge-diff-base-upper
">" #'smerge-diff-base-lower
"=" #'smerge-diff-upper-lower)))
(after! git-timemachine
;; Sometimes I forget `git-timemachine' is enabled in a buffer, so instead of
;; showing revision details in the minibuffer, show them in

View file

@ -6,7 +6,7 @@
(package! smerge-mode :built-in t)
(package! browse-at-remote :pin "76aa27dfd469fcae75ed7031bb73830831aaccbf")
(package! git-commit :pin "2da34f1317c619ec2dfb9e0d969449261ca7f31f")
(package! git-commit :pin "0aa26864e3fc4e6949711a4821caf6819e7ab171")
(package! git-timemachine
;; The original lives on codeberg.org; which has uptime issues.
:recipe (:host github :repo "emacsmirror/git-timemachine")

149
modules/lang/org/cli.el Normal file
View file

@ -0,0 +1,149 @@
;;; lang/org/cli.el -*- lexical-binding: t; -*-
(defcli! () ()
"Commands to invoke Org's powerful capabilities."
:partial t)
(defcli! (tangle)
((all? ("-a" "--all") "Tangle all src blocks, unconditionally")
(print? ("-p" "--print") "Print the tangled results to stdout (implies -q/--quiet)")
(quiet? ("-q" "--quiet") "Don't log any status messages to stdout")
(lang ("-l" "--lang" lang))
&multiple
(tags ("-t" "--tag" "--and" "--or" tag) "Target blocks under headers with specific tags")
&args paths)
"Tangle an org file in `PATHS'.
`PATHS' can be files or folders (which are searched for org files,
recursively).
EXAMPLES:
%p %c some-file.org
%p %c literate/config/
%p %c `-p' `-l' sh scripts.org > script.sh
%p %c `-p' `-l' python `-t' tagA `-t' tagB file.org | python"
(unless paths
(user-error "No paths to org files provided."))
;; Prefer module's version of org, if available.
;; TODO: Handle this upstream.
(add-to-list
'load-path
(cl-find-if #'file-exists-p
(list (doom-path straight-base-dir "straight" straight-build-dir "org")
(doom-path straight-base-dir "straight" "repos" "org"))))
(require 'org)
(require 'ox)
(require 'ob-tangle)
(letf! ((defun org-babel-tangle-collect-blocks (&optional language tangle-file)
"Ignore blocks that are in trees with the :notangle: tag."
(let ((counter 0) last-heading-pos blocks)
(org-babel-map-src-blocks (buffer-file-name)
(let ((current-heading-pos
(if (org-element--cache-active-p)
(or (org-element-property :begin (org-element-lineage (org-element-at-point) '(headline) t)) 1)
(org-with-wide-buffer
(org-with-limited-levels (outline-previous-heading))))))
(if (eq last-heading-pos current-heading-pos) (cl-incf counter)
(setq counter 1)
(setq last-heading-pos current-heading-pos)))
(unless (or (org-in-commented-heading-p)
(org-in-archived-heading-p))
(let* ((tags (org-get-tags-at))
(info (org-babel-get-src-block-info 'no-eval))
(src-lang (nth 0 info))
(src-tfile (cdr (assq :tangle (nth 2 info)))))
(cond ((member "notangle" tags))
((let* ((tags (seq-group-by (fn! (equal (car %) "--or")) tags))
(or-tags (mapcar #'cdr (cdr (assq t tags))))
(and-tags (mapcar #'cdr (cdr (assq nil tags))))
(all-tags (append or-tags and-tags)))
(and (or or-tags and-tags)
(or (not and-tags)
(let ((a (cl-intersection and-tags all-tags :test #'string=))
(b and-tags))
(not (or (cl-set-difference a b :test #'equal)
(cl-set-difference b a :test #'equal)))))
(or (not or-tags)
(cl-intersection or-tags all-tags :test #'string=))
t)))
((or (not src-tfile)
(string= src-tfile "no") ; tangle blocks by default
(if tangle-file (not (equal tangle-file src-tfile)))
(if language (not (string= language src-lang)))))
;; Add the spec for this block to blocks under its language.
((let* ((block (org-babel-tangle-single-block counter))
(src-tfile (cdr (assq :tangle (nth 4 block))))
(file-name (org-babel-effective-tangled-filename
(nth 1 block) src-lang src-tfile))
(by-fn (assoc file-name blocks)))
(if by-fn
(setcdr by-fn (cons (cons src-lang block) (cdr by-fn)))
(push (cons file-name (list (cons src-lang block)))
blocks))))))))
;; Ensure blocks are in the correct order.
(mapcar (lambda (b) (cons (car b) (nreverse (cdr b))))
(nreverse blocks))))
(success nil))
(if print? (setq quiet? t))
(when (and all? (not quiet?))
(print! (warn "Tangling all blocks, unconditionally...")))
(dolist (file (cl-loop for path in (mapcar #'expand-file-name paths)
if (file-directory-p path)
append (doom-files-in path :type 'files :match "\\.org\\'")
else if (file-exists-p path)
collect path
else do (print! (error "Can't find %s. Skipping..." (path path))))
(or success (exit! 1)))
(unless quiet?
(print! (start "Reading %s...") (path file)))
(let ((backup (make-temp-file (file-name-base file) nil ".backup.org"))
;; Prevent slow initialization from interfering
(org-startup-indented nil)
(org-startup-folded nil)
(vc-handled-backends nil)
;; Prevent unwanted entries in recentf, or formatters, or
;; anything that could be on these hooks, really. Nothing else
;; should be touching these files (particularly in interactive
;; sessions).
(write-file-functions nil)
(before-save-hook nil)
(after-save-hook nil)
;; Prevent infinite recursion due to recompile-on-save hooks
;; later, and speed up `org-mode' init.
(org-mode-hook nil)
(org-inhibit-startup t)
;; Allow evaluation of src blocks at tangle-time (would abort
;; them otherwise). This is a security hazard, but Doom will
;; trust that you know what you're doing!
(org-confirm-babel-evaluate nil)
;; Tangle everything by default.
(org-babel-default-header-args (copy-sequence org-babel-default-header-args)))
(when all?
(setf (alist-get :tangle org-babel-default-header-args) "yes"))
(unwind-protect
(progn
;; Do the ol' switcheroo because `org-babel-tangle' writes changes
;; to the current file, which would be imposing on the user.
(copy-file file backup t)
(with-current-buffer (delay-mode-hooks (find-file-noselect file))
;; Tangling doesn't expand #+INCLUDE directives, so we do it
;; ourselves, since includes are so useful for literate configs!
(org-export-expand-include-keyword)
(if-let ((results (reverse (org-babel-tangle nil nil lang))))
(dolist (file results)
(if (not quiet?)
(print-group!
(setq success t)
(print! (success "Tangled to %s") (path file)))
(when print?
(print! "%s" (doom-file-read file))
(delete-file file))))
(unless quiet?
(print-group!
(print! (warn "Nothing to tangle from %s") (path file)))))))
(ignore-errors (copy-file backup file t))
(ignore-errors (delete-file backup)))))))

View file

@ -787,30 +787,26 @@ via an indirect buffer."
(defvar recentf-exclude)
(defadvice! +org--optimize-backgrounded-agenda-buffers-a (fn file)
"Disable a lot of org-mode's startup processes for temporary agenda buffers.
"Disable `org-mode's startup processes for temporary agenda buffers.
This includes preventing them from polluting recentf.
However, if the user tries to visit one of these buffers they'll see a
gimped, half-broken org buffer. To avoid that, install a hook to restart
`org-mode' when they're switched to so they can grow up to be fully-fledged
org-mode buffers."
Prevents recentf pollution as well. However, if the user tries to visit one of
these buffers they'll see a gimped, half-broken org buffer, so to avoid that,
install a hook to restart `org-mode' when they're switched to so they can grow
up to be fully-fledged org-mode buffers."
:around #'org-get-agenda-file-buffer
(if-let (buf (org-find-base-buffer-visiting file))
buf
(let ((recentf-exclude (list (lambda (_file) t)))
(let ((recentf-exclude '(always))
(doom-inhibit-large-file-detection t)
org-startup-indented
org-startup-folded
(doom-inhibit-local-var-hooks t)
(org-inhibit-startup t)
vc-handled-backends
org-mode-hook
enable-local-variables
find-file-hook)
(let ((buf (funcall fn file)))
(when buf
(when-let ((buf (delay-mode-hooks (funcall fn file))))
(with-current-buffer buf
(add-hook 'doom-switch-buffer-hook #'+org--restart-mode-h
nil 'local)))
nil 'local))
buf))))
(defadvice! +org--fix-inconsistent-uuidgen-case-a (uuid)
@ -1219,8 +1215,8 @@ between the two."
:n CSup #'org-shiftup
:n CSdown #'org-shiftdown
;; more intuitive RET keybinds
:n [return] #'+org/dwim-at-point
:n "RET" #'+org/dwim-at-point
:m [return] #'+org/dwim-at-point
:m "RET" #'+org/dwim-at-point
:i [return] #'+org/return
:i "RET" #'+org/return
:i [S-return] #'+org/shift-return

View file

@ -68,9 +68,9 @@
(when (modulep! :tools pdf)
(package! org-pdftools :pin "4e420233a153a9c4ab3d1a7e1d7d3211c836f0ac"))
(when (modulep! :tools magit)
(package! orgit :pin "29a0f37e5cc74b2979f3f256913460624deaf152")
(package! orgit :pin "59d21fdb21f84238c3172d37fdd2446b753e98dc")
(when (modulep! :tools magit +forge)
(package! orgit-forge :pin "a989b2b54d116bda9d0396a9773b3e11b9f54e05")))
(package! orgit-forge :pin "2718a6aaf0f64cb52c64c419053fbc80eb358c8d")))
(when (modulep! +brain)
(package! org-brain :pin "2bad7732aae1a3051e2a14de2e30f970bbe43c25"))
(when (modulep! +dragndrop)

View file

@ -259,16 +259,14 @@
(use-package! conda
:when (modulep! +conda)
:after python
:config
;; The location of your anaconda home will be guessed from a list of common
;; possibilities, starting with `conda-anaconda-home''s default value (which
;; will consult a ANACONDA_HOME envvar, if it exists).
;;
;; 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
(or (cl-loop for dir in (list conda-anaconda-home
"~/.anaconda"
:preface
;; HACK: `conda-anaconda-home's initialization can throw an error if none of
;; `conda-home-candidates' exist, so unset it early.
;; REVIEW: Fix this upstream.
(setq conda-anaconda-home (getenv "ANACONDA_HOME")
conda-home-candidates
(list "~/.anaconda"
"~/.anaconda3"
"~/.miniconda"
"~/.miniconda3"
"~/.miniforge3"
@ -280,7 +278,16 @@
"/usr/local/anaconda3"
"/usr/local/miniconda3"
"/usr/local/Caskroom/miniconda/base"
"~/.conda")
"~/.conda"))
:config
;; The location of your anaconda home will be guessed from a list of common
;; possibilities, starting with `conda-anaconda-home''s default value (which
;; will consult a ANACONDA_HOME envvar, if it exists).
;;
;; 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
(or (cl-loop for dir in (cons conda-anaconda-home conda-home-candidates)
if (file-directory-p dir)
return (setq conda-anaconda-home (expand-file-name dir)
conda-env-home-directory (expand-file-name dir)))

View file

@ -4,9 +4,9 @@
;; NOTE: Always bump magit and forge to HEAD~1, not HEAD, because the latest
;; commit on their melpa branches are auto-generated and moved to HEAD every
;; time there's a commit to its main branch.
(package! magit :pin "2da34f1317c619ec2dfb9e0d969449261ca7f31f")
(package! magit :pin "0aa26864e3fc4e6949711a4821caf6819e7ab171")
(when (modulep! +forge)
(package! forge :pin "30f181f785522f2debf60945d6b589a65bc415f6")
(package! forge :pin "35cc600d62a01d50699a529b0caa7d40e642d62a")
(package! code-review
:recipe (:host github
:repo "doomelpa/code-review"

View file

@ -63,11 +63,11 @@ font.")
(defvar +ligatures-prog-mode-list nil
"A list of ligatures to enable in all `prog-mode' buffers.")
(make-obsolete-variable '+ligatures-prog-mode-list "Use `+ligatures-alist' instead" "3.0.0")
(make-obsolete-variable '+ligatures-prog-mode-list "Use `+ligatures-alist' instead" "24.09.0")
(defvar +ligatures-all-modes-list nil
"A list of ligatures to enable in all buffers.")
(make-obsolete-variable '+ligatures-all-modes-list "Use `+ligatures-alist' instead" "3.0.0")
(make-obsolete-variable '+ligatures-all-modes-list "Use `+ligatures-alist' instead" "24.09.0")
(defvar +ligatures-extra-alist '((t))
"A map of major modes to symbol lists (for `prettify-symbols-alist').")

View file

@ -1,11 +1,5 @@
;;; ui/tabs/config.el -*- lexical-binding: t; -*-
(defcustom +tabs-buffer-update-groups-delay 0.1
"Minimum wait time (in seconds) before tab groups are recalculated."
:type 'float
:group 'doom)
;;
;;; Packages