mirror of
https://gitlab.com/dwt1/dotfiles.git
synced 2026-04-23 03:20:26 +10:00
Updating Doom Emacs.
This commit is contained in:
@@ -36,7 +36,7 @@ it if it doesn't exist).")
|
||||
|
||||
|
||||
;;
|
||||
;; Functions
|
||||
;;; Functions
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-buffer-frame-predicate (buf)
|
||||
@@ -139,6 +139,8 @@ If BUFFER-OR-NAME is omitted or nil, the current buffer is tested."
|
||||
(stringp buffer-or-name)
|
||||
(signal 'wrong-type-argument (list '(bufferp stringp) buffer-or-name)))
|
||||
(when-let (buf (get-buffer buffer-or-name))
|
||||
(when-let (basebuf (buffer-base-buffer buf))
|
||||
(setq buf basebuf))
|
||||
(and (buffer-live-p buf)
|
||||
(not (doom-temp-buffer-p buf))
|
||||
(or (buffer-local-value 'doom-real-buffer-p buf)
|
||||
@@ -195,7 +197,9 @@ If DERIVED-P, test with `derived-mode-p', otherwise use `eq'."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-set-buffer-real (buffer flag)
|
||||
"Forcibly mark BUFFER as FLAG (non-nil = real)."
|
||||
"Forcibly mark BUFFER as FLAG (non-nil = real).
|
||||
|
||||
See `doom-real-buffer-p' for an explanation for real buffers."
|
||||
(with-current-buffer buffer
|
||||
(setq doom-real-buffer-p flag)))
|
||||
|
||||
@@ -251,7 +255,9 @@ regex PATTERN. Returns the number of killed buffers."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-mark-buffer-as-real-h ()
|
||||
"Hook function that marks the current buffer as real."
|
||||
"Hook function that marks the current buffer as real.
|
||||
|
||||
See `doom-real-buffer-p' for an explanation for real buffers."
|
||||
(doom-set-buffer-real (current-buffer) t))
|
||||
|
||||
|
||||
@@ -272,6 +278,12 @@ If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
|
||||
(set-buffer-modified-p nil)))
|
||||
(doom-kill-buffer-fixup-windows buffer))
|
||||
|
||||
|
||||
(defun doom--message-or-count (interactive message count)
|
||||
(if interactive
|
||||
(message message count)
|
||||
count))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-all-buffers (&optional buffer-list interactive)
|
||||
"Kill all buffers and closes their windows.
|
||||
@@ -286,14 +298,14 @@ belong to the current project."
|
||||
(if (null buffer-list)
|
||||
(message "No buffers to kill")
|
||||
(save-some-buffers)
|
||||
(delete-other-windows)
|
||||
(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)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))))
|
||||
(mapc #'kill-buffer buffer-list)
|
||||
(doom--message-or-count
|
||||
interactive "Killed %d buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-other-buffers (&optional buffer-list interactive)
|
||||
@@ -308,10 +320,10 @@ project."
|
||||
(doom-buffer-list)))
|
||||
t))
|
||||
(mapc #'doom-kill-buffer-and-windows buffer-list)
|
||||
(when interactive
|
||||
(message "Killed %s buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list))))))
|
||||
(doom--message-or-count
|
||||
interactive "Killed %d other buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-matching-buffers (pattern &optional buffer-list interactive)
|
||||
@@ -341,10 +353,10 @@ current project."
|
||||
(if current-prefix-arg (doom-project-buffer-list)))
|
||||
t))
|
||||
(mapc #'kill-buffer buffer-list)
|
||||
(when interactive
|
||||
(message "Killed %s buried buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list))))))
|
||||
(doom--message-or-count
|
||||
interactive "Killed %d buried buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/kill-project-buffers (project &optional interactive)
|
||||
@@ -362,9 +374,9 @@ current project."
|
||||
nil)
|
||||
t))
|
||||
(when project
|
||||
(let ((buffers (doom-project-buffer-list project)))
|
||||
(doom-kill-buffers-fixup-windows buffers)
|
||||
(when interactive
|
||||
(message "Killed %d buffer(s)"
|
||||
(- (length buffers)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffers))))))))
|
||||
(let ((buffer-list (doom-project-buffer-list project)))
|
||||
(doom-kill-buffers-fixup-windows buffer-list)
|
||||
(doom--message-or-count
|
||||
interactive "Killed %d project buffers"
|
||||
(- (length buffer-list)
|
||||
(length (cl-remove-if-not #'buffer-live-p buffer-list)))))))
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
;;; core/autoload/cache.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; This little library thinly wraps around persistent-soft (which is a pcache
|
||||
;; wrapper, how about that). It has three purposes:
|
||||
;;
|
||||
;; + To encapsulate the cache backend (persistent-soft/pcache in this case), in
|
||||
;; case it needs to change.
|
||||
;; + To provide `doom-cache-persist': a mechanism for easily persisting
|
||||
;; variables across Emacs sessions.
|
||||
;; + To lazy-load persistent-soft until it is really needed.
|
||||
;;
|
||||
;; Like persistent-soft, caches assume a 2-tier structure, where all caches are
|
||||
;; namespaced by location.
|
||||
|
||||
(defvar doom-cache-alists '(t)
|
||||
"An alist of alists, containing lists of variables for the doom cache library
|
||||
to persist across Emacs sessions.")
|
||||
|
||||
(defvar doom-cache-location 'doom
|
||||
"The default location for cache files. This symbol is translated into a file
|
||||
name under `pcache-directory' (by default a subdirectory under
|
||||
`doom-cache-dir'). One file may contain multiple cache entries.")
|
||||
|
||||
(defun doom-save-persistent-cache-h ()
|
||||
"Hook to run when an Emacs session is killed. Saves all persisted variables
|
||||
listed in `doom-cache-alists' to files."
|
||||
(dolist (alist (butlast doom-cache-alists 1))
|
||||
(cl-loop with key = (car alist)
|
||||
for var in (cdr alist)
|
||||
if (symbol-value var)
|
||||
do (doom-cache-set var it nil key))))
|
||||
(add-hook 'kill-emacs-hook #'doom-save-persistent-cache-h)
|
||||
|
||||
|
||||
;;
|
||||
;; Library
|
||||
|
||||
;;;###autoload
|
||||
(defmacro with-cache! (location &rest body)
|
||||
"Runs BODY with a different default `doom-cache-location'."
|
||||
(declare (indent defun))
|
||||
`(let ((doom-cache-location ',location))
|
||||
,@body))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-persist (location variables)
|
||||
"Persist VARIABLES (list of symbols) in LOCATION (symbol).
|
||||
|
||||
This populates these variables with cached values, if one exists, and saves them
|
||||
to file when Emacs quits.
|
||||
|
||||
Warning: this is incompatible with buffer-local variables."
|
||||
(dolist (var variables)
|
||||
(when (doom-cache-exists var location)
|
||||
(set var (doom-cache-get var location))))
|
||||
(setf (alist-get location doom-cache-alists)
|
||||
(append variables (cdr (assq location doom-cache-alists)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-desist (location &optional variables)
|
||||
"Unregisters VARIABLES (list of symbols) in LOCATION (symbol) from
|
||||
`doom-cache-alists', thus preventing them from being saved between sessions.
|
||||
Does not affect the actual variables themselves or their values."
|
||||
(if variables
|
||||
(setf (alist-get location doom-cache-alists)
|
||||
(cl-set-difference (cdr (assq location doom-cache-alists))
|
||||
variables))
|
||||
(delq (assq location doom-cache-alists)
|
||||
doom-cache-alists)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-get (key &optional location)
|
||||
"Retrieve KEY from LOCATION (defaults to `doom-cache-location'), if it exists
|
||||
and hasn't expired."
|
||||
(persistent-soft-fetch
|
||||
key (symbol-name (or location doom-cache-location))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-set (key value &optional ttl location)
|
||||
"Set KEY to VALUE in the cache. TTL is the time (in seconds) until this cache
|
||||
entry expires. LOCATION is the super-key to store this cache item under; the
|
||||
default is `doom-cache-location'. "
|
||||
(persistent-soft-store
|
||||
key value
|
||||
(symbol-name (or location doom-cache-location)) ttl))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-exists (key &optional location)
|
||||
"Returns t if KEY exists at LOCATION (defaults to `doom-cache-location')."
|
||||
(persistent-soft-exists-p key (or location doom-cache-location)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cache-clear (&optional location)
|
||||
"Clear a cache LOCATION (defaults to `doom-cache-location')."
|
||||
(persistent-soft-flush (or location doom-cache-location)))
|
||||
@@ -1,45 +0,0 @@
|
||||
;;; core/autoload/cli.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-call-process (command &rest args)
|
||||
"Execute COMMAND with ARGS synchronously.
|
||||
|
||||
Returns (STATUS . OUTPUT) when it is done, where STATUS is the returned error
|
||||
code of the process and OUTPUT is its stdout output."
|
||||
(with-temp-buffer
|
||||
(cons (or (apply #'call-process command nil t nil args)
|
||||
-1)
|
||||
(string-trim (buffer-string)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-exec-process (command &rest args)
|
||||
"Execute COMMAND with ARGS synchronously.
|
||||
|
||||
Unlike `doom-call-process', this pipes output to `standard-output' on the fly to
|
||||
simulate 'exec' in the shell, so batch scripts could run external programs
|
||||
synchronously without sacrificing their output.
|
||||
|
||||
Warning: freezes indefinitely on any stdin prompt."
|
||||
;; FIXME Is there any way to handle prompts?
|
||||
(with-temp-buffer
|
||||
(cons (let ((process
|
||||
(make-process :name "doom-sh"
|
||||
:buffer (current-buffer)
|
||||
:command (cons command args)
|
||||
:connection-type 'pipe))
|
||||
done-p)
|
||||
(set-process-filter
|
||||
process (lambda (_process output)
|
||||
(princ output (current-buffer))
|
||||
(princ output)))
|
||||
(set-process-sentinel
|
||||
process (lambda (process _event)
|
||||
(when (memq (process-status process) '(exit stop))
|
||||
(setq done-p t))))
|
||||
(while (not done-p)
|
||||
(sit-for 0.1))
|
||||
(process-exit-status process))
|
||||
(string-trim (buffer-string)))))
|
||||
@@ -26,8 +26,9 @@
|
||||
(doom-project-find-file doom-private-dir))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/goto-doomblock ()
|
||||
"Open your private init.el and go to your `doom!' block."
|
||||
(defun doom/goto-private-init-file ()
|
||||
"Open your private init.el file.
|
||||
And jumps to your `doom!' block."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "init.el" doom-private-dir))
|
||||
(goto-char
|
||||
@@ -37,13 +38,13 @@
|
||||
(point))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/goto-config-file ()
|
||||
(defun doom/goto-private-config-file ()
|
||||
"Open your private config.el file."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "config.el" doom-private-dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/goto-packages-file ()
|
||||
(defun doom/goto-private-packages-file ()
|
||||
"Open your private packages.el file."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "packages.el" doom-private-dir)))
|
||||
@@ -52,42 +53,48 @@
|
||||
;;
|
||||
;;; Managements
|
||||
|
||||
(cl-defmacro doom--compile (command &key on-success on-failure)
|
||||
(declare (indent defun))
|
||||
`(with-current-buffer (compile ,command)
|
||||
(add-hook
|
||||
'compilation-finish-functions
|
||||
(lambda (_buf status)
|
||||
(if (equal status "finished\n")
|
||||
,on-success
|
||||
,on-failure))
|
||||
nil 'local)))
|
||||
(defmacro doom--if-compile (command on-success &optional on-failure)
|
||||
(declare (indent 2))
|
||||
(let ((windowsym (make-symbol "doom-sync-window")))
|
||||
`(with-current-buffer (compile ,command t)
|
||||
(let ((,windowsym (get-buffer-window (current-buffer))))
|
||||
(select-window ,windowsym)
|
||||
(add-hook
|
||||
'compilation-finish-functions
|
||||
(lambda (_buf status)
|
||||
(if (equal status "finished\n")
|
||||
(progn
|
||||
(delete-window ,windowsym)
|
||||
,on-success)
|
||||
,on-failure))
|
||||
nil 'local)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload ()
|
||||
"Reloads your private config.
|
||||
|
||||
This is experimental! It will try to do as `bin/doom refresh' does, but from
|
||||
within this Emacs session. i.e. it reload autoloads files (if necessary),
|
||||
reloads your package list, and lastly, reloads your private config.el.
|
||||
This is experimental! It will try to do as `bin/doom sync' does, but from within
|
||||
this Emacs session. i.e. it reload autoloads files (if necessary), reloads your
|
||||
package list, and lastly, reloads your private config.el.
|
||||
|
||||
Runs `doom-reload-hook' afterwards."
|
||||
(interactive)
|
||||
(require 'core-cli)
|
||||
(when (and IS-WINDOWS (file-exists-p doom-env-file))
|
||||
(warn "Can't regenerate envvar file from within Emacs. Run 'doom env' from the console"))
|
||||
(doom--compile (format "%s refresh -e" doom-bin)
|
||||
:on-success
|
||||
(let ((doom-reloading-p t))
|
||||
(doom-initialize 'force)
|
||||
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
|
||||
(general-auto-unbind-keys)
|
||||
(unwind-protect
|
||||
(doom-initialize-modules 'force)
|
||||
(general-auto-unbind-keys t)))
|
||||
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook)
|
||||
(print! (success "Config successfully reloaded!")))
|
||||
:on-failure
|
||||
(message "Can't regenerate envvar file from within Emacs. Run 'doom env' from the console"))
|
||||
;; In case doom/reload is run before incrementally loaded packages are loaded,
|
||||
;; which could cause odd load order issues.
|
||||
(mapc #'require (cdr doom-incremental-packages))
|
||||
(doom--if-compile (format "%s sync -e" doom-bin)
|
||||
(let ((doom-reloading-p t))
|
||||
(doom-initialize 'force)
|
||||
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
|
||||
(general-auto-unbind-keys)
|
||||
(unwind-protect
|
||||
(doom-initialize-modules 'force)
|
||||
(general-auto-unbind-keys t)))
|
||||
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook)
|
||||
(message "Config successfully reloaded!"))
|
||||
(user-error "Failed to reload your config")))
|
||||
|
||||
;;;###autoload
|
||||
@@ -98,13 +105,13 @@ This is much faster and safer than `doom/reload', but not as comprehensive. This
|
||||
reloads your package and module visibility, but does not install new packages or
|
||||
remove orphaned ones. It also doesn't reload your private config.
|
||||
|
||||
It is useful to only pull in changes performed by 'doom refresh' on the command
|
||||
It is useful to only pull in changes performed by 'doom sync' on the command
|
||||
line."
|
||||
(interactive)
|
||||
(require 'core-cli)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)
|
||||
(doom-cli-reload-autoloads nil 'force))
|
||||
(doom-autoloads-reload))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-env (&optional arg)
|
||||
@@ -118,25 +125,22 @@ imported into Emacs."
|
||||
(interactive "P")
|
||||
(when IS-WINDOWS
|
||||
(user-error "Cannot reload envvar file from within Emacs on Windows, run it from cmd.exe"))
|
||||
(doom--compile
|
||||
(format "%s -ic '%s env%s'"
|
||||
(string-trim
|
||||
(shell-command-to-string
|
||||
(format "getent passwd %S | cut -d: -f7"
|
||||
(user-login-name))))
|
||||
doom-bin (if arg " -c" ""))
|
||||
:on-success
|
||||
(let ((doom-reloading-p t))
|
||||
(unless arg
|
||||
(doom-load-envvars-file doom-env-file)))
|
||||
:on-failure
|
||||
(doom--if-compile
|
||||
(format "%s -ic '%s env%s'"
|
||||
(string-trim
|
||||
(shell-command-to-string
|
||||
(format "getent passwd %S | cut -d: -f7"
|
||||
(user-login-name))))
|
||||
doom-bin (if arg " -c" ""))
|
||||
(let ((doom-reloading-p t))
|
||||
(unless arg
|
||||
(doom-load-envvars-file doom-env-file)))
|
||||
(error "Failed to generate env file")))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/upgrade ()
|
||||
"Run 'doom upgrade' then prompt to restart Emacs."
|
||||
(interactive)
|
||||
(doom--compile (format "%s upgrade" doom-bin)
|
||||
:on-success
|
||||
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect.\n\nRestart Emacs?")
|
||||
(doom/restart-and-restore))))
|
||||
(doom--if-compile (format "%s -y upgrade" doom-bin)
|
||||
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect.\n\nRestart Emacs?")
|
||||
(doom/restart-and-restore))))
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
;;; core/autoload/debug.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;;; Doom's debug mode
|
||||
|
||||
;;;###autoload
|
||||
(defvar doom-debug-variables
|
||||
'(doom-debug-p
|
||||
init-file-debug
|
||||
debug-on-error
|
||||
garbage-collection-messages
|
||||
use-package-verbose
|
||||
jka-compr-verbose
|
||||
lsp-log-io
|
||||
gcmh-verbose
|
||||
magit-refresh-verbose
|
||||
url-debug)
|
||||
"A list of variable to toggle on `doom-debug-mode'.")
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode doom-debug-mode
|
||||
"Toggle `debug-on-error' and `doom-debug-p' for verbose logging."
|
||||
:init-value doom-debug-p
|
||||
:global t
|
||||
(let ((value
|
||||
(cond ((eq arg 'toggle) (not doom-debug-mode))
|
||||
((> (prefix-numeric-value arg) 0)))))
|
||||
(mapc (doom-rpartial #'set value) doom-debug-variables)
|
||||
(message "Debug mode %s" (if value "on" "off"))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-run-all-startup-hooks-h ()
|
||||
"Run all startup Emacs hooks. Meant to be executed after starting Emacs with
|
||||
@@ -17,36 +49,44 @@
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defun doom-template-insert (template)
|
||||
"TODO"
|
||||
(let ((file (expand-file-name (format "templates/%s" template) doom-core-dir)))
|
||||
(when (file-exists-p file)
|
||||
(insert-file-contents file))))
|
||||
(defsubst doom--collect-forms-in (file form)
|
||||
(when (file-readable-p file)
|
||||
(let (forms)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(let (emacs-lisp-mode) (emacs-lisp-mode))
|
||||
(while (re-search-forward (format "(%s " (regexp-quote form)) nil t)
|
||||
(let ((ppss (syntax-ppss)))
|
||||
(unless (or (nth 4 ppss)
|
||||
(nth 3 ppss))
|
||||
(save-excursion
|
||||
(goto-char (match-beginning 0))
|
||||
(push (sexp-at-point) forms)))))
|
||||
(nreverse forms)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-info ()
|
||||
"Returns diagnostic information about the current Emacs session in markdown,
|
||||
ready to be pasted in a bug report on github."
|
||||
(require 'vc-git)
|
||||
(require 'core-packages)
|
||||
(let ((default-directory doom-emacs-dir)
|
||||
(doom-modules (doom-modules)))
|
||||
(cl-letf
|
||||
(((symbol-function 'sh)
|
||||
(lambda (&rest args)
|
||||
(cdr (apply #'doom-call-process args)))))
|
||||
(doom-modules (doom-module-list)))
|
||||
(letf! (defun sh (&rest args) (cdr (apply #'doom-call-process args)))
|
||||
`((emacs
|
||||
(version . ,emacs-version)
|
||||
(features ,@system-configuration-features)
|
||||
(build . ,(format-time-string "%b %d, %Y" emacs-build-time))
|
||||
(buildopts ,system-configuration-options)
|
||||
(windowsys . ,(if noninteractive 'batch window-system))
|
||||
(windowsys . ,(if doom-interactive-p window-system 'batch))
|
||||
(daemonp . ,(cond ((daemonp) 'daemon)
|
||||
((and (require 'server)
|
||||
(server-running-p))
|
||||
'server-running))))
|
||||
(doom
|
||||
(version . ,doom-version)
|
||||
(build . ,(sh "git" "log" "-1" "--format=%D %h %ci")))
|
||||
(build . ,(sh "git" "log" "-1" "--format=%D %h %ci"))
|
||||
(dir . ,(abbreviate-file-name (file-truename doom-private-dir))))
|
||||
(system
|
||||
(type . ,system-type)
|
||||
(config . ,system-configuration)
|
||||
@@ -79,14 +119,19 @@ ready to be pasted in a bug report on github."
|
||||
'("n/a")))
|
||||
(packages
|
||||
,@(or (condition-case e
|
||||
(cl-loop for (name . plist) in (doom-package-list)
|
||||
if (cl-find :private (plist-get plist :modules)
|
||||
:key #'car)
|
||||
collect
|
||||
(if-let (splist (doom-plist-delete (copy-sequence plist)
|
||||
:modules))
|
||||
(prin1-to-string (cons name splist))
|
||||
name))
|
||||
(mapcar
|
||||
#'cdr (doom--collect-forms-in
|
||||
(doom-path doom-private-dir "packages.el")
|
||||
"package!"))
|
||||
(error (format "<%S>" e)))
|
||||
'("n/a")))
|
||||
(unpin
|
||||
,@(or (condition-case e
|
||||
(mapcan #'identity
|
||||
(mapcar
|
||||
#'cdr (doom--collect-forms-in
|
||||
(doom-path doom-private-dir "packages.el")
|
||||
"unpin!")))
|
||||
(error (format "<%S>" e)))
|
||||
'("n/a")))
|
||||
(elpa
|
||||
@@ -109,13 +154,13 @@ branch and commit."
|
||||
(interactive)
|
||||
(require 'vc-git)
|
||||
(let ((default-directory doom-core-dir))
|
||||
(print! "Doom v%s (Emacs v%s)\nBranch: %s\nCommit: %s\nBuild date: %s"
|
||||
(print! "Doom v%s (%s)\nEmacs v%s\nBranch: %s\nBuild date: %s"
|
||||
doom-version
|
||||
(or (vc-git-working-revision doom-core-dir)
|
||||
"n/a")
|
||||
emacs-version
|
||||
(or (vc-git--symbolic-ref doom-core-dir)
|
||||
"n/a")
|
||||
(or (vc-git-working-revision doom-core-dir)
|
||||
"n/a")
|
||||
(or (cdr (doom-call-process "git" "log" "-1" "--format=%ci"))
|
||||
"n/a"))))
|
||||
|
||||
@@ -127,22 +172,23 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(let ((buffer (get-buffer-create "*doom-info*"))
|
||||
(info (doom-info)))
|
||||
(with-current-buffer buffer
|
||||
(unless (or noninteractive
|
||||
(eq major-mode 'markdown-mode)
|
||||
(not (fboundp 'markdown-mode)))
|
||||
(markdown-mode))
|
||||
(or (not doom-interactive-p)
|
||||
(eq major-mode 'markdown-mode)
|
||||
(not (fboundp 'markdown-mode))
|
||||
(markdown-mode))
|
||||
(erase-buffer)
|
||||
(if raw
|
||||
(progn
|
||||
(save-excursion
|
||||
(pp info (current-buffer)))
|
||||
(when (search-forward "(modules " nil t)
|
||||
(goto-char (match-beginning 0))
|
||||
(cl-destructuring-bind (beg . end)
|
||||
(bounds-of-thing-at-point 'sexp)
|
||||
(let ((sexp (prin1-to-string (sexp-at-point))))
|
||||
(delete-region beg end)
|
||||
(insert sexp)))))
|
||||
(dolist (sym '(modules packages))
|
||||
(when (re-search-forward (format "^ *\\((%s\\)" sym) nil t)
|
||||
(goto-char (match-beginning 1))
|
||||
(cl-destructuring-bind (beg . end)
|
||||
(bounds-of-thing-at-point 'sexp)
|
||||
(let ((sexp (prin1-to-string (sexp-at-point))))
|
||||
(delete-region beg end)
|
||||
(insert sexp))))))
|
||||
(insert "<details>\n\n```\n")
|
||||
(dolist (group info)
|
||||
(insert! "%-8s%-10s %s\n"
|
||||
@@ -153,7 +199,7 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(insert! (indent 8 "%-10s %s\n")
|
||||
((car spec) (cdr spec)))))
|
||||
(insert "```\n</details>"))
|
||||
(if noninteractive
|
||||
(if (not doom-interactive-p)
|
||||
(print! (buffer-string))
|
||||
(switch-to-buffer buffer)
|
||||
(kill-new (buffer-string))
|
||||
@@ -161,15 +207,45 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/am-i-secure ()
|
||||
"Test to see if your root certificates are securely configured in emacs."
|
||||
"Test to see if your root certificates are securely configured in emacs.
|
||||
Some items are not supported by the `nsm.el' module."
|
||||
(declare (interactive-only t))
|
||||
(interactive)
|
||||
(unless (string-match-p "\\_<GNUTLS\\_>" system-configuration-features)
|
||||
(warn "gnutls support isn't built into Emacs, there may be problems"))
|
||||
(if-let* ((bad-hosts
|
||||
(cl-loop for bad
|
||||
in '("https://wrong.host.badssl.com/"
|
||||
"https://self-signed.badssl.com/")
|
||||
in '("https://expired.badssl.com/"
|
||||
"https://wrong.host.badssl.com/"
|
||||
"https://self-signed.badssl.com/"
|
||||
"https://untrusted-root.badssl.com/"
|
||||
;; "https://revoked.badssl.com/"
|
||||
;; "https://pinning-test.badssl.com/"
|
||||
"https://sha1-intermediate.badssl.com/"
|
||||
"https://rc4-md5.badssl.com/"
|
||||
"https://rc4.badssl.com/"
|
||||
"https://3des.badssl.com/"
|
||||
"https://null.badssl.com/"
|
||||
"https://sha1-intermediate.badssl.com/"
|
||||
;; "https://client-cert-missing.badssl.com/"
|
||||
"https://dh480.badssl.com/"
|
||||
"https://dh512.badssl.com/"
|
||||
"https://dh-small-subgroup.badssl.com/"
|
||||
"https://dh-composite.badssl.com/"
|
||||
"https://invalid-expected-sct.badssl.com/"
|
||||
;; "https://no-sct.badssl.com/"
|
||||
;; "https://mixed-script.badssl.com/"
|
||||
;; "https://very.badssl.com/"
|
||||
"https://subdomain.preloaded-hsts.badssl.com/"
|
||||
"https://superfish.badssl.com/"
|
||||
"https://edellroot.badssl.com/"
|
||||
"https://dsdtestprovider.badssl.com/"
|
||||
"https://preact-cli.badssl.com/"
|
||||
"https://webpack-dev-server.badssl.com/"
|
||||
"https://captive-portal.badssl.com/"
|
||||
"https://mitm-software.badssl.com/"
|
||||
"https://sha1-2016.badssl.com/"
|
||||
"https://sha1-2017.badssl.com/")
|
||||
if (condition-case _e
|
||||
(url-retrieve-synchronously bad)
|
||||
(error nil))
|
||||
@@ -193,48 +269,59 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(file (make-temp-file "doom-sandbox-")))
|
||||
(require 'package)
|
||||
(with-temp-file file
|
||||
(insert
|
||||
(prin1-to-string
|
||||
(macroexp-progn
|
||||
(append `((setq noninteractive nil
|
||||
doom-debug-mode t
|
||||
load-path ',load-path
|
||||
package--init-file-ensured t
|
||||
package-user-dir ,package-user-dir
|
||||
package-archives ',package-archives
|
||||
user-emacs-directory ,doom-emacs-dir)
|
||||
(with-eval-after-load 'undo-tree
|
||||
;; undo-tree throws errors because `buffer-undo-tree' isn't
|
||||
;; corrrectly initialized
|
||||
(setq-default buffer-undo-tree (make-undo-tree))))
|
||||
(pcase mode
|
||||
(`vanilla-doom+ ; Doom core + modules - private config
|
||||
`((load-file ,(expand-file-name "core.el" doom-core-dir))
|
||||
(doom-initialize)
|
||||
(doom-initialize-core)
|
||||
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
|
||||
(setq doom-modules ',doom-modules)
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "init" (doom-module-locate-path (car key) (cdr key)) t)))
|
||||
doom-modules)
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "config" (doom-module-locate-path (car key) (cdr key)) t)))
|
||||
doom-modules)
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla-doom ; only Doom core
|
||||
`((load-file ,(expand-file-name "core.el" doom-core-dir))
|
||||
(doom-initialize)
|
||||
(doom-initialize-core)
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla ; nothing loaded
|
||||
`((package-initialize)))))))
|
||||
"\n(unwind-protect (progn\n" contents "\n)\n"
|
||||
(format "(delete-file %S))" file)))
|
||||
(prin1 `(progn
|
||||
(setq noninteractive nil
|
||||
process-environment ',doom--initial-process-environment
|
||||
exec-path ',doom--initial-exec-path
|
||||
init-file-debug t
|
||||
load-path ',load-path
|
||||
package--init-file-ensured t
|
||||
package-user-dir ,package-user-dir
|
||||
package-archives ',package-archives
|
||||
user-emacs-directory ,doom-emacs-dir)
|
||||
(with-eval-after-load 'undo-tree
|
||||
;; undo-tree throws errors because `buffer-undo-tree' isn't
|
||||
;; correctly initialized
|
||||
(setq-default buffer-undo-tree (make-undo-tree)))
|
||||
(ignore-errors
|
||||
(delete-directory ,(expand-file-name "auto-save-list" doom-emacs-dir) 'parents)))
|
||||
(current-buffer))
|
||||
(prin1 `(unwind-protect
|
||||
(defun --run-- () ,(read (concat "(progn\n" contents "\n)")))
|
||||
(delete-file ,file))
|
||||
(current-buffer))
|
||||
(prin1 (pcase mode
|
||||
(`vanilla-doom+ ; Doom core + modules - private config
|
||||
`(progn
|
||||
(load-file ,(expand-file-name "core.el" doom-core-dir))
|
||||
(setq doom-modules-dirs (list doom-modules-dir))
|
||||
(let ((doom-init-modules-p t))
|
||||
(doom-initialize)
|
||||
(doom-initialize-core-modules))
|
||||
(setq doom-modules ',doom-modules)
|
||||
(maphash (lambda (key plist)
|
||||
(doom-module-put
|
||||
(car key) (cdr key)
|
||||
:path (doom-module-locate-path (car key) (cdr key))))
|
||||
doom-modules)
|
||||
(--run--)
|
||||
(maphash (doom-module-loader doom-module-init-file) doom-modules)
|
||||
(maphash (doom-module-loader doom-module-config-file) doom-modules)
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla-doom ; only Doom core
|
||||
`(progn
|
||||
(load-file ,(expand-file-name "core.el" doom-core-dir))
|
||||
(let ((doom-init-modules-p t))
|
||||
(doom-initialize)
|
||||
(doom-initialize-core-modules))
|
||||
(--run--)
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla ; nothing loaded
|
||||
`(progn
|
||||
(package-initialize)
|
||||
(--run--))))
|
||||
(current-buffer)))
|
||||
(let ((args (if (eq mode 'doom)
|
||||
(list "-l" file)
|
||||
(list "-Q" "-l" file))))
|
||||
@@ -254,10 +341,10 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(delete-file file)
|
||||
(signal (car e) (cdr e)))))))
|
||||
|
||||
(fset 'doom--run-vanilla-emacs (lambda! (doom--run-sandbox 'vanilla)))
|
||||
(fset 'doom--run-vanilla-doom (lambda! (doom--run-sandbox 'vanilla-doom)))
|
||||
(fset 'doom--run-vanilla-doom+ (lambda! (doom--run-sandbox 'vanilla-doom+)))
|
||||
(fset 'doom--run-full-doom (lambda! (doom--run-sandbox 'doom)))
|
||||
(fset 'doom--run-vanilla-emacs (cmd! (doom--run-sandbox 'vanilla)))
|
||||
(fset 'doom--run-vanilla-doom (cmd! (doom--run-sandbox 'vanilla-doom)))
|
||||
(fset 'doom--run-vanilla-doom+ (cmd! (doom--run-sandbox 'vanilla-doom+)))
|
||||
(fset 'doom--run-full-doom (cmd! (doom--run-sandbox 'doom)))
|
||||
|
||||
(defvar doom-sandbox-emacs-lisp-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
@@ -293,7 +380,7 @@ to reproduce bugs and determine if Doom is to blame."
|
||||
(doom-sandbox-emacs-lisp-mode)
|
||||
(setq-local default-directory doom-emacs-dir)
|
||||
(unless (buffer-live-p exists)
|
||||
(doom-template-insert "VANILLA_SANDBOX")
|
||||
(insert-file-contents (doom-glob doom-core-dir "templates/VANILLA_SANDBOX"))
|
||||
(let ((contents (substitute-command-keys (buffer-string))))
|
||||
(erase-buffer)
|
||||
(insert contents "\n")))
|
||||
@@ -328,17 +415,3 @@ will be automatically appended to the result."
|
||||
(profiler-report)
|
||||
(profiler-stop))
|
||||
(setq doom--profiler (not doom--profiler)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/toggle-debug-mode (&optional arg)
|
||||
"Toggle `debug-on-error' and `doom-debug-mode' for verbose logging."
|
||||
(interactive (list (or current-prefix-arg 'toggle)))
|
||||
(let ((value
|
||||
(cond ((eq arg 'toggle) (not doom-debug-mode))
|
||||
((> (prefix-numeric-value arg) 0)))))
|
||||
(setq doom-debug-mode value
|
||||
debug-on-error value
|
||||
jka-compr-verbose value
|
||||
lsp-log-io value
|
||||
gcmh-verbose value)
|
||||
(message "Debug mode %s" (if value "on" "off"))))
|
||||
|
||||
@@ -22,23 +22,20 @@ Returns (approximately):
|
||||
|
||||
This is used by `file-exists-p!' and `project-file-exists-p!'."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(let ((exists-fn (if (fboundp 'projectile-file-exists-p)
|
||||
#'projectile-file-exists-p
|
||||
#'file-exists-p)))
|
||||
(if (and (listp spec)
|
||||
(memq (car spec) '(or and)))
|
||||
(cons (car spec)
|
||||
(mapcar (doom-rpartial #'doom--resolve-path-forms directory)
|
||||
(cdr spec)))
|
||||
(let ((filevar (make-symbol "file")))
|
||||
`(let* ((file-name-handler-alist nil)
|
||||
(,filevar ,spec))
|
||||
(and (stringp ,filevar)
|
||||
,(if directory
|
||||
`(let ((default-directory ,directory))
|
||||
(,exists-fn ,filevar))
|
||||
(list exists-fn filevar))
|
||||
,filevar))))))
|
||||
(if (and (listp spec)
|
||||
(memq (car spec) '(or and)))
|
||||
(cons (car spec)
|
||||
(mapcar (doom-rpartial #'doom--resolve-path-forms directory)
|
||||
(cdr spec)))
|
||||
(let ((filevar (make-symbol "file")))
|
||||
`(let* ((file-name-handler-alist nil)
|
||||
(,filevar ,spec))
|
||||
(and (stringp ,filevar)
|
||||
,(if directory
|
||||
`(let ((default-directory ,directory))
|
||||
(file-exists-p ,filevar))
|
||||
`(file-exists-p ,filevar))
|
||||
,filevar)))))
|
||||
|
||||
(defun doom--path (&rest segments)
|
||||
(let (file-name-handler-alist)
|
||||
@@ -108,26 +105,26 @@ be relative to it.
|
||||
The search recurses up to DEPTH and no further. DEPTH is an integer.
|
||||
|
||||
MATCH is a string regexp. Only entries that match it will be included."
|
||||
(let (file-name-handler-alist
|
||||
result)
|
||||
(let (result file-name-handler-alist)
|
||||
(dolist (file (mapcan (doom-rpartial #'doom-glob "*") (doom-enlist paths)))
|
||||
(cond ((file-directory-p file)
|
||||
(nconcq! result
|
||||
(and (memq type '(t dirs))
|
||||
(string-match-p match file)
|
||||
(not (and filter (funcall filter file)))
|
||||
(not (and (file-symlink-p file)
|
||||
(not follow-symlinks)))
|
||||
(<= mindepth 0)
|
||||
(list (cond (map (funcall map file))
|
||||
(relative-to (file-relative-name file relative-to))
|
||||
(file))))
|
||||
(and (>= depth 1)
|
||||
(apply #'doom-files-in file
|
||||
(append (list :mindepth (1- mindepth)
|
||||
:depth (1- depth)
|
||||
:relative-to relative-to)
|
||||
rest)))))
|
||||
(appendq!
|
||||
result
|
||||
(and (memq type '(t dirs))
|
||||
(string-match-p match file)
|
||||
(not (and filter (funcall filter file)))
|
||||
(not (and (file-symlink-p file)
|
||||
(not follow-symlinks)))
|
||||
(<= mindepth 0)
|
||||
(list (cond (map (funcall map file))
|
||||
(relative-to (file-relative-name file relative-to))
|
||||
(file))))
|
||||
(and (>= depth 1)
|
||||
(apply #'doom-files-in file
|
||||
(append (list :mindepth (1- mindepth)
|
||||
:depth (1- depth)
|
||||
:relative-to relative-to)
|
||||
rest)))))
|
||||
((and (memq type '(t files))
|
||||
(string-match-p match file)
|
||||
(not (and filter (funcall filter file)))
|
||||
@@ -203,53 +200,29 @@ single file or nested compound statement of `and' and `or' statements."
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defun doom--forget-file (old-path &optional new-path)
|
||||
"Ensure `recentf', `projectile' and `save-place' forget OLD-PATH."
|
||||
(when (bound-and-true-p recentf-mode)
|
||||
(when new-path
|
||||
(recentf-add-file new-path))
|
||||
(recentf-remove-if-non-kept old-path))
|
||||
(when (and (bound-and-true-p projectile-mode)
|
||||
(doom-project-p)
|
||||
(projectile-file-cached-p old-path (doom-project-root)))
|
||||
(projectile-purge-file-from-cache old-path))
|
||||
(when (bound-and-true-p save-place-mode)
|
||||
(save-place-forget-unreadable-files)))
|
||||
|
||||
(defun doom--update-file (path)
|
||||
(when (featurep 'vc)
|
||||
(vc-file-clearprops path)
|
||||
(vc-resynch-buffer path nil t))
|
||||
(when (featurep 'magit)
|
||||
(magit-refresh)))
|
||||
|
||||
(defun doom--copy-file (old-path new-path &optional force-p)
|
||||
(let* ((new-path (expand-file-name new-path))
|
||||
(old-path (file-truename old-path))
|
||||
(new-path (apply #'expand-file-name
|
||||
(if (or (directory-name-p new-path)
|
||||
(file-directory-p new-path))
|
||||
(list (file-name-nondirectory old-path) new-path)
|
||||
(list new-path))))
|
||||
(new-path-dir (file-name-directory new-path))
|
||||
(project-root (doom-project-root))
|
||||
(short-new-name (if (and project-root (file-in-directory-p new-path project-root))
|
||||
(file-relative-name new-path project-root)
|
||||
(abbreviate-file-name new-path))))
|
||||
(unless (file-directory-p new-path-dir)
|
||||
(make-directory new-path-dir t))
|
||||
(when (buffer-modified-p)
|
||||
(save-buffer))
|
||||
(cond ((file-equal-p old-path new-path)
|
||||
(throw 'status 'overwrite-self))
|
||||
((and (file-exists-p new-path)
|
||||
(not force-p)
|
||||
(not (y-or-n-p (format "File already exists at %s, overwrite?" short-new-name))))
|
||||
(throw 'status 'aborted))
|
||||
((file-exists-p old-path)
|
||||
(copy-file old-path new-path t)
|
||||
short-new-name)
|
||||
(short-new-name))))
|
||||
(defun doom--update-files (&rest files)
|
||||
"Ensure FILES are updated in `recentf', `magit' and `save-place'."
|
||||
(let (toplevels)
|
||||
(dolist (file files)
|
||||
(when (featurep 'vc)
|
||||
(vc-file-clearprops file)
|
||||
(when-let (buffer (get-file-buffer file))
|
||||
(with-current-buffer buffer
|
||||
(vc-refresh-state))))
|
||||
(when (featurep 'magit)
|
||||
(when-let (default-directory (magit-toplevel (file-name-directory file)))
|
||||
(cl-pushnew default-directory toplevels)))
|
||||
(unless (file-readable-p file)
|
||||
(when (bound-and-true-p recentf-mode)
|
||||
(recentf-remove-if-non-kept file))
|
||||
(when (and (bound-and-true-p projectile-mode)
|
||||
(doom-project-p)
|
||||
(projectile-file-cached-p file (doom-project-root)))
|
||||
(projectile-purge-file-from-cache file))))
|
||||
(dolist (default-directory toplevels)
|
||||
(magit-refresh))
|
||||
(when (bound-and-true-p save-place-mode)
|
||||
(save-place-forget-unreadable-files))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -257,68 +230,69 @@ single file or nested compound statement of `and' and `or' statements."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/delete-this-file (&optional path force-p)
|
||||
"Delete FILENAME (defaults to the file associated with current buffer) and
|
||||
kills the buffer. If FORCE-P, force the deletion (don't ask for confirmation)."
|
||||
"Delete PATH, kill its buffers and expunge it from vc/magit cache.
|
||||
|
||||
If PATH is not specified, default to the current buffer's file.
|
||||
|
||||
If FORCE-P, delete without confirmation."
|
||||
(interactive
|
||||
(list (file-truename (buffer-file-name))
|
||||
(list (buffer-file-name (buffer-base-buffer))
|
||||
current-prefix-arg))
|
||||
(let* ((fbase (file-name-sans-extension (file-name-nondirectory path)))
|
||||
(buf (current-buffer)))
|
||||
(cond ((not (file-exists-p path))
|
||||
(error "File doesn't exist: %s" path))
|
||||
((not (or force-p (y-or-n-p (format "Really delete %s?" fbase))))
|
||||
(message "Aborted")
|
||||
nil)
|
||||
((unwind-protect
|
||||
(progn (delete-file path) t)
|
||||
(let ((short-path (file-relative-name path (doom-project-root))))
|
||||
(if (file-exists-p path)
|
||||
(error "Failed to delete %s" short-path)
|
||||
;; Ensures that windows displaying this buffer will be switched
|
||||
;; to real buffers (`doom-real-buffer-p')
|
||||
(doom/kill-this-buffer-in-all-windows buf t)
|
||||
(doom--forget-file path)
|
||||
(doom--update-file path)
|
||||
(message "Successfully deleted %s" short-path))))))))
|
||||
(let* ((path (or path (buffer-file-name (buffer-base-buffer))))
|
||||
(short-path (abbreviate-file-name path)))
|
||||
(unless (and path (file-exists-p path))
|
||||
(user-error "Buffer is not visiting any file"))
|
||||
(unless (file-exists-p path)
|
||||
(error "File doesn't exist: %s" path))
|
||||
(unless (or force-p (y-or-n-p (format "Really delete %S?" short-path)))
|
||||
(user-error "Aborted"))
|
||||
(let ((buf (current-buffer)))
|
||||
(unwind-protect
|
||||
(progn (delete-file path) t)
|
||||
(if (file-exists-p path)
|
||||
(error "Failed to delete %S" short-path)
|
||||
;; Ensures that windows displaying this buffer will be switched to
|
||||
;; real buffers (`doom-real-buffer-p')
|
||||
(doom/kill-this-buffer-in-all-windows buf t)
|
||||
(doom--update-files path)
|
||||
(message "Deleted %S" short-path))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/copy-this-file (new-path &optional force-p)
|
||||
"Copy current buffer's file to NEW-PATH. If FORCE-P, overwrite the destination
|
||||
file if it exists, without confirmation."
|
||||
"Copy current buffer's file to NEW-PATH.
|
||||
|
||||
If FORCE-P, overwrite the destination file if it exists, without confirmation."
|
||||
(interactive
|
||||
(list (read-file-name "Copy file to: ")
|
||||
current-prefix-arg))
|
||||
(pcase (catch 'status
|
||||
(when-let (dest (doom--copy-file (buffer-file-name) new-path force-p))
|
||||
(doom--update-file new-path)
|
||||
(message "File successfully copied to %s" dest)))
|
||||
(`overwrite-self (error "Cannot overwrite self"))
|
||||
(`aborted (message "Aborted"))
|
||||
(_ t)))
|
||||
(unless (and buffer-file-name (file-exists-p buffer-file-name))
|
||||
(user-error "Buffer is not visiting any file"))
|
||||
(let ((old-path (buffer-file-name (buffer-base-buffer)))
|
||||
(new-path (expand-file-name new-path)))
|
||||
(make-directory (file-name-directory new-path) 't)
|
||||
(copy-file old-path new-path (or force-p 1))
|
||||
(doom--update-files old-path new-path)
|
||||
(message "File copied to %S" (abbreviate-file-name new-path))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/move-this-file (new-path &optional force-p)
|
||||
"Move current buffer's file to NEW-PATH. If FORCE-P, overwrite the destination
|
||||
file if it exists, without confirmation."
|
||||
"Move current buffer's file to NEW-PATH.
|
||||
|
||||
If FORCE-P, overwrite the destination file if it exists, without confirmation."
|
||||
(interactive
|
||||
(list (read-file-name "Move file to: ")
|
||||
current-prefix-arg))
|
||||
(pcase (catch 'status
|
||||
(let ((old-path (buffer-file-name))
|
||||
(new-path (expand-file-name new-path)))
|
||||
(when-let (dest (doom--copy-file old-path new-path force-p))
|
||||
(when (file-exists-p old-path)
|
||||
(delete-file old-path))
|
||||
(kill-current-buffer)
|
||||
(doom--forget-file old-path new-path)
|
||||
(doom--update-file new-path)
|
||||
(find-file new-path)
|
||||
(message "File successfully moved to %s" dest))))
|
||||
(`overwrite-self (error "Cannot overwrite self"))
|
||||
(`aborted (message "Aborted"))
|
||||
(_ t)))
|
||||
(unless (and buffer-file-name (file-exists-p buffer-file-name))
|
||||
(user-error "Buffer is not visiting any file"))
|
||||
(let ((old-path (buffer-file-name (buffer-base-buffer)))
|
||||
(new-path (expand-file-name new-path)))
|
||||
(make-directory (file-name-directory new-path) 't)
|
||||
(rename-file old-path new-path (or force-p 1))
|
||||
(set-visited-file-name new-path t t)
|
||||
(doom--update-files old-path new-path)
|
||||
(message "File moved to %S" (abbreviate-file-name new-path))))
|
||||
|
||||
(defun doom--sudo-file (file)
|
||||
(defun doom--sudo-file-path (file)
|
||||
(let ((host (or (file-remote-p file 'host) "localhost")))
|
||||
(concat "/" (when (file-remote-p file)
|
||||
(concat (file-remote-p file 'method) ":"
|
||||
@@ -334,10 +308,32 @@ file if it exists, without confirmation."
|
||||
(defun doom/sudo-find-file (file)
|
||||
"Open FILE as root."
|
||||
(interactive "FOpen file as root: ")
|
||||
(find-file (doom--sudo-file file)))
|
||||
(find-file (doom--sudo-file-path file)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/sudo-this-file ()
|
||||
"Open the current file as root."
|
||||
(interactive)
|
||||
(find-alternate-file (doom--sudo-file buffer-file-name)))
|
||||
(find-file
|
||||
(doom--sudo-file-path
|
||||
(or buffer-file-name
|
||||
(when (or (derived-mode-p 'dired-mode)
|
||||
(derived-mode-p 'wdired-mode))
|
||||
default-directory)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/sudo-save-buffer ()
|
||||
"Save this file as root."
|
||||
(interactive)
|
||||
(let ((file (doom--sudo-file-path buffer-file-name)))
|
||||
(if-let (buffer (find-file-noselect file))
|
||||
(let ((origin (current-buffer)))
|
||||
(copy-to-buffer buffer (point-min) (point-max))
|
||||
(unwind-protect
|
||||
(with-current-buffer buffer
|
||||
(save-buffer))
|
||||
(unless (eq origin buffer)
|
||||
(kill-buffer buffer))
|
||||
(with-current-buffer origin
|
||||
(revert-buffer t t))))
|
||||
(user-error "Unable to open %S" file))))
|
||||
|
||||
@@ -12,7 +12,7 @@ scaled up by `doom-big-font-increment'. See `doom-font' for details on
|
||||
acceptable values for this variable.")
|
||||
|
||||
;;;###autoload
|
||||
(defvar doom-big-font-increment 8
|
||||
(defvar doom-big-font-increment 4
|
||||
"How many steps to increase the font size (with `doom-font' as the base) when
|
||||
`doom-big-font-mode' is enabled and `doom-big-font' is nil.")
|
||||
|
||||
@@ -20,56 +20,47 @@ acceptable values for this variable.")
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
(defun doom--font-name (fontname frame)
|
||||
(defun doom--font-name (fontname)
|
||||
(when (query-fontset fontname)
|
||||
(when-let (ascii (assq 'ascii (aref (fontset-info fontname frame) 2)))
|
||||
(when-let (ascii (assq 'ascii (aref (fontset-info fontname) 2)))
|
||||
(setq fontname (nth 2 ascii))))
|
||||
(or (x-decompose-font-name fontname)
|
||||
(error "Cannot decompose font name")))
|
||||
|
||||
(defun doom--frame-list (&optional frame)
|
||||
"Return a list consisting of FRAME and all of FRAME's child frames."
|
||||
(let ((frame (or frame (selected-frame))))
|
||||
(cons (selected-frame)
|
||||
(cl-loop for fr in (frame-list)
|
||||
if (eq (frame-parameter fr 'parent-frame) frame)
|
||||
collect fr))))
|
||||
|
||||
(defvar doom--font-scale nil)
|
||||
;;;###autoload
|
||||
(defun doom-adjust-font-size (increment &optional frame)
|
||||
(defun doom-adjust-font-size (increment)
|
||||
"Increase size of font in FRAME by INCREMENT.
|
||||
FRAME parameter defaults to current frame."
|
||||
(if (null increment)
|
||||
(let ((frames (doom--frame-list frame)))
|
||||
(dolist (frame frames)
|
||||
(when (frame-parameter frame 'font-scale)
|
||||
(set-frame-parameter frame 'font-scale nil)))
|
||||
(set-frame-font doom-font 'keep-size frames)
|
||||
(and frames t))
|
||||
(let (success)
|
||||
(dolist (frame (doom--frame-list frame))
|
||||
(let* ((font (frame-parameter frame 'font))
|
||||
(font (doom--font-name font frame))
|
||||
(increment (* increment doom-font-increment))
|
||||
(zoom-factor (or (frame-parameter frame 'font-scale) 0)))
|
||||
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
|
||||
increment)))
|
||||
(unless (> new-size 0)
|
||||
(error "Font is too small at %d" new-size))
|
||||
(aset font xlfd-regexp-pixelsize-subnum (number-to-string new-size)))
|
||||
;; Set point size & width to "*", so frame width will adjust to new font size
|
||||
(aset font xlfd-regexp-pointsize-subnum "*")
|
||||
(aset font xlfd-regexp-avgwidth-subnum "*")
|
||||
(setq font (x-compose-font-name font))
|
||||
(unless (x-list-fonts font)
|
||||
(error "Cannot change font size"))
|
||||
(set-frame-parameter frame 'font font)
|
||||
(set-frame-parameter frame 'font-scale (+ zoom-factor increment))
|
||||
(setq success t)))
|
||||
(when success
|
||||
;; Unlike `set-frame-font', `set-frame-parameter' won't trigger this
|
||||
(run-hooks 'after-setting-font-hook)
|
||||
t))))
|
||||
(progn
|
||||
(set-frame-font doom-font 'keep-size t)
|
||||
(setf (alist-get 'font default-frame-alist)
|
||||
(cond ((stringp doom-font) doom-font)
|
||||
((fontp doom-font) (font-xlfd-name doom-font))
|
||||
((signal 'wrong-type-argument (list '(fontp stringp)
|
||||
doom-font)))))
|
||||
t)
|
||||
(let* ((font (frame-parameter nil 'font))
|
||||
(font (doom--font-name font))
|
||||
(increment (* increment doom-font-increment))
|
||||
(zoom-factor (or doom--font-scale 0)))
|
||||
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
|
||||
increment)))
|
||||
(unless (> new-size 0)
|
||||
(error "Font is too small at %d" new-size))
|
||||
(aset font xlfd-regexp-pixelsize-subnum (number-to-string new-size)))
|
||||
;; Set point size & width to "*", so frame width will adjust to new font size
|
||||
(aset font xlfd-regexp-pointsize-subnum "*")
|
||||
(aset font xlfd-regexp-avgwidth-subnum "*")
|
||||
(setq font (x-compose-font-name font))
|
||||
(unless (x-list-fonts font)
|
||||
(error "Cannot change font size"))
|
||||
(set-frame-font font 'keep-size t)
|
||||
(setf (alist-get 'font default-frame-alist) font)
|
||||
(setq doom--font-scale (+ zoom-factor increment))
|
||||
;; Unlike `set-frame-font', `set-frame-parameter' won't trigger this
|
||||
(run-hooks 'after-setting-font-hook))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -127,8 +118,13 @@ This uses `doom/increase-font-size' under the hood, and enlargens the font by
|
||||
(unless doom-font
|
||||
(user-error "`doom-font' must be set to a valid font"))
|
||||
(if doom-big-font
|
||||
(set-frame-font (if doom-big-font-mode doom-big-font doom-font)
|
||||
'keep-size (doom--frame-list))
|
||||
(let ((font (if doom-big-font-mode doom-big-font doom-font)))
|
||||
(set-frame-font font 'keep-size t)
|
||||
(setf (alist-get 'font default-frame-alist)
|
||||
(cond ((stringp doom-font) font)
|
||||
((fontp font) (font-xlfd-name font))
|
||||
((signal 'wrong-type-argument (list '(fontp stringp)
|
||||
font))))))
|
||||
(doom-adjust-font-size
|
||||
(and doom-big-font-mode
|
||||
(integerp doom-big-font-increment)
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
;;; core/autoload/format.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-format-ansi-alist
|
||||
'(;; fx
|
||||
(bold 1 :weight bold)
|
||||
(dark 2)
|
||||
(italic 3 :slant italic)
|
||||
(underscore 4 :underline t)
|
||||
(blink 5)
|
||||
(rapid 6)
|
||||
(contrary 7)
|
||||
(concealed 8)
|
||||
(strike 9 :strike-through t)
|
||||
;; fg
|
||||
(black 30 term-color-black)
|
||||
(red 31 term-color-red)
|
||||
(green 32 term-color-green)
|
||||
(yellow 33 term-color-yellow)
|
||||
(blue 34 term-color-blue)
|
||||
(magenta 35 term-color-magenta)
|
||||
(cyan 36 term-color-cyan)
|
||||
(white 37 term-color-white)
|
||||
;; bg
|
||||
(on-black 40 term-color-black)
|
||||
(on-red 41 term-color-red)
|
||||
(on-green 42 term-color-green)
|
||||
(on-yellow 43 term-color-yellow)
|
||||
(on-blue 44 term-color-blue)
|
||||
(on-magenta 45 term-color-magenta)
|
||||
(on-cyan 46 term-color-cyan)
|
||||
(on-white 47 term-color-white))
|
||||
"An alist of fg/bg/fx names mapped to ansi codes and term-color-* variables.
|
||||
|
||||
This serves as the cipher for converting (COLOR ...) function calls in `print!'
|
||||
and `format!' into colored output, where COLOR is any car of this list.")
|
||||
|
||||
(defvar doom-format-class-alist
|
||||
`((color . doom--format-color)
|
||||
(class . doom--format-class)
|
||||
(indent . doom--format-indent)
|
||||
(autofill . doom--format-autofill)
|
||||
|
||||
(success . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'green (format "✓ %s" str) args)))
|
||||
(warn . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'yellow (format "! %s" str) args)))
|
||||
(error . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'red (format "x %s" str) args)))
|
||||
(info . (lambda (str &rest args)
|
||||
(concat "- " (if args (apply #'format str args) str))))
|
||||
(start . (lambda (str &rest args)
|
||||
(concat "> " (if args (apply #'format str args) str))))
|
||||
(debug . (lambda (str &rest args)
|
||||
(if doom-debug-mode
|
||||
(if args
|
||||
(apply #'format str args)
|
||||
(format "%s" str))
|
||||
"")))
|
||||
(path . abbreviate-file-name)
|
||||
(symbol . symbol-name)
|
||||
(relpath . (lambda (str &optional dir)
|
||||
(if (or (not str)
|
||||
(not (stringp str))
|
||||
(string-empty-p str))
|
||||
str
|
||||
(let ((dir (or dir (file-truename default-directory)))
|
||||
(str (file-truename str)))
|
||||
(if (file-in-directory-p str dir)
|
||||
(file-relative-name str dir)
|
||||
(abbreviate-file-name str))))))
|
||||
(filename . file-name-nondirectory)
|
||||
(dirname . (lambda (path)
|
||||
(unless (file-directory-p path)
|
||||
(setq path (file-name-directory path)))
|
||||
(directory-file-name path))))
|
||||
"An alist of text classes that map to transformation functions.
|
||||
|
||||
Any of these classes can be called like functions from within `format!' and
|
||||
`print!' calls, which will transform their input.")
|
||||
|
||||
(defvar doom-format-indent 0
|
||||
"Level to rigidly indent text returned by `format!' and `print!'.")
|
||||
|
||||
(defvar doom-format-indent-increment 2
|
||||
"Steps in which to increment `doom-format-indent' for consecutive levels.")
|
||||
|
||||
(defvar doom-format-backend
|
||||
(if noninteractive 'ansi 'text-properties)
|
||||
"Determines whether to print colors with ANSI codes or with text properties.
|
||||
|
||||
Accepts 'ansi and 'text-properties. nil means don't render colors.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format (output)
|
||||
(if (string-empty-p (string-trim output))
|
||||
""
|
||||
(concat (make-string doom-format-indent 32)
|
||||
(replace-regexp-in-string
|
||||
"\n" (concat "\n" (make-string doom-format-indent 32))
|
||||
output t t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-print (output)
|
||||
(unless (string-empty-p output)
|
||||
(princ output)
|
||||
(when (or noninteractive (not (eq standard-output t)))
|
||||
(terpri)) ; newline
|
||||
t))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-indent (width text &optional prefix)
|
||||
"Indent TEXT by WIDTH spaces. If ARGS, format TEXT with them."
|
||||
(with-temp-buffer
|
||||
(setq text (format "%s" text))
|
||||
(insert text)
|
||||
(indent-rigidly (point-min) (point-max) width)
|
||||
(when (stringp prefix)
|
||||
(when (> width 2)
|
||||
(goto-char (point-min))
|
||||
(beginning-of-line-text)
|
||||
(delete-char (- (length prefix)))
|
||||
(insert prefix)))
|
||||
(buffer-string)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-autofill (&rest msgs)
|
||||
"Ensure MSG is split into lines no longer than `fill-column'."
|
||||
(with-temp-buffer
|
||||
(let ((fill-column 76))
|
||||
(dolist (line msgs)
|
||||
(when line
|
||||
(insert (format "%s" line))))
|
||||
(fill-region (point-min) (point-max))
|
||||
(buffer-string))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-color (style format &rest args)
|
||||
"Apply STYLE to formatted MESSAGE with ARGS.
|
||||
|
||||
STYLE is a symbol that correlates to `doom-format-ansi-alist'.
|
||||
|
||||
In a noninteractive session, this wraps the result in ansi color codes.
|
||||
Otherwise, it maps colors to a term-color-* face."
|
||||
(let* ((code (cadr (assq style doom-format-ansi-alist)))
|
||||
(format (format "%s" format))
|
||||
(message (if args (apply #'format format args) format)))
|
||||
(unless code
|
||||
(error "%S is an invalid color" style))
|
||||
(pcase doom-format-backend
|
||||
(`ansi
|
||||
(format "\e[%dm%s\e[%dm" code message 0))
|
||||
(`text-properties
|
||||
(require 'term) ; piggyback on term's color faces
|
||||
(propertize
|
||||
message
|
||||
'face
|
||||
(append (get-text-property 0 'face format)
|
||||
(cond ((>= code 40)
|
||||
`(:background ,(caddr (assq style doom-format-ansi-alist))))
|
||||
((>= code 30)
|
||||
`(:foreground ,(face-foreground (caddr (assq style doom-format-ansi-alist)))))
|
||||
((cddr (assq style doom-format-ansi-alist)))))))
|
||||
(_ message))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-class (class format &rest args)
|
||||
"Apply CLASS to formatted format with ARGS.
|
||||
|
||||
CLASS is derived from `doom-format-class-alist', and can contain any arbitrary,
|
||||
transformative logic."
|
||||
(let (fn)
|
||||
(cond ((setq fn (cdr (assq class doom-format-class-alist)))
|
||||
(if (functionp fn)
|
||||
(apply fn format args)
|
||||
(error "%s does not have a function" class)))
|
||||
(args (apply #'format format args))
|
||||
(format))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom--format-apply (forms &optional sub)
|
||||
"Replace color-name functions with calls to `doom--format-color'."
|
||||
(cond ((null forms) nil)
|
||||
((listp forms)
|
||||
(append (cond ((not (symbolp (car forms)))
|
||||
(list (doom--format-apply (car forms))))
|
||||
(sub
|
||||
(list (car forms)))
|
||||
((assq (car forms) doom-format-ansi-alist)
|
||||
`(doom--format-color ',(car forms)))
|
||||
((assq (car forms) doom-format-class-alist)
|
||||
`(doom--format-class ',(car forms)))
|
||||
((list (car forms))))
|
||||
(doom--format-apply (cdr forms) t)
|
||||
nil))
|
||||
(forms)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro format! (message &rest args)
|
||||
"An alternative to `format' that understands (color ...) and converts them
|
||||
into faces or ANSI codes depending on the type of sesssion we're in."
|
||||
`(doom--format (format ,@(doom--format-apply `(,message ,@args)))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro print-group! (&rest body)
|
||||
"Indents any `print!' or `format!' output within BODY."
|
||||
`(let ((doom-format-indent (+ doom-format-indent-increment doom-format-indent)))
|
||||
,@body))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro print! (message &rest args)
|
||||
"Uses `message' in interactive sessions and `princ' otherwise (prints to
|
||||
standard out).
|
||||
|
||||
Can be colored using (color ...) blocks:
|
||||
|
||||
(print! \"Hello %s\" (bold (blue \"How are you?\")))
|
||||
(print! \"Hello %s\" (red \"World\"))
|
||||
(print! (green \"Great %s!\") \"success\")
|
||||
|
||||
Uses faces in interactive sessions and ANSI codes otherwise."
|
||||
`(doom--format-print (format! ,message ,@args)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro insert! (message &rest args)
|
||||
"Like `insert'; the last argument must be format arguments for MESSAGE.
|
||||
|
||||
\(fn MESSAGE... ARGS)"
|
||||
`(insert (format! (concat ,message ,@(butlast args))
|
||||
,@(car (last args)))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro error! (message &rest args)
|
||||
"Like `error', but with the power of `format!'."
|
||||
`(error (format! ,message ,@args)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro user-error! (message &rest args)
|
||||
"Like `user-error', but with the power of `format!'."
|
||||
`(user-error (format! ,message ,@args)))
|
||||
@@ -3,9 +3,6 @@
|
||||
(defvar doom--help-major-mode-module-alist
|
||||
'((dockerfile-mode :tools docker)
|
||||
(agda2-mode :lang agda)
|
||||
(haxor-mode :lang assembly)
|
||||
(mips-mode :lang assembly)
|
||||
(nasm-mode :lang assembly)
|
||||
(c-mode :lang cc)
|
||||
(c++-mode :lang cc)
|
||||
(objc++-mode :lang cc)
|
||||
@@ -34,6 +31,7 @@
|
||||
(js2-mode :lang javascript)
|
||||
(rjsx-mode :lang javascript)
|
||||
(typescript-mode :lang javascript)
|
||||
(typescript-tsx-mode :lang javascript)
|
||||
(coffee-mode :lang javascript)
|
||||
(julia-mode :lang julia)
|
||||
(kotlin-mode :lang kotlin)
|
||||
@@ -41,13 +39,14 @@
|
||||
(LaTeX-mode :lang latex)
|
||||
(ledger-mode :lang ledger)
|
||||
(lua-mode :lang lua)
|
||||
(moonscript-mode :lang lua)
|
||||
(markdown-mode :lang markdown)
|
||||
(gfm-mode :lang markdown)
|
||||
(nim-mode :lang nim)
|
||||
(nix-mode :lang nix)
|
||||
(taureg-mode :lang ocaml)
|
||||
(org-mode :lang org)
|
||||
(perl-mode :lang perl)
|
||||
(raku-mode :lang raku)
|
||||
(php-mode :lang php)
|
||||
(hack-mode :lang php)
|
||||
(plantuml-mode :lang plantuml)
|
||||
@@ -55,9 +54,10 @@
|
||||
(python-mode :lang python)
|
||||
(restclient-mode :lang rest)
|
||||
(ruby-mode :lang ruby)
|
||||
(enh-ruby-mode :lang ruby)
|
||||
(rust-mode :lang rust)
|
||||
(rustic-mode :lang rust)
|
||||
(scala-mode :lang scala)
|
||||
(scheme-mode :lang scheme)
|
||||
(sh-mode :lang sh)
|
||||
(swift-mode :lang swift)
|
||||
(web-mode :lang web)
|
||||
@@ -96,7 +96,7 @@ the current major-modea.")
|
||||
"Get information on an active minor mode. Use `describe-minor-mode' for a
|
||||
selection of all minor-modes, active or not."
|
||||
(interactive
|
||||
(list (completing-read "Minor mode: " (doom-active-minor-modes))))
|
||||
(list (completing-read "Describe active mode: " (doom-active-minor-modes))))
|
||||
(let ((symbol
|
||||
(cond ((stringp mode) (intern mode))
|
||||
((symbolp mode) mode)
|
||||
@@ -105,21 +105,6 @@ selection of all minor-modes, active or not."
|
||||
(helpful-function symbol)
|
||||
(helpful-variable symbol))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/describe-symbol (symbol)
|
||||
"Show help for SYMBOL, a variable, function or macro."
|
||||
(interactive
|
||||
(list (helpful--read-symbol "Symbol: " #'helpful--bound-p)))
|
||||
(let* ((sym (intern-soft symbol))
|
||||
(bound (boundp sym))
|
||||
(fbound (fboundp sym)))
|
||||
(cond ((and sym bound (not fbound))
|
||||
(helpful-variable sym))
|
||||
((and sym fbound (not bound))
|
||||
(helpful-callable sym))
|
||||
((apropos (format "^%s\$" symbol)))
|
||||
((apropos (format "%s" symbol))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Documentation commands
|
||||
@@ -130,7 +115,8 @@ selection of all minor-modes, active or not."
|
||||
(require 'org)
|
||||
(let* ((default-directory doom-docs-dir)
|
||||
(org-agenda-files (mapcar #'expand-file-name (doom-enlist files)))
|
||||
(depth (if (integerp depth) depth)))
|
||||
(depth (if (integerp depth) depth))
|
||||
(org-inhibit-startup t))
|
||||
(message "Loading search results...")
|
||||
(unwind-protect
|
||||
(delq
|
||||
@@ -150,7 +136,8 @@ selection of all minor-modes, active or not."
|
||||
(list (or (+org-get-global-property "TITLE")
|
||||
(file-relative-name (buffer-file-name)))))
|
||||
path
|
||||
(list (replace-regexp-in-string org-link-any-re "\\4" text)))
|
||||
(when text
|
||||
(list (replace-regexp-in-string org-link-any-re "\\4" text))))
|
||||
" > ")
|
||||
tags)
|
||||
" ")
|
||||
@@ -196,7 +183,7 @@ selection of all minor-modes, active or not."
|
||||
(find-file (expand-file-name "index.org" doom-docs-dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-search (&optional initial-input)
|
||||
(defun doom/help-search-headings (&optional initial-input)
|
||||
"Search Doom's documentation and jump to a headline."
|
||||
(interactive)
|
||||
(doom-completing-read-org-headings
|
||||
@@ -213,7 +200,26 @@ selection of all minor-modes, active or not."
|
||||
(doom--help-modules-list))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-news-search (&optional initial-input)
|
||||
(defun doom/help-search (&optional initial-input)
|
||||
"Preform a text search on all of Doom's documentation."
|
||||
(interactive)
|
||||
(funcall (cond ((fboundp '+ivy-file-search)
|
||||
#'+ivy-file-search)
|
||||
((fboundp '+helm-file-search)
|
||||
#'+helm-file-search)
|
||||
((rgrep
|
||||
(read-regexp
|
||||
"Search for" (or initial-input 'grep-tag-default)
|
||||
'grep-regexp-history)
|
||||
"*.org" doom-emacs-dir)
|
||||
#'ignore))
|
||||
:query initial-input
|
||||
:args '("-g" "*.org")
|
||||
:in doom-emacs-dir
|
||||
:prompt "Search documentation for: "))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-search-news (&optional initial-input)
|
||||
"Search headlines in Doom's newsletters."
|
||||
(interactive)
|
||||
(doom-completing-read-org-headings
|
||||
@@ -316,13 +322,7 @@ without needing to check if they are available."
|
||||
readme-path)))
|
||||
|
||||
(defun doom--help-current-module-str ()
|
||||
(cond ((and buffer-file-name
|
||||
(eq major-mode 'emacs-lisp-mode)
|
||||
(file-in-directory-p buffer-file-name doom-private-dir)
|
||||
(save-excursion (goto-char (point-min))
|
||||
(re-search-forward "^\\s-*(doom! " nil t))
|
||||
(thing-at-point 'sexp t)))
|
||||
((save-excursion
|
||||
(cond ((save-excursion
|
||||
(require 'smartparens)
|
||||
(ignore-errors
|
||||
(sp-beginning-of-sexp)
|
||||
@@ -341,11 +341,14 @@ without needing to check if they are available."
|
||||
(symbol-name (cadr mod)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-modules (category module)
|
||||
(defun doom/help-modules (category module &optional visit-dir)
|
||||
"Open the documentation for a Doom module.
|
||||
|
||||
CATEGORY is a keyword and MODULE is a symbol. e.g. :editor and 'evil.
|
||||
|
||||
If VISIT-DIR is non-nil, visit the module's directory rather than its
|
||||
documentation.
|
||||
|
||||
Automatically selects a) the module at point (in private init files), b) the
|
||||
module derived from a `featurep!' or `require!' call, c) the module that the
|
||||
current file is in, or d) the module associated with the current major mode (see
|
||||
@@ -354,7 +357,8 @@ current file is in, or d) the module associated with the current major mode (see
|
||||
(mapcar #'intern
|
||||
(split-string
|
||||
(completing-read "Describe module: "
|
||||
(doom--help-modules-list) nil t nil nil
|
||||
(doom--help-modules-list)
|
||||
nil t nil nil
|
||||
(doom--help-current-module-str))
|
||||
" " t)))
|
||||
(cl-check-type category symbol)
|
||||
@@ -362,14 +366,19 @@ current file is in, or d) the module associated with the current major mode (see
|
||||
(cl-destructuring-bind (module-string path)
|
||||
(or (assoc (format "%s %s" category module) (doom--help-modules-list))
|
||||
(user-error "'%s %s' is not a valid module" category module))
|
||||
(setq module-string (substring-no-properties module-string))
|
||||
(unless (file-readable-p path)
|
||||
(error "Can't find or read %S module at %S" module-string path))
|
||||
(if (not (file-directory-p path))
|
||||
(find-file path)
|
||||
(if (y-or-n-p (format "The %S module has no README file. Explore its directory?"
|
||||
module-string))
|
||||
(doom-project-browse path)
|
||||
(user-error "Aborted module lookup")))))
|
||||
(cond ((not (file-directory-p path))
|
||||
(if visit-dir
|
||||
(doom-project-browse (file-name-directory path))
|
||||
(find-file path)))
|
||||
(visit-dir
|
||||
(doom-project-browse path))
|
||||
((y-or-n-p (format "The %S module has no README file. Explore its directory?"
|
||||
module-string))
|
||||
(doom-project-browse (file-name-directory path)))
|
||||
((user-error "Aborted module lookup")))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -419,8 +428,8 @@ If prefix arg is present, refresh the cache."
|
||||
(let ((guess (or (function-called-at-point)
|
||||
(symbol-at-point))))
|
||||
(require 'finder-inf nil t)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)
|
||||
(require 'package)
|
||||
(require 'straight)
|
||||
(let ((packages (delete-dups
|
||||
(append (mapcar #'car package-alist)
|
||||
(mapcar #'car package--builtins)
|
||||
@@ -432,9 +441,9 @@ If prefix arg is present, refresh the cache."
|
||||
(list
|
||||
(intern
|
||||
(completing-read (if guess
|
||||
(format "Select package to search for (default %s): "
|
||||
(format "Select Doom package to search for (default %s): "
|
||||
guess)
|
||||
"Describe package: ")
|
||||
"Describe Doom package: ")
|
||||
packages nil t nil nil
|
||||
(if guess (symbol-name guess))))))))
|
||||
(require 'core-packages)
|
||||
@@ -462,27 +471,44 @@ If prefix arg is present, refresh the cache."
|
||||
(insert (symbol-name package) "\n")
|
||||
|
||||
(package--print-help-section "Source")
|
||||
(insert (or (pcase (doom-package-backend package)
|
||||
(`straight
|
||||
(format! "Straight (%s)\n%s"
|
||||
(let ((default-directory (straight--build-dir (symbol-name package))))
|
||||
(cdr
|
||||
(doom-call-process "git" "log" "-1" "--format=%D %h %ci")))
|
||||
(indent
|
||||
13 (string-trim
|
||||
(pp-to-string
|
||||
(doom-package-build-recipe package))))))
|
||||
(`elpa
|
||||
(format "[M]ELPA %s" (doom--package-url package)))
|
||||
(`builtin "Built-in")
|
||||
(_ (abbreviate-file-name (symbol-file package))))
|
||||
"unknown")
|
||||
"\n")
|
||||
(pcase (doom-package-backend package)
|
||||
(`straight
|
||||
(insert "Straight\n")
|
||||
(package--print-help-section "Pinned")
|
||||
(insert (if-let (pin (plist-get (cdr (assq package doom-packages)) :pin))
|
||||
pin
|
||||
"unpinned")
|
||||
"\n")
|
||||
(package--print-help-section "Build")
|
||||
(insert (let ((default-directory (straight--repos-dir (symbol-name package))))
|
||||
(cdr
|
||||
(doom-call-process "git" "log" "-1" "--format=%D %h %ci")))
|
||||
"\n")
|
||||
(let ((recipe (doom-package-build-recipe package)))
|
||||
(insert (format! "%s\n"
|
||||
(indent 13
|
||||
(string-trim (pp-to-string recipe)))))
|
||||
|
||||
(when (gethash (symbol-name package) straight--build-cache)
|
||||
(package--print-help-section "Homepage")
|
||||
(insert (doom--package-url package))))
|
||||
(`elpa (insert "[M]ELPA " (doom--package-url package)))
|
||||
(`builtin (insert "Built-in"))
|
||||
(`other (insert
|
||||
(abbreviate-file-name
|
||||
(or (symbol-file package)
|
||||
(locate-library (symbol-name package))))))
|
||||
(_ (insert "Not installed")))
|
||||
(insert "\n")
|
||||
|
||||
(when-let
|
||||
(modules
|
||||
(if (gethash (symbol-name package) straight--build-cache)
|
||||
(doom-package-get package :modules)
|
||||
(plist-get (cdr (assq package (doom-package-list 'all)))
|
||||
:modules)))
|
||||
(package--print-help-section "Modules")
|
||||
(insert "Declared by the following Doom modules:\n")
|
||||
(dolist (m (doom-package-get package :modules))
|
||||
(dolist (m modules)
|
||||
(insert indent)
|
||||
(doom--help-package-insert-button
|
||||
(format "%s %s" (car m) (or (cdr m) ""))
|
||||
@@ -512,7 +538,7 @@ If prefix arg is present, refresh the cache."
|
||||
(insert "\n\n")))))
|
||||
|
||||
(defvar doom--package-cache nil)
|
||||
(defun doom--package-list ()
|
||||
(defun doom--package-list (&optional prompt)
|
||||
(let* ((guess (or (function-called-at-point)
|
||||
(symbol-at-point))))
|
||||
(require 'finder-inf nil t)
|
||||
@@ -528,10 +554,11 @@ If prefix arg is present, refresh the cache."
|
||||
(setq doom--package-cache packages)
|
||||
(unless (memq guess packages)
|
||||
(setq guess nil))
|
||||
(intern (completing-read (if guess
|
||||
(format "Select package to search for (default %s): "
|
||||
guess)
|
||||
"Describe package: ")
|
||||
(intern (completing-read (or prompt
|
||||
(if guess
|
||||
(format "Select package to search for (default %s): "
|
||||
guess)
|
||||
"Describe package: "))
|
||||
packages nil t nil nil
|
||||
(if guess (symbol-name guess)))))))
|
||||
|
||||
@@ -578,7 +605,7 @@ If prefix arg is present, refresh the cache."
|
||||
|
||||
This only searches `doom-emacs-dir' (typically ~/.emacs.d) and does not include
|
||||
config blocks in your private config."
|
||||
(interactive (list (doom--package-list)))
|
||||
(interactive (list (doom--package-list "Find package config: ")))
|
||||
(cl-destructuring-bind (file line _match)
|
||||
(split-string
|
||||
(completing-read
|
||||
@@ -592,55 +619,48 @@ config blocks in your private config."
|
||||
(recenter)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-package-homepage (package)
|
||||
"Open PACKAGE's repo or homepage in your browser."
|
||||
(interactive (list (doom--package-list)))
|
||||
(browse-url (doom--package-url package)))
|
||||
(defalias 'doom/help-package-homepage #'straight-visit-package-website)
|
||||
|
||||
(defun doom--help-search-prompt (prompt)
|
||||
(let ((query (doom-thing-at-point-or-region)))
|
||||
(if (featurep 'counsel)
|
||||
query
|
||||
(read-string prompt query 'git-grep query))))
|
||||
|
||||
(defvar counsel-rg-base-command)
|
||||
(defun doom--help-search (dirs query prompt)
|
||||
;; REVIEW Replace with deadgrep
|
||||
(unless (executable-find "rg")
|
||||
(user-error "Can't find ripgrep on your system"))
|
||||
(if (fboundp 'counsel-rg)
|
||||
(let ((counsel-rg-base-command (append counsel-rg-base-command dirs)))
|
||||
(counsel-rg query nil "-Lz" prompt))
|
||||
;; TODO Add helm support?
|
||||
(grep-find
|
||||
(string-join
|
||||
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never"
|
||||
(shell-quote-argument query))
|
||||
(mapcar #'shell-quote-argument dirs))
|
||||
" "))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-search-load-path (query)
|
||||
"Perform a text search on your `load-path'.
|
||||
Uses the symbol at point or the current selection, if available."
|
||||
(interactive
|
||||
(let ((query
|
||||
;; TODO Generalize this later; into something the lookup module and
|
||||
;; project search commands could as well
|
||||
(if (use-region-p)
|
||||
(buffer-substring-no-properties (region-beginning) (region-end))
|
||||
(or (symbol-name (symbol-at-point)) ""))))
|
||||
(list (read-string
|
||||
(format "Search load-path (default: %s): " query)
|
||||
nil 'git-grep query))))
|
||||
;; REVIEW Replace with deadgrep
|
||||
(grep-find
|
||||
(mapconcat
|
||||
#'shell-quote-argument
|
||||
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never" query)
|
||||
(cl-remove-if-not #'file-directory-p load-path))
|
||||
" ")))
|
||||
(list (doom--help-search-prompt "Search load-path: ")))
|
||||
(doom--help-search (cl-remove-if-not #'file-directory-p load-path)
|
||||
query "Search load-path: "))
|
||||
|
||||
;; TODO factor our the duplicate code between this and the above
|
||||
;;;###autoload
|
||||
(defun doom/help-search-loaded-files (query)
|
||||
"Perform a text search on your `load-path'.
|
||||
Uses the symbol at point or the current selection, if available."
|
||||
(interactive
|
||||
(let ((query
|
||||
;; TODO Generalize this later; into something the lookup module and
|
||||
;; project search commands could as well.
|
||||
(if (use-region-p)
|
||||
(buffer-substring-no-properties (region-beginning) (region-end))
|
||||
(or (symbol-name (symbol-at-point)) ""))))
|
||||
(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
|
||||
(grep-find
|
||||
(mapconcat
|
||||
#'shell-quote-argument
|
||||
(append (list "rg" "-L" "--search-zip" "--no-heading" "--color=never" query)
|
||||
(cl-remove-if-not #'file-directory-p (elisp-refs--loaded-paths)))
|
||||
" ")))
|
||||
(list (doom--help-search-prompt "Search loaded files: ")))
|
||||
(doom--help-search
|
||||
(cl-loop for (file . _) in (cl-remove-if-not #'stringp load-history :key #'car)
|
||||
for filebase = (file-name-sans-extension file)
|
||||
if (file-exists-p! (format "%s.el" filebase))
|
||||
collect it)
|
||||
query "Search loaded files: "))
|
||||
|
||||
@@ -1,198 +1,5 @@
|
||||
;;; core/autoload/packages.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;;; Package metadata
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-get (package &optional prop nil-value)
|
||||
"Returns PACKAGE's `package!' recipe from `doom-packages'."
|
||||
(let ((plist (cdr (assq package doom-packages))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-recipe (package &optional prop nil-value)
|
||||
"Returns the `straight' recipe PACKAGE was registered with."
|
||||
(let ((plist (gethash (symbol-name package) straight--recipe-cache)))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-build-recipe (package &optional prop nil-value)
|
||||
"Returns the `straight' recipe PACKAGE was installed with."
|
||||
(let ((plist (nth 2 (gethash (symbol-name package) straight--build-cache))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-build-time (package)
|
||||
"TODO"
|
||||
(car (gethash (symbol-name package) straight--build-cache)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-dependencies (package &optional recursive noerror)
|
||||
"Return a list of dependencies for a package."
|
||||
(let ((deps (nth 1 (gethash (symbol-name package) straight--build-cache))))
|
||||
(if recursive
|
||||
(nconc deps (mapcan (lambda (dep) (doom-package-dependencies dep t t))
|
||||
deps))
|
||||
deps)))
|
||||
|
||||
(defun doom-package-depending-on (package &optional noerror)
|
||||
"Return a list of packages that depend on the package named NAME."
|
||||
(cl-check-type name symbol)
|
||||
;; can't get dependencies for built-in packages
|
||||
(unless (or (doom-package-build-recipe name)
|
||||
noerror)
|
||||
(error "Couldn't find %s, is it installed?" name))
|
||||
(cl-loop for pkg in (hash-table-keys straight--build-cache)
|
||||
for deps = (doom-package-dependencies pkg)
|
||||
if (memq package deps)
|
||||
collect pkg
|
||||
and append (doom-package-depending-on pkg t)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Predicate functions
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-built-in-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) is built-in."
|
||||
(eq (doom-package-build-recipe package :type)
|
||||
'built-in))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-installed-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) is installed."
|
||||
(file-directory-p (straight--build-dir (symbol-name package))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-registered-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) has been registered with `package!'.
|
||||
|
||||
Excludes packages that have a non-nil :built-in property."
|
||||
(when-let (plist (doom-package-get package))
|
||||
(not (plist-get plist :ignore))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-private-p (package)
|
||||
"Return non-nil if PACKAGE was installed by the user's private config."
|
||||
(assq :private (doom-package-get package :modules)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-protected-p (package)
|
||||
"Return non-nil if PACKAGE is protected.
|
||||
|
||||
A protected package cannot be deleted and will be auto-installed if missing."
|
||||
(memq package doom-core-packages))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-core-p (package)
|
||||
"Return non-nil if PACKAGE is a core Doom package."
|
||||
(or (doom-package-protected-p package)
|
||||
(assq :core (doom-package-get package :modules))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-backend (package)
|
||||
"Return 'straight, 'builtin, 'elpa or 'other, depending on how PACKAGE is
|
||||
installed."
|
||||
(cond ((gethash (symbol-name package) straight--build-cache)
|
||||
'straight)
|
||||
((or (doom-package-built-in-p package)
|
||||
(assq package package--builtins))
|
||||
'builtin)
|
||||
((assq package package-alist)
|
||||
'elpa)
|
||||
('other)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-different-recipe-p (name)
|
||||
"Return t if a package named NAME (a symbol) has a different recipe than it
|
||||
was installed with."
|
||||
(cl-check-type name symbol)
|
||||
;; TODO
|
||||
;; (when (doom-package-installed-p name)
|
||||
;; (when-let* ((doom-recipe (assq name doom-packages))
|
||||
;; (install-recipe (doom-package-recipe)))
|
||||
;; (not (equal (cdr quelpa-recipe)
|
||||
;; (cdr (plist-get (cdr doom-recipe) :recipe))))))
|
||||
)
|
||||
|
||||
|
||||
;;
|
||||
;;; Package list getters
|
||||
|
||||
(defun doom--read-module-packages-file (file &optional noeval noerror)
|
||||
(with-temp-buffer ; prevent buffer-local settings from propagating
|
||||
(condition-case e
|
||||
(if (not noeval)
|
||||
(load file noerror t t)
|
||||
(when (file-readable-p file)
|
||||
(insert-file-contents file)
|
||||
(delay-mode-hooks (emacs-lisp-mode))
|
||||
(while (search-forward "(package! " nil t)
|
||||
(save-excursion
|
||||
(goto-char (match-beginning 0))
|
||||
(unless (let ((ppss (syntax-ppss)))
|
||||
(or (nth 3 ppss)
|
||||
(nth 4 ppss)))
|
||||
(cl-destructuring-bind (name . plist)
|
||||
(cdr (sexp-at-point))
|
||||
(push (cons
|
||||
name (plist-put
|
||||
plist :modules
|
||||
(list (doom-module-from-path file))))
|
||||
doom-packages)))))))
|
||||
((debug error)
|
||||
(signal 'doom-package-error
|
||||
(list (doom-module-from-path file)
|
||||
e))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-list (&optional all-p)
|
||||
"Retrieve a list of explicitly declared packages from enabled modules.
|
||||
|
||||
This excludes core packages listed in `doom-core-packages'.
|
||||
|
||||
If ALL-P, gather packages unconditionally across all modules, including disabled
|
||||
ones."
|
||||
(let ((doom-interactive-mode t)
|
||||
(doom-modules (doom-modules))
|
||||
doom-packages
|
||||
doom-disabled-packages)
|
||||
(doom--read-module-packages-file
|
||||
(doom-path doom-core-dir "packages.el") all-p t)
|
||||
(let ((private-packages (doom-path doom-private-dir "packages.el")))
|
||||
(unless all-p
|
||||
;; We load the private packages file twice to ensure disabled packages
|
||||
;; are seen ASAP, and a second time to ensure privately overridden
|
||||
;; packages are properly overwritten.
|
||||
(doom--read-module-packages-file private-packages nil t))
|
||||
(if all-p
|
||||
(mapc #'doom--read-module-packages-file
|
||||
(doom-files-in doom-modules-dir
|
||||
:depth 2
|
||||
:match "/packages\\.el$"))
|
||||
(cl-loop for key being the hash-keys of doom-modules
|
||||
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
||||
for doom--current-module = key
|
||||
do (doom--read-module-packages-file path nil t)))
|
||||
(doom--read-module-packages-file private-packages all-p t))
|
||||
(nreverse doom-packages)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Main functions
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-packages ()
|
||||
"Reload `doom-packages', `package' and `quelpa'."
|
||||
@@ -201,3 +8,190 @@ ones."
|
||||
(message "Reloading packages")
|
||||
(doom-initialize-packages t)
|
||||
(message "Reloading packages...DONE"))
|
||||
|
||||
|
||||
;;
|
||||
;;; Bump commands
|
||||
|
||||
(defun doom--package-full-recipe (package plist)
|
||||
(doom-plist-merge
|
||||
(plist-get plist :recipe)
|
||||
(or (cdr (straight-recipes-retrieve package))
|
||||
(plist-get (cdr (assq package doom-packages))
|
||||
:recipe))))
|
||||
|
||||
(defun doom--package-to-bump-string (package plist)
|
||||
"Return a PACKAGE and its PLIST in 'username/repo@commit' format."
|
||||
(format "%s@%s"
|
||||
(plist-get (doom--package-full-recipe package plist) :repo)
|
||||
(substring-no-properties (plist-get plist :pin) 0 7)))
|
||||
|
||||
(defun doom--package-at-point (&optional point)
|
||||
"Return the package and plist from the (package! PACKAGE PLIST...) at point."
|
||||
(save-match-data
|
||||
(save-excursion
|
||||
(and point (goto-char point))
|
||||
(while (and (or (atom (sexp-at-point))
|
||||
(doom-point-in-string-or-comment-p))
|
||||
(search-backward "(" nil t)))
|
||||
(when (eq (car-safe (sexp-at-point)) 'package!)
|
||||
(cl-destructuring-bind (beg . end)
|
||||
(bounds-of-thing-at-point 'sexp)
|
||||
(let* ((doom-packages nil)
|
||||
(buffer-file-name
|
||||
(or buffer-file-name
|
||||
(bound-and-true-p org-src-source-file-name)))
|
||||
(package (eval (sexp-at-point) t)))
|
||||
(list :beg beg
|
||||
:end end
|
||||
:package (car package)
|
||||
:plist (cdr package))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bumpify-package-at-point ()
|
||||
"Convert `package!' call at point to a bump string."
|
||||
(interactive)
|
||||
(cl-destructuring-bind (&key package plist beg end)
|
||||
(doom--package-at-point)
|
||||
(when-let (str (doom--package-to-bump-string package plist))
|
||||
(goto-char beg)
|
||||
(delete-region beg end)
|
||||
(insert str))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bumpify-packages-in-buffer ()
|
||||
"Convert all `package!' calls in buffer into bump strings."
|
||||
(interactive)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (search-forward "(package!" nil t)
|
||||
(unless (doom-point-in-string-or-comment-p)
|
||||
(doom/bumpify-package-at-point)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bump-package-at-point (&optional select)
|
||||
"Inserts or updates a `:pin' for the `package!' statement at point.
|
||||
Grabs the latest commit id of the package using 'git'."
|
||||
(interactive "P")
|
||||
(doom-initialize-packages)
|
||||
(cl-destructuring-bind (&key package plist beg end)
|
||||
(or (doom--package-at-point)
|
||||
(user-error "Not on a `package!' call"))
|
||||
(let* ((recipe (doom--package-full-recipe package plist))
|
||||
(branch (or (plist-get recipe :branch)
|
||||
straight-vc-git-default-branch))
|
||||
(oldid (or (plist-get plist :pin)
|
||||
(doom-package-get package :pin)))
|
||||
(url (straight-vc-git--destructure recipe (upstream-repo upstream-host)
|
||||
(straight-vc-git--encode-url upstream-repo upstream-host)))
|
||||
(id (or (when url
|
||||
(cdr (doom-call-process
|
||||
"git" "ls-remote" url
|
||||
(unless select
|
||||
(or branch straight-vc-git-default-branch)))))
|
||||
(user-error "Couldn't find a recipe for %s" package)))
|
||||
(id (car (split-string
|
||||
(if select
|
||||
(completing-read "Commit: " (split-string id "\n" t))
|
||||
id)))))
|
||||
(when (and oldid
|
||||
(plist-member plist :pin)
|
||||
(equal oldid id))
|
||||
(user-error "%s: no update necessary" package))
|
||||
(save-excursion
|
||||
(if (re-search-forward ":pin +\"\\([^\"]+\\)\"" end t)
|
||||
(replace-match id t t nil 1)
|
||||
(goto-char (1- end))
|
||||
(insert " :pin " (prin1-to-string id))))
|
||||
(cond ((not oldid)
|
||||
(message "%s: → %s" package (substring id 0 10)))
|
||||
((< (length oldid) (length id))
|
||||
(message "%s: extended to %s..." package id))
|
||||
((message "%s: %s → %s"
|
||||
package
|
||||
(substring oldid 0 10)
|
||||
(substring id 0 10)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bump-packages-in-buffer (&optional select)
|
||||
"Inserts or updates a `:pin' for the `package!' statement at point.
|
||||
Grabs the latest commit id of the package using 'git'."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(doom-initialize-packages)
|
||||
(let (packages)
|
||||
(while (search-forward "(package! " nil t)
|
||||
(unless (let ((ppss (syntax-ppss)))
|
||||
(or (nth 4 ppss)
|
||||
(nth 3 ppss)
|
||||
(save-excursion
|
||||
(and (goto-char (match-beginning 0))
|
||||
(not (plist-member (sexp-at-point) :pin))))))
|
||||
(condition-case e
|
||||
(push (doom/bump-package-at-point) packages)
|
||||
(user-error (message "%s" (error-message-string e))))))
|
||||
(if packages
|
||||
(message "Updated %d packages\n- %s" (length packages) (string-join packages "\n- "))
|
||||
(message "No packages to update")))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bump-module (category &optional module select)
|
||||
"Bump packages in CATEGORY MODULE.
|
||||
If SELECT (prefix arg) is non-nil, prompt you to choose a specific commit for
|
||||
each package."
|
||||
(interactive
|
||||
(let* ((module (completing-read
|
||||
"Bump module: "
|
||||
(let ((modules (doom-module-list 'all)))
|
||||
(mapcar (lambda (m)
|
||||
(if (listp m)
|
||||
(format "%s %s" (car m) (cdr m))
|
||||
(format "%s" m)))
|
||||
(append '(:private :core)
|
||||
(delete-dups (mapcar #'car modules))
|
||||
modules)))
|
||||
nil t nil nil))
|
||||
(module (split-string module " " t)))
|
||||
(list (intern (car module))
|
||||
(ignore-errors (intern (cadr module)))
|
||||
current-prefix-arg)))
|
||||
(mapc (fn! ((cat . mod))
|
||||
(if-let (packages-file
|
||||
(pcase cat
|
||||
(:private (doom-glob doom-private-dir "packages.el"))
|
||||
(:core (doom-glob doom-core-dir "packages.el"))
|
||||
(_ (doom-module-locate-path cat mod "packages.el"))))
|
||||
(with-current-buffer
|
||||
(or (get-file-buffer packages-file)
|
||||
(find-file-noselect packages-file))
|
||||
(doom/bump-packages-in-buffer select)
|
||||
(save-buffer))
|
||||
(message "Module %s has no packages.el file" (cons cat mod))))
|
||||
(if module
|
||||
(list (cons category module))
|
||||
(cl-remove-if-not (lambda (m) (eq (car m) category))
|
||||
(append '((:core) (:private))
|
||||
(doom-module-list 'all))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/bump-package (package)
|
||||
"Bump PACKAGE in all modules that install it."
|
||||
(interactive
|
||||
(list (completing-read "Bump package: "
|
||||
(mapcar #'car (doom-package-list 'all)))))
|
||||
(let* ((packages (doom-package-list 'all))
|
||||
(modules (plist-get (alist-get package packages) :modules)))
|
||||
(unless modules
|
||||
(user-error "This package isn't installed by any Doom module"))
|
||||
(dolist (module modules)
|
||||
(when-let (packages-file (doom-module-locate-path (car module) (cdr module)))
|
||||
(doom/bump-module (car module) (cdr module))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Bump commits
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/commit-bumps ()
|
||||
(interactive))
|
||||
|
||||
@@ -35,24 +35,6 @@ list, the pair is destructured into (CAR . CDR)."
|
||||
"Delete PROP from PLIST in-place."
|
||||
`(setq ,plist (doom-plist-delete ,plist ,prop)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro with-plist! (plist props &rest body)
|
||||
"With props bound from PLIST to PROPS, evaluate BODY.
|
||||
|
||||
PROPS is a list of symbols. Each one is converted to a keyword and then its
|
||||
value is looked up in the PLIST and bound to the symbol for the duration of
|
||||
BODY."
|
||||
(declare (indent 2))
|
||||
(let ((plist-sym (make-symbol "plist")))
|
||||
`(let* ((,plist-sym ,plist)
|
||||
,@(cl-loop for prop in props
|
||||
collect
|
||||
`(,prop
|
||||
(plist-get
|
||||
,plist-sym
|
||||
,(doom-keyword-intern (symbol-name prop))))))
|
||||
,@body)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
@@ -66,7 +48,7 @@ BODY."
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-plist-merge (from-plist to-plist)
|
||||
"Destructively merge FROM-PLIST onto TO-PLIST"
|
||||
"Non-destructively merge FROM-PLIST onto TO-PLIST"
|
||||
(let ((plist (copy-sequence from-plist)))
|
||||
(while plist
|
||||
(plist-put! to-plist (pop plist) (pop plist)))
|
||||
@@ -83,11 +65,11 @@ BODY."
|
||||
p))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-plist-delete (plist prop)
|
||||
"Delete PROP from a copy of PLIST."
|
||||
(defun doom-plist-delete (plist &rest props)
|
||||
"Delete PROPS from a copy of PLIST."
|
||||
(let (p)
|
||||
(while plist
|
||||
(if (not (eq prop (car plist)))
|
||||
(if (not (memq (car plist) props))
|
||||
(plist-put! p (car plist) (nth 1 plist)))
|
||||
(setq plist (cddr plist)))
|
||||
p))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
;;; core/autoload/projects.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar projectile-project-root nil)
|
||||
(defvar projectile-enable-caching)
|
||||
(defvar projectile-require-project-root)
|
||||
|
||||
;;;###autoload (autoload 'projectile-relevant-known-projects "projectile")
|
||||
|
||||
@@ -39,8 +41,7 @@ they are absolute."
|
||||
"Preforms `projectile-find-file' in a known project of your choosing."
|
||||
(interactive
|
||||
(list
|
||||
(completing-read "Find file in project: " (projectile-relevant-known-projects)
|
||||
nil nil nil nil (doom-project-root))))
|
||||
(completing-read "Find file in project: " (projectile-relevant-known-projects))))
|
||||
(unless (file-directory-p project-root)
|
||||
(error "Project directory '%s' doesn't exist" project-root))
|
||||
(doom-project-find-file project-root))
|
||||
@@ -50,8 +51,7 @@ they are absolute."
|
||||
"Preforms `find-file' in a known project of your choosing."
|
||||
(interactive
|
||||
(list
|
||||
(completing-read "Browse in project: " (projectile-relevant-known-projects)
|
||||
nil nil nil nil (doom-project-root))))
|
||||
(completing-read "Browse in project: " (projectile-relevant-known-projects))))
|
||||
(unless (file-directory-p project-root)
|
||||
(error "Project directory '%s' doesn't exist" project-root))
|
||||
(doom-project-browse project-root))
|
||||
@@ -99,11 +99,10 @@ If DIR is not a project, it will be indexed (but not cached)."
|
||||
(unless (file-readable-p dir)
|
||||
(error "Directory %S isn't readable" dir))
|
||||
(let* ((default-directory (file-truename (expand-file-name dir)))
|
||||
(project-root (doom-project-root default-directory))
|
||||
(projectile-project-root default-directory)
|
||||
(projectile-project-root (doom-project-root default-directory))
|
||||
(projectile-enable-caching projectile-enable-caching))
|
||||
(cond ((and project-root (file-equal-p project-root projectile-project-root))
|
||||
(unless (doom-project-p projectile-project-root)
|
||||
(cond ((and projectile-project-root (file-equal-p projectile-project-root default-directory))
|
||||
(unless (doom-project-p default-directory)
|
||||
;; Disable caching if this is not a real project; caching
|
||||
;; non-projects easily has the potential to inflate the projectile
|
||||
;; cache beyond reason.
|
||||
|
||||
@@ -8,9 +8,11 @@ Will be saved in `doom-scratch-dir'.")
|
||||
(defvar doom-scratch-dir (concat doom-etc-dir "scratch")
|
||||
"Where to save persistent scratch buffers.")
|
||||
|
||||
(defvar doom-scratch-buffer-major-mode nil
|
||||
"What major mode to use in scratch buffers. This can be one of the
|
||||
following:
|
||||
(defvar doom-scratch-initial-major-mode nil
|
||||
"What major mode to start fresh scratch buffers in.
|
||||
|
||||
Scratch buffers preserve their last major mode, however, so this only affects
|
||||
the first, fresh scratch buffer you create. This accepts:
|
||||
|
||||
t Inherits the major mode of the last buffer you had selected.
|
||||
nil Uses `fundamental-mode'
|
||||
@@ -21,43 +23,56 @@ following:
|
||||
|
||||
(defvar doom-scratch-current-project nil
|
||||
"The name of the project associated with the current scratch buffer.")
|
||||
(put 'doom-scratch-current-project 'permanent-local t)
|
||||
|
||||
(defvar doom-scratch-buffer-hook ()
|
||||
"The hooks to run after a scratch buffer is created.")
|
||||
|
||||
|
||||
(defun doom--load-persistent-scratch-buffer (name)
|
||||
(defun doom--load-persistent-scratch-buffer (project-name)
|
||||
(setq-local doom-scratch-current-project
|
||||
(or name
|
||||
(or project-name
|
||||
doom-scratch-default-file))
|
||||
(let ((scratch-file
|
||||
(expand-file-name doom-scratch-current-project
|
||||
(let ((smart-scratch-file
|
||||
(expand-file-name (concat doom-scratch-current-project ".el")
|
||||
doom-scratch-dir)))
|
||||
(make-directory doom-scratch-dir t)
|
||||
(when (file-readable-p scratch-file)
|
||||
(erase-buffer)
|
||||
(insert-file-contents scratch-file)
|
||||
(set-auto-mode)
|
||||
t)))
|
||||
(when (file-readable-p smart-scratch-file)
|
||||
(message "Reading %s" smart-scratch-file)
|
||||
(cl-destructuring-bind (content point mode)
|
||||
(with-temp-buffer
|
||||
(save-excursion (insert-file-contents smart-scratch-file))
|
||||
(read (current-buffer)))
|
||||
(erase-buffer)
|
||||
(funcall mode)
|
||||
(insert content)
|
||||
(goto-char point)
|
||||
t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-scratch-buffer (&optional mode directory project-name)
|
||||
(defun doom-scratch-buffer (&optional dont-restore-p mode directory project-name)
|
||||
"Return a scratchpad buffer in major MODE."
|
||||
(with-current-buffer
|
||||
(get-buffer-create (if project-name
|
||||
(format "*doom:scratch (%s)*" project-name)
|
||||
"*doom:scratch*"))
|
||||
(setq default-directory directory)
|
||||
(unless doom-scratch-current-project
|
||||
(doom--load-persistent-scratch-buffer project-name)
|
||||
(when (and (eq major-mode 'fundamental-mode)
|
||||
(functionp mode))
|
||||
(funcall mode)))
|
||||
(cl-pushnew (current-buffer) doom-scratch-buffers)
|
||||
(add-hook 'kill-buffer-hook #'doom-persist-scratch-buffer-h nil 'local)
|
||||
(add-hook 'doom-switch-buffer-hook #'doom-persist-scratch-buffers-after-switch-h)
|
||||
(run-hooks 'doom-scratch-buffer-created-hook)
|
||||
(current-buffer)))
|
||||
(let* ((buffer-name (if project-name
|
||||
(format "*doom:scratch (%s)*" project-name)
|
||||
"*doom:scratch*"))
|
||||
(buffer (get-buffer buffer-name)))
|
||||
(with-current-buffer
|
||||
(or buffer (get-buffer-create buffer-name))
|
||||
(setq default-directory directory)
|
||||
(setq-local so-long--inhibited t)
|
||||
(if dont-restore-p
|
||||
(erase-buffer)
|
||||
(unless buffer
|
||||
(doom--load-persistent-scratch-buffer project-name)
|
||||
(when (and (eq major-mode 'fundamental-mode)
|
||||
(functionp mode))
|
||||
(funcall mode))))
|
||||
(cl-pushnew (current-buffer) doom-scratch-buffers)
|
||||
(add-transient-hook! 'doom-switch-buffer-hook (doom-persist-scratch-buffers-h))
|
||||
(add-transient-hook! 'doom-switch-window-hook (doom-persist-scratch-buffers-h))
|
||||
(add-hook 'kill-buffer-hook #'doom-persist-scratch-buffer-h nil 'local)
|
||||
(run-hooks 'doom-scratch-buffer-created-hook)
|
||||
(current-buffer))))
|
||||
|
||||
|
||||
;;
|
||||
@@ -66,11 +81,18 @@ following:
|
||||
;;;###autoload
|
||||
(defun doom-persist-scratch-buffer-h ()
|
||||
"Save the current buffer to `doom-scratch-dir'."
|
||||
(write-region
|
||||
(point-min) (point-max)
|
||||
(expand-file-name (or doom-scratch-current-project
|
||||
doom-scratch-default-file)
|
||||
doom-scratch-dir)))
|
||||
(let ((content (buffer-substring-no-properties (point-min) (point-max)))
|
||||
(point (point))
|
||||
(mode major-mode))
|
||||
(with-temp-file
|
||||
(expand-file-name (concat (or doom-scratch-current-project
|
||||
doom-scratch-default-file)
|
||||
".el")
|
||||
doom-scratch-dir)
|
||||
(prin1 (list content
|
||||
point
|
||||
mode)
|
||||
(current-buffer)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-persist-scratch-buffers-h ()
|
||||
@@ -89,62 +111,66 @@ following:
|
||||
(remove-hook 'doom-switch-buffer-hook #'doom-persist-scratch-buffers-after-switch-h)))
|
||||
|
||||
;;;###autoload
|
||||
(unless noninteractive
|
||||
(when doom-interactive-p
|
||||
(add-hook 'kill-emacs-hook #'doom-persist-scratch-buffers-h))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
(defvar projectile-enable-caching)
|
||||
;;;###autoload
|
||||
(defun doom/open-scratch-buffer (&optional arg project-p)
|
||||
"Opens the (persistent) scratch buffer in a popup.
|
||||
(defun doom/open-scratch-buffer (&optional arg project-p same-window-p)
|
||||
"Pop up a persistent scratch buffer.
|
||||
|
||||
If passed the prefix ARG, switch to it in the current window.
|
||||
If passed the prefix ARG, do not restore the last scratch buffer.
|
||||
If PROJECT-P is non-nil, open a persistent scratch buffer associated with the
|
||||
current project."
|
||||
(interactive "P")
|
||||
(let (projectile-enable-caching)
|
||||
(funcall
|
||||
(if arg
|
||||
(if same-window-p
|
||||
#'switch-to-buffer
|
||||
#'pop-to-buffer)
|
||||
(doom-scratch-buffer
|
||||
(cond ((eq doom-scratch-buffer-major-mode t)
|
||||
arg
|
||||
(cond ((eq doom-scratch-initial-major-mode t)
|
||||
(unless (or buffer-read-only
|
||||
(derived-mode-p 'special-mode)
|
||||
(string-match-p "^ ?\\*" (buffer-name)))
|
||||
major-mode))
|
||||
((null doom-scratch-buffer-major-mode)
|
||||
((null doom-scratch-initial-major-mode)
|
||||
nil)
|
||||
((symbolp doom-scratch-buffer-major-mode)
|
||||
doom-scratch-buffer-major-mode))
|
||||
((symbolp doom-scratch-initial-major-mode)
|
||||
doom-scratch-initial-major-mode))
|
||||
default-directory
|
||||
(when project-p
|
||||
(doom-project-name))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/switch-to-scratch-buffer (&optional project-p)
|
||||
(defun doom/switch-to-scratch-buffer (&optional arg project-p)
|
||||
"Like `doom/open-scratch-buffer', but switches to it in the current window.
|
||||
|
||||
If passed the prefix arg, open project scratch buffer."
|
||||
If passed the prefix ARG, do not restore the last scratch buffer."
|
||||
(interactive "P")
|
||||
(doom/open-scratch-buffer t project-p))
|
||||
(doom/open-scratch-buffer arg project-p 'same-window))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/open-project-scratch-buffer (&optional current-window)
|
||||
(defun doom/open-project-scratch-buffer (&optional arg same-window-p)
|
||||
"Opens the (persistent) project scratch buffer in a popup.
|
||||
|
||||
If passed the prefix arg, switch to it in the current window."
|
||||
If passed the prefix ARG, do not restore the last scratch buffer."
|
||||
(interactive "P")
|
||||
(doom/open-scratch-buffer current-window 'project))
|
||||
(doom/open-scratch-buffer arg 'project same-window-p))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/switch-to-project-scratch-buffer ()
|
||||
(defun doom/switch-to-project-scratch-buffer (&optional arg)
|
||||
"Like `doom/open-project-scratch-buffer', but switches to it in the current
|
||||
window."
|
||||
(interactive)
|
||||
(doom/open-project-scratch-buffer t))
|
||||
window.
|
||||
|
||||
If passed the prefix ARG, do not restore the last scratch buffer."
|
||||
(interactive "P")
|
||||
(doom/open-project-scratch-buffer arg 'same-window))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/revert-scratch-buffer ()
|
||||
|
||||
@@ -47,10 +47,16 @@
|
||||
"TODO"
|
||||
(setq file (expand-file-name (or file (doom-session-file))))
|
||||
(message "Attempting to load %s" file)
|
||||
(cond ((require 'persp-mode nil t)
|
||||
(cond ((not (file-readable-p file))
|
||||
(message "No session file at %S to read from" file))
|
||||
((require 'persp-mode nil t)
|
||||
(unless persp-mode
|
||||
(persp-mode +1))
|
||||
(persp-load-state-from-file file))
|
||||
(let ((allowed (persp-list-persp-names-in-file file)))
|
||||
(cl-loop for name being the hash-keys of *persp-hash*
|
||||
unless (member name allowed)
|
||||
do (persp-kill name))
|
||||
(persp-load-state-from-file file)))
|
||||
((and (require 'frameset nil t)
|
||||
(require 'restart-emacs nil t))
|
||||
(restart-emacs--restore-frames-using-desktop file))
|
||||
@@ -65,6 +71,9 @@
|
||||
"TODO"
|
||||
(add-hook 'window-setup-hook #'doom-load-session 'append))
|
||||
|
||||
;;;###autoload
|
||||
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
@@ -124,5 +133,11 @@
|
||||
(interactive "P")
|
||||
(setq doom-autosave-session nil)
|
||||
(doom/quicksave-session)
|
||||
(restart-emacs
|
||||
(delq nil (list (if debug "--debug-init") "--restore"))))
|
||||
(save-some-buffers nil t)
|
||||
(letf! ((#'save-buffers-kill-emacs #'kill-emacs)
|
||||
(confirm-kill-emacs))
|
||||
(restart-emacs
|
||||
(append (if debug (list "--debug-init"))
|
||||
(when (boundp 'chemacs-current-emacs-profile)
|
||||
(list "--with-profile" chemacs-current-emacs-profile))
|
||||
(list "--restore")))))
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
;;; core/autoload/text.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-point-in-comment-functions ()
|
||||
"List of functions to run to determine if point is in a comment.
|
||||
|
||||
Each function takes one argument: the position of the point. Stops on the first
|
||||
function to return non-nil. Used by `doom-point-in-comment-p'.")
|
||||
|
||||
(defvar doom-point-in-string-functions ()
|
||||
"List of functions to run to determine if point is in a string.
|
||||
|
||||
Each function takes one argument: the position of the point. Stops on the first
|
||||
function to return non-nil. Used by `doom-point-in-string-p'.")
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-surrounded-p (pair &optional inline balanced)
|
||||
"Returns t if point is surrounded by a brace delimiter: {[(
|
||||
@@ -28,31 +40,18 @@ lines, above and below, with only whitespace in between."
|
||||
;;;###autoload
|
||||
(defun doom-point-in-comment-p (&optional pos)
|
||||
"Return non-nil if POS is in a comment.
|
||||
|
||||
POS defaults to the current position."
|
||||
;; REVIEW Should we cache `syntax-ppss'?
|
||||
(let* ((pos (or pos (point)))
|
||||
(ppss (syntax-ppss pos)))
|
||||
(or (nth 4 ppss)
|
||||
(nth 8 ppss)
|
||||
(and (< pos (point-max))
|
||||
(memq (char-syntax (char-after pos)) '(?< ?>))
|
||||
(not (eq (char-after pos) ?\n)))
|
||||
(when-let (s (car (syntax-after pos)))
|
||||
(or (and (/= 0 (logand (lsh 1 16) s))
|
||||
(nth 4 (doom-syntax-ppss (+ pos 2))))
|
||||
(and (/= 0 (logand (lsh 1 17) s))
|
||||
(nth 4 (doom-syntax-ppss (+ pos 1))))
|
||||
(and (/= 0 (logand (lsh 1 18) s))
|
||||
(nth 4 (doom-syntax-ppss (- pos 1))))
|
||||
(and (/= 0 (logand (lsh 1 19) s))
|
||||
(nth 4 (doom-syntax-ppss (- pos 2)))))))))
|
||||
(let ((pos (or pos (point))))
|
||||
(or (run-hook-with-args-until-success 'doom-point-in-comment-functions pos)
|
||||
(sp-point-in-comment pos))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-point-in-string-p (&optional pos)
|
||||
"Return non-nil if POS is in a string."
|
||||
;; REVIEW Should we cache `syntax-ppss'?
|
||||
(nth 3 (syntax-ppss pos)))
|
||||
(let ((pos (or pos (point))))
|
||||
(or (run-hook-with-args-until-success 'doom-point-in-string-functions pos)
|
||||
(sp-point-in-string pos))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-point-in-string-or-comment-p (&optional pos)
|
||||
@@ -60,74 +59,157 @@ POS defaults to the current position."
|
||||
(or (doom-point-in-string-p pos)
|
||||
(doom-point-in-comment-p pos)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-region-active-p ()
|
||||
"Return non-nil if selection is active.
|
||||
Detects evil visual mode as well."
|
||||
(declare (side-effect-free t))
|
||||
(or (use-region-p)
|
||||
(and (bound-and-true-p evil-local-mode)
|
||||
(evil-visual-state-p))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-region-beginning ()
|
||||
"Return beginning position of selection.
|
||||
Uses `evil-visual-beginning' if available."
|
||||
(declare (side-effect-free t))
|
||||
(if (bound-and-true-p evil-local-mode)
|
||||
evil-visual-beginning
|
||||
(region-beginning)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-region-end ()
|
||||
"Return end position of selection.
|
||||
Uses `evil-visual-end' if available."
|
||||
(declare (side-effect-free t))
|
||||
(if (bound-and-true-p evil-local-mode)
|
||||
evil-visual-end
|
||||
(region-end)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-thing-at-point-or-region (&optional thing prompt)
|
||||
"Grab the current selection, THING at point, or xref identifier at point.
|
||||
|
||||
Returns THING if it is a string. Otherwise, if nothing is found at point and
|
||||
PROMPT is non-nil, prompt for a string (if PROMPT is a string it'll be used as
|
||||
the prompting string). Returns nil if all else fails.
|
||||
|
||||
NOTE: Don't use THING for grabbing symbol-at-point. The xref fallback is smarter
|
||||
in some cases."
|
||||
(declare (side-effect-free t))
|
||||
(cond ((stringp thing)
|
||||
thing)
|
||||
((doom-region-active-p)
|
||||
(buffer-substring-no-properties
|
||||
(doom-region-beginning)
|
||||
(doom-region-end)))
|
||||
(thing
|
||||
(thing-at-point thing t))
|
||||
((require 'xref nil t)
|
||||
;; A little smarter than using `symbol-at-point', though in most cases,
|
||||
;; xref ends up using `symbol-at-point' anyway.
|
||||
(xref-backend-identifier-at-point (xref-find-backend)))
|
||||
(prompt
|
||||
(read-string (if (stringp prompt) prompt "")))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
(defvar doom--last-backward-pt most-positive-fixnum)
|
||||
(defun doom--bol-bot-eot-eol (&optional pos)
|
||||
(save-mark-and-excursion
|
||||
(when pos
|
||||
(goto-char pos))
|
||||
(let* ((bol (if visual-line-mode
|
||||
(save-excursion
|
||||
(beginning-of-visual-line)
|
||||
(point))
|
||||
(line-beginning-position)))
|
||||
(bot (save-excursion
|
||||
(goto-char bol)
|
||||
(skip-chars-forward " \t\r")
|
||||
(point)))
|
||||
(eol (if visual-line-mode
|
||||
(save-excursion (end-of-visual-line) (point))
|
||||
(line-end-position)))
|
||||
(eot (or (save-excursion
|
||||
(if (not comment-use-syntax)
|
||||
(progn
|
||||
(goto-char bol)
|
||||
(when (re-search-forward comment-start-skip eol t)
|
||||
(or (match-end 1) (match-beginning 0))))
|
||||
(goto-char eol)
|
||||
(while (and (doom-point-in-comment-p)
|
||||
(> (point) bol))
|
||||
(backward-char))
|
||||
(skip-chars-backward " " bol)
|
||||
(unless (or (eq (char-after) 32) (eolp))
|
||||
(forward-char))
|
||||
(point)))
|
||||
eol)))
|
||||
(list bol bot eot eol))))
|
||||
|
||||
(defvar doom--last-backward-pt nil)
|
||||
;;;###autoload
|
||||
(defun doom/backward-to-bol-or-indent ()
|
||||
(defun doom/backward-to-bol-or-indent (&optional point)
|
||||
"Jump between the indentation column (first non-whitespace character) and the
|
||||
beginning of the line. The opposite of
|
||||
`doom/forward-to-last-non-comment-or-eol'."
|
||||
(interactive)
|
||||
(let ((pt (point)))
|
||||
(cl-destructuring-bind (bol . bot)
|
||||
(save-excursion
|
||||
(beginning-of-visual-line)
|
||||
(cons (point)
|
||||
(progn (skip-chars-forward " \t\r")
|
||||
(point))))
|
||||
(interactive "^d")
|
||||
(let ((pt (or point (point))))
|
||||
(cl-destructuring-bind (bol bot _eot _eol)
|
||||
(doom--bol-bot-eot-eol pt)
|
||||
(cond ((> pt bot)
|
||||
(goto-char bot))
|
||||
((= pt bol)
|
||||
(goto-char (min doom--last-backward-pt bot))
|
||||
(setq doom--last-backward-pt most-positive-fixnum))
|
||||
(or (and doom--last-backward-pt
|
||||
(= (line-number-at-pos doom--last-backward-pt)
|
||||
(line-number-at-pos pt)))
|
||||
(setq doom--last-backward-pt nil))
|
||||
(goto-char (or doom--last-backward-pt bot))
|
||||
(setq doom--last-backward-pt nil))
|
||||
((<= pt bot)
|
||||
(setq doom--last-backward-pt pt)
|
||||
(goto-char bol))))))
|
||||
|
||||
(defvar doom--last-forward-pt -1)
|
||||
(defvar doom--last-forward-pt nil)
|
||||
;;;###autoload
|
||||
(defun doom/forward-to-last-non-comment-or-eol ()
|
||||
(defun doom/forward-to-last-non-comment-or-eol (&optional point)
|
||||
"Jumps between the last non-blank, non-comment character in the line and the
|
||||
true end of the line. The opposite of `doom/backward-to-bol-or-indent'."
|
||||
(interactive "^d")
|
||||
(let ((pt (or point (point))))
|
||||
(cl-destructuring-bind (_bol _bot eot eol)
|
||||
(doom--bol-bot-eot-eol pt)
|
||||
(cond ((< pt eot)
|
||||
(goto-char eot))
|
||||
((= pt eol)
|
||||
(goto-char (or doom--last-forward-pt eot))
|
||||
(setq doom--last-forward-pt nil))
|
||||
((>= pt eot)
|
||||
(setq doom--last-backward-pt pt)
|
||||
(goto-char eol))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/backward-kill-to-bol-and-indent ()
|
||||
"Kill line to the first non-blank character. If invoked again afterwards, kill
|
||||
line to beginning of line. Same as `evil-delete-back-to-indentation'."
|
||||
(interactive)
|
||||
(let ((eol (if (not visual-line-mode)
|
||||
(line-end-position)
|
||||
(save-excursion (end-of-visual-line) (point)))))
|
||||
(if (or (and (< (point) eol)
|
||||
(sp-point-in-comment))
|
||||
(not (sp-point-in-comment eol)))
|
||||
(if (= (point) eol)
|
||||
(progn
|
||||
(goto-char doom--last-forward-pt)
|
||||
(setq doom--last-forward-pt -1))
|
||||
(setq doom--last-forward-pt (point))
|
||||
(goto-char eol))
|
||||
(let* ((bol (save-excursion (beginning-of-visual-line) (point)))
|
||||
(boc (or (save-excursion
|
||||
(if (not comment-use-syntax)
|
||||
(progn
|
||||
(goto-char bol)
|
||||
(when (re-search-forward comment-start-skip eol t)
|
||||
(or (match-end 1) (match-beginning 0))))
|
||||
(goto-char eol)
|
||||
(while (and (sp-point-in-comment)
|
||||
(> (point) bol))
|
||||
(backward-char))
|
||||
(skip-chars-backward " " bol)
|
||||
(point)))
|
||||
eol)))
|
||||
(when (> doom--last-forward-pt boc)
|
||||
(setq boc doom--last-forward-pt))
|
||||
(if (or (= eol (point))
|
||||
(> boc (point)))
|
||||
(progn
|
||||
(goto-char boc)
|
||||
(setq doom--last-forward-pt -1))
|
||||
(setq doom--last-forward-pt (point))
|
||||
(goto-char eol))))))
|
||||
(let ((empty-line-p (save-excursion (beginning-of-line)
|
||||
(looking-at-p "[ \t]*$"))))
|
||||
(funcall (if (fboundp 'evil-delete)
|
||||
#'evil-delete
|
||||
#'delete-region)
|
||||
(point-at-bol) (point))
|
||||
(unless empty-line-p
|
||||
(indent-according-to-mode))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/delete-backward-word (arg)
|
||||
"Like `backward-kill-word', but doesn't affect the kill-ring."
|
||||
(interactive "p")
|
||||
(let (kill-ring)
|
||||
(backward-kill-word arg)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/dumb-indent ()
|
||||
@@ -155,20 +237,6 @@ true end of the line. The opposite of `doom/backward-to-bol-or-indent'."
|
||||
tab-width
|
||||
(- tab-width movement)))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/backward-kill-to-bol-and-indent ()
|
||||
"Kill line to the first non-blank character. If invoked again
|
||||
afterwards, kill line to beginning of line."
|
||||
(interactive)
|
||||
(let ((empty-line-p (save-excursion (beginning-of-line)
|
||||
(looking-at-p "[ \t]*$"))))
|
||||
(funcall (if (fboundp 'evil-delete)
|
||||
#'evil-delete
|
||||
#'delete-region)
|
||||
(point-at-bol) (point))
|
||||
(unless empty-line-p
|
||||
(indent-according-to-mode))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/retab (arg &optional beg end)
|
||||
"Converts tabs-to-spaces or spaces-to-tabs within BEG and END (defaults to
|
||||
@@ -192,15 +260,9 @@ opposite indentation style."
|
||||
|
||||
Respects `require-final-newline'."
|
||||
(interactive)
|
||||
(goto-char (point-max))
|
||||
(skip-chars-backward " \t\n\v")
|
||||
(when (looking-at "\n\\(\n\\|\\'\\)")
|
||||
(forward-char 1))
|
||||
(when require-final-newline
|
||||
(unless (bolp)
|
||||
(insert "\n")))
|
||||
(when (looking-at "\n+")
|
||||
(replace-match "")))
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(delete-blank-lines)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/dos2unix ()
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
`((,(car spec) ((t ,(cdr spec))))))
|
||||
(`((,(car spec) ,(cdr spec))))))
|
||||
|
||||
;;;###autoload
|
||||
(defconst doom-customize-theme-hook nil)
|
||||
|
||||
(add-hook! 'doom-load-theme-hook :append
|
||||
(defun doom-apply-customized-faces-h ()
|
||||
(run-hooks 'doom-customize-theme-hook)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro custom-theme-set-faces! (theme &rest specs)
|
||||
"Apply a list of face SPECS as user customizations for THEME.
|
||||
@@ -16,26 +23,27 @@
|
||||
THEME can be a single symbol or list thereof. If nil, apply these settings to
|
||||
all themes. It will apply to all themes once they are loaded."
|
||||
(declare (indent defun))
|
||||
`(let ((fn (gensym "doom--customize-themes-h-")))
|
||||
(fset
|
||||
fn (lambda ()
|
||||
(let (custom--inhibit-theme-enable)
|
||||
(dolist (theme (doom-enlist (or ,theme 'user)))
|
||||
(when (or (eq theme 'user)
|
||||
(custom-theme-enabled-p theme))
|
||||
(apply #'custom-theme-set-faces theme
|
||||
(mapcan #'doom--custom-theme-set-face
|
||||
(list ,@specs))))))))
|
||||
(when (or doom-init-theme-p (null doom-theme))
|
||||
(funcall fn))
|
||||
(add-hook 'doom-load-theme-hook fn 'append)))
|
||||
(let ((fn (gensym "doom--customize-themes-h-")))
|
||||
`(progn
|
||||
(defun ,fn ()
|
||||
(let (custom--inhibit-theme-enable)
|
||||
(dolist (theme (doom-enlist (or ,theme 'user)))
|
||||
(when (or (eq theme 'user)
|
||||
(custom-theme-enabled-p theme))
|
||||
(apply #'custom-theme-set-faces theme
|
||||
(mapcan #'doom--custom-theme-set-face
|
||||
(list ,@specs)))))))
|
||||
(when (or doom-init-theme-p (null doom-theme))
|
||||
(funcall #',fn))
|
||||
(add-hook 'doom-customize-theme-hook #',fn 'append))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro custom-set-faces! (&rest specs)
|
||||
"Apply a list of face SPECS as user customizations.
|
||||
|
||||
This is a drop-in replacement for `custom-set-face' that allows for a simplified
|
||||
face format."
|
||||
This is a convenience macro alternative to `custom-set-face' which allows for a
|
||||
simplified face format, and takes care of load order issues, so you can use
|
||||
doom-themes' API without worry."
|
||||
(declare (indent defun))
|
||||
`(custom-theme-set-faces! 'user ,@specs))
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
;;; core/autoload/ui.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;; Public library
|
||||
;;; Public library
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-resize-window (window new-size &optional horizontal force-p)
|
||||
@@ -24,13 +24,23 @@ are open."
|
||||
|
||||
|
||||
;;
|
||||
;; Advice
|
||||
;;; Advice
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-recenter-a (&rest _)
|
||||
"Generic advisor for recentering window (typically :after other functions)."
|
||||
"Generic advice for recentering window (typically :after other functions)."
|
||||
(recenter))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-preserve-window-position-a (orig-fn &rest args)
|
||||
"Generic advice for preserving cursor position on screen after scrolling."
|
||||
(let ((row (cdr (posn-col-row (posn-at-point)))))
|
||||
(prog1 (apply orig-fn args)
|
||||
(save-excursion
|
||||
(let ((target-row (- (line-number-at-pos) row)))
|
||||
(unless (< target-row 0)
|
||||
(evil-scroll-line-to-top target-row)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-shut-up-a (orig-fn &rest args)
|
||||
"Generic advisor for silencing noisy functions.
|
||||
@@ -43,7 +53,7 @@ In tty Emacs, messages suppressed completely."
|
||||
|
||||
|
||||
;;
|
||||
;; Hooks
|
||||
;;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-apply-ansi-color-to-compilation-buffer-h ()
|
||||
@@ -57,9 +67,17 @@ In tty Emacs, messages suppressed completely."
|
||||
"Turn off `show-paren-mode' buffer-locally."
|
||||
(setq-local show-paren-mode nil))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-enable-line-numbers-h ()
|
||||
(display-line-numbers-mode +1))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-disable-line-numbers-h ()
|
||||
(display-line-numbers-mode -1))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
;;; Commands
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/toggle-line-numbers ()
|
||||
@@ -87,7 +105,7 @@ See `display-line-numbers' for what these values mean."
|
||||
(_ (symbol-name next))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/delete-frame ()
|
||||
(defun doom/delete-frame-with-prompt ()
|
||||
"Delete the current frame, but ask for confirmation if it isn't empty."
|
||||
(interactive)
|
||||
(if (cdr (frame-list))
|
||||
@@ -95,6 +113,7 @@ See `display-line-numbers' for what these values mean."
|
||||
(delete-frame))
|
||||
(save-buffers-kill-emacs)))
|
||||
|
||||
(defvar doom--maximize-last-wconf nil)
|
||||
;;;###autoload
|
||||
(defun doom/window-maximize-buffer ()
|
||||
"Close other windows to focus on this one. Activate again to undo this. If the
|
||||
@@ -102,41 +121,40 @@ window changes before then, the undo expires.
|
||||
|
||||
Alternatively, use `doom/window-enlargen'."
|
||||
(interactive)
|
||||
(if (and (one-window-p)
|
||||
(assq ?_ register-alist))
|
||||
(jump-to-register ?_)
|
||||
(when (and (bound-and-true-p +popup-mode)
|
||||
(+popup-window-p))
|
||||
(user-error "Cannot maximize a popup, use `+popup/raise' first or use `doom/window-enlargen' instead"))
|
||||
(window-configuration-to-register ?_)
|
||||
(delete-other-windows)))
|
||||
(setq doom--maximize-last-wconf
|
||||
(if (and (null (cdr (cl-remove-if #'window-dedicated-p (window-list))))
|
||||
doom--maximize-last-wconf)
|
||||
(ignore (set-window-configuration doom--maximize-last-wconf))
|
||||
(when (and (bound-and-true-p +popup-mode)
|
||||
(+popup-window-p))
|
||||
(user-error "Cannot maximize a popup, use `+popup/raise' first or use `doom/window-enlargen' instead"))
|
||||
(prog1 (current-window-configuration)
|
||||
(delete-other-windows)))))
|
||||
|
||||
(defvar doom--window-enlargened nil)
|
||||
(defvar doom--enlargen-last-wconf nil)
|
||||
;;;###autoload
|
||||
(defun doom/window-enlargen ()
|
||||
"Enlargen the current window to focus on this one. Does not close other
|
||||
windows (unlike `doom/window-maximize-buffer') Activate again to undo."
|
||||
windows (unlike `doom/window-maximize-buffer'). Activate again to undo."
|
||||
(interactive)
|
||||
(setq doom--window-enlargened
|
||||
(if (and doom--window-enlargened
|
||||
(assq ?_ register-alist))
|
||||
(ignore (ignore-errors (jump-to-register ?_)))
|
||||
(window-configuration-to-register ?_)
|
||||
(let* ((window (selected-window))
|
||||
(dedicated-p (window-dedicated-p window))
|
||||
(preserved-p (window-parameter window 'window-preserved-size))
|
||||
(ignore-window-parameters t))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(when dedicated-p
|
||||
(set-window-dedicated-p window nil))
|
||||
(when preserved-p
|
||||
(set-window-parameter window 'window-preserved-size nil))
|
||||
(maximize-window window))
|
||||
(set-window-dedicated-p window dedicated-p)
|
||||
(when preserved-p
|
||||
(set-window-parameter window 'window-preserved-size preserved-p)))
|
||||
t))))
|
||||
(setq doom--enlargen-last-wconf
|
||||
(if doom--enlargen-last-wconf
|
||||
(ignore (set-window-configuration doom--enlargen-last-wconf))
|
||||
(prog1 (current-window-configuration)
|
||||
(let* ((window (selected-window))
|
||||
(dedicated-p (window-dedicated-p window))
|
||||
(preserved-p (window-parameter window 'window-preserved-size))
|
||||
(ignore-window-parameters t))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(when dedicated-p
|
||||
(set-window-dedicated-p window nil))
|
||||
(when preserved-p
|
||||
(set-window-parameter window 'window-preserved-size nil))
|
||||
(maximize-window window))
|
||||
(set-window-dedicated-p window dedicated-p)
|
||||
(when preserved-p
|
||||
(set-window-parameter window 'window-preserved-size preserved-p))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/window-maximize-horizontally ()
|
||||
|
||||
Reference in New Issue
Block a user