Add and expand doom/help* commands
Adds the following commands: - doom/help (opens the Doom manual) - doom/help-search (for searching through org headlines in Doom's documentation) - doom/help-faq (for searching the FAQ) - doom/help-news (for browsing the Doom newsletters) - doom/help-autodefs (renamed from doom/describe-autodef -- for looking up documentation on autodef function/macros, like `set-lookup-handler!`) - doom/help-modules (renamed from doom/describe-module, for jumping to a Doom module's documentation) - doom/help-packages (renamed from doom/describe-package and recently fixed -- looks up information about installed packages, including what Doom module(s) install it and where it is configured) - doom/help-package-config (for searching and jumping to any block where a package is configured in Doom Emacs) Also adds the SPC h d (or C-h d) prefix for Doom-specific help commands. SPC h D will invoke doom/help. However, the documentation itself hasn't been committed yet, so some of these commands may be useless atm. Sorry!
This commit is contained in:
parent
5df4a2f18e
commit
fa7f7042b0
3 changed files with 227 additions and 112 deletions
|
@ -1,7 +1,8 @@
|
|||
;;; core/autoload/help.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom--module-mode-alist
|
||||
(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)
|
||||
|
@ -27,12 +28,14 @@
|
|||
(go-mode :lang go)
|
||||
(haskell-mode :lang haskell)
|
||||
(hy-mode :lang hy)
|
||||
(idris-mode :lang idris)
|
||||
(java-mode :lang java)
|
||||
(js2-mode :lang javascript)
|
||||
(rjsx-mode :lang javascript)
|
||||
(typescript-mode :lang javascript)
|
||||
(coffee-mode :lang javascript)
|
||||
(julia-mode :lang julia)
|
||||
(kotlin-mode :lang kotlin)
|
||||
(latex-mode :lang latex)
|
||||
(LaTeX-mode :lang latex)
|
||||
(ledger-mode :lang ledger)
|
||||
|
@ -61,12 +64,14 @@
|
|||
(scss-mode :lang web)
|
||||
(sass-mode :lang web)
|
||||
(less-css-mode :lang web)
|
||||
(stylus-mode :lang web))
|
||||
(stylus-mode :lang web)
|
||||
(terra-mode :lang terra)
|
||||
(vala-mode :lang vala))
|
||||
"TODO")
|
||||
|
||||
|
||||
;;
|
||||
;; Helpers
|
||||
;;; Helpers
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-active-minor-modes ()
|
||||
|
@ -77,16 +82,131 @@
|
|||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
;;; Custom describe commands
|
||||
|
||||
;;;###autoload (defalias 'doom/describe-autodefs #'doom/help-autodefs)
|
||||
;;;###autoload (defalias 'doom/describe-module #'doom/help-modules)
|
||||
;;;###autoload (defalias 'doom/describe-package #'doom/help-packages)
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/describe-autodefs (autodef)
|
||||
"Open the documentation of Doom autodefs.
|
||||
(defun doom/describe-active-minor-mode (mode)
|
||||
"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))))
|
||||
(describe-minor-mode-from-symbol
|
||||
(cond ((stringp mode) (intern mode))
|
||||
((symbolp mode) mode)
|
||||
((error "Expected a symbol/string, got a %s" (type-of mode))))))
|
||||
|
||||
What is an autodef? It's a function or macro that is always defined, even if its
|
||||
containing module is disabled (in which case it will safely no-op). This
|
||||
syntactic sugar lets you use them without needing to check if they are
|
||||
available."
|
||||
;;;###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
|
||||
|
||||
(defun doom--org-headings (files &optional depth prompt include-files)
|
||||
(let ((org-agenda-files (doom-enlist files))
|
||||
(default-directory doom-docs-dir))
|
||||
(unwind-protect
|
||||
(delq nil
|
||||
(org-map-entries
|
||||
(lambda ()
|
||||
(let* ((components (org-heading-components))
|
||||
(path (org-get-outline-path))
|
||||
(level (nth 0 components))
|
||||
(text (nth 4 components))
|
||||
(tags (nth 5 components)))
|
||||
(when (and (or (not depth)
|
||||
(and (integerp depth)
|
||||
(<= level depth)))
|
||||
(or (not tags)
|
||||
(not (string-match-p ":TOC" tags))))
|
||||
(list
|
||||
(mapconcat
|
||||
'identity
|
||||
(list (mapconcat 'identity
|
||||
(append (when include-files
|
||||
(list (or (+org-get-property "TITLE")
|
||||
(file-relative-name buffer-file-name))))
|
||||
path
|
||||
(list text))
|
||||
" > ")
|
||||
tags)
|
||||
" ")
|
||||
buffer-file-name
|
||||
(point)))))
|
||||
nil
|
||||
'agenda))
|
||||
(mapc #'kill-buffer org-agenda-new-buffers)
|
||||
(setq org-agenda-new-buffers nil))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help ()
|
||||
"Open Doom's user manual."
|
||||
(interactive)
|
||||
(find-file (expand-file-name "index.org" doom-docs-dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-search ()
|
||||
"Search Doom's documentation and jump to a headline."
|
||||
(interactive)
|
||||
(let (ivy-sort-functions-alist)
|
||||
(completing-read "Find in Doom help: "
|
||||
(doom--org-headings (list "getting_started.org"
|
||||
"contributing.org"
|
||||
"troubleshooting.org"
|
||||
"tutorials.org"
|
||||
"faq.org")
|
||||
2 nil t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-faq ()
|
||||
"Search Doom's FAQ and jump to a question."
|
||||
(interactive)
|
||||
(completing-read "Find in FAQ: "
|
||||
(doom--org-headings (list "faq.org"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-news ()
|
||||
"Open a Doom newsletter.
|
||||
The latest newsletter will be selected by default."
|
||||
(interactive)
|
||||
(let* ((default-directory (expand-file-name "news/" doom-docs-dir))
|
||||
(news-files (doom-files-in default-directory)))
|
||||
(find-file
|
||||
(read-file-name (format "Open Doom newsletter (current: v%s): "
|
||||
doom-version)
|
||||
default-directory
|
||||
(if (member doom-version news-files)
|
||||
doom-version
|
||||
(concat (mapconcat #'number-to-string
|
||||
(nbutlast (version-to-list doom-version) 1)
|
||||
".")
|
||||
".x"))
|
||||
t doom-version))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/help-autodefs (autodef)
|
||||
"Open the documentation of an autodef.
|
||||
|
||||
An autodef is a Doom concept. It is a function or macro that is always defined,
|
||||
whether or not its containing module is disabled (in which case it will safely
|
||||
no-op). This syntactic sugar lets you use them without needing to check if they
|
||||
are available."
|
||||
(interactive
|
||||
(let* ((settings
|
||||
(cl-loop with case-fold-search = nil
|
||||
|
@ -133,26 +253,15 @@ available."
|
|||
(describe-function fn))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/describe-active-minor-mode (mode)
|
||||
"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))))
|
||||
(describe-minor-mode-from-symbol
|
||||
(cond ((stringp mode) (intern mode))
|
||||
((symbolp mode) mode)
|
||||
((error "Expected a symbol/string, got a %s" (type-of mode))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/describe-module (category module)
|
||||
"Open the documentation of CATEGORY MODULE.
|
||||
(defun doom/help-modules (category module)
|
||||
"Open the documentation for a Doom module.
|
||||
|
||||
CATEGORY is a keyword and MODULE is a symbol. e.g. :editor and 'evil.
|
||||
|
||||
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
|
||||
`doom--module-mode-alist')."
|
||||
`doom--help-major-mode-module-alist')."
|
||||
(interactive
|
||||
(let* ((module
|
||||
(cond ((and buffer-file-name
|
||||
|
@ -173,7 +282,7 @@ current file is in, or d) the module associated with the current major mode (see
|
|||
((and buffer-file-name
|
||||
(when-let* ((mod (doom-module-from-path buffer-file-name)))
|
||||
(format "%s %s" (car mod) (cdr mod)))))
|
||||
((when-let* ((mod (cdr (assq major-mode doom--module-mode-alist))))
|
||||
((when-let* ((mod (cdr (assq major-mode doom--help-major-mode-module-alist))))
|
||||
(format "%s %s"
|
||||
(symbol-name (car mod))
|
||||
(symbol-name (cadr mod)))))))
|
||||
|
@ -185,7 +294,7 @@ current file is in, or d) the module associated with the current major mode (see
|
|||
for format = (format "%s %s" cat mod)
|
||||
if (doom-module-p cat mod)
|
||||
collect format
|
||||
else
|
||||
else if (and cat mod)
|
||||
collect (propertize format 'face 'font-lock-comment-face))
|
||||
nil t nil nil module))
|
||||
(key (split-string module-string " ")))
|
||||
|
@ -203,6 +312,10 @@ current file is in, or d) the module associated with the current major mode (see
|
|||
(doom-project-browse path)
|
||||
(user-error "Aborted module lookup")))))
|
||||
|
||||
|
||||
;;
|
||||
;;; `doom/help-packages'
|
||||
|
||||
(defun doom--describe-package-insert-button (label path &optional regexp)
|
||||
(declare (indent defun))
|
||||
(insert-text-button
|
||||
|
@ -223,49 +336,61 @@ current file is in, or d) the module associated with the current major mode (see
|
|||
(recenter)
|
||||
(message "Couldn't find the config block"))))))))
|
||||
|
||||
;;;###autoload
|
||||
(global-set-key [remap describe-package] #'doom/describe-package)
|
||||
(defun doom--completing-package (&optional prompt refresh)
|
||||
(let* (guess
|
||||
(sym (symbol-at-point))
|
||||
(package-list (or (unless refresh (doom-cache-get 'help-packages))
|
||||
(doom-cache-set 'help-packages (doom-package-list 'all))))
|
||||
(pkg-alist (seq-group-by #'car package-list))
|
||||
(packages
|
||||
;; TODO Refactor me
|
||||
(cl-loop for (pkg . descs) in (cl-sort pkg-alist #'string-lessp :key #'car)
|
||||
for str =
|
||||
(format "%-40s %s"
|
||||
pkg
|
||||
(cl-loop for (desc . plist) in descs
|
||||
for module = (car (plist-get plist :modules))
|
||||
collect
|
||||
(format "%s%s"
|
||||
(car module)
|
||||
(if (cdr module) (format " %s" (cdr module)) ""))
|
||||
into modules
|
||||
finally return
|
||||
(propertize (string-join modules ", ")
|
||||
'face 'font-lock-comment-face)))
|
||||
collect str
|
||||
and do
|
||||
(when (eq pkg sym)
|
||||
(setq guess str)))))
|
||||
(intern
|
||||
(car (split-string
|
||||
(completing-read
|
||||
(or prompt
|
||||
(if guess
|
||||
(format "Describe package (default %s): "
|
||||
(car (split-string guess " ")))
|
||||
"Describe package: "))
|
||||
packages nil t nil nil
|
||||
(if guess guess))
|
||||
" ")))))
|
||||
|
||||
(defvar doom--describe-package-list-cache nil)
|
||||
;;;###autoload
|
||||
(defun doom/describe-package (package)
|
||||
"Like `describe-packages', but is Doom aware.
|
||||
(defun doom/help-packages (package)
|
||||
"Like `describe-package', but for packages installed by Doom modules.
|
||||
|
||||
Only shows installed packages. Includes information about where packages are
|
||||
defined and configured.
|
||||
|
||||
If prefix arg is prsent, refresh the cache."
|
||||
If prefix arg is present, refresh the cache."
|
||||
(interactive
|
||||
(list
|
||||
(let* ((guess (or (function-called-at-point)
|
||||
(symbol-at-point))))
|
||||
(require 'finder-inf nil t)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)
|
||||
(let ((packages
|
||||
(or (unless current-prefix-arg doom--describe-package-list-cache)
|
||||
(cl-loop for pkg
|
||||
in (cl-delete-duplicates
|
||||
(sort (append (mapcar #'car package-alist)
|
||||
(mapcar #'car package-archive-contents)
|
||||
(mapcar #'car package--builtins))
|
||||
#'string-greaterp))
|
||||
if (assq pkg package-alist)
|
||||
collect (symbol-name pkg)
|
||||
else
|
||||
collect (propertize (symbol-name pkg) 'face 'font-lock-comment-face)))))
|
||||
(unless (memq guess packages)
|
||||
(setq guess nil))
|
||||
(setq doom--describe-package-list-cache packages)
|
||||
(intern
|
||||
(completing-read
|
||||
(if guess
|
||||
(format "Describe package (default %s): "
|
||||
guess)
|
||||
"Describe package: ")
|
||||
packages nil t nil nil
|
||||
(if guess (symbol-name guess))))))))
|
||||
(describe-package package)
|
||||
(list (doom--completing-package nil current-prefix-arg)))
|
||||
(if (or (package-desc-p package)
|
||||
(and (symbolp package)
|
||||
(or (assq package package-alist)
|
||||
(assq package package-archive-contents)
|
||||
(assq package package--builtins))))
|
||||
(describe-package package)
|
||||
(doom--describe-package package))
|
||||
(save-excursion
|
||||
(with-current-buffer (help-buffer)
|
||||
(let ((inhibit-read-only t))
|
||||
|
@ -275,7 +400,7 @@ If prefix arg is prsent, refresh the cache."
|
|||
(end-of-line)
|
||||
(let ((indent (make-string (length (match-string 0)) ? )))
|
||||
(insert "\n" indent "Installed by the following Doom modules:\n")
|
||||
(dolist (m (get package 'doom-module))
|
||||
(dolist (m (doom-package-prop package :modules))
|
||||
(insert indent)
|
||||
(doom--describe-package-insert-button
|
||||
(format " %s %s" (car m) (or (cdr m) ""))
|
||||
|
@ -293,45 +418,25 @@ If prefix arg is prsent, refresh the cache."
|
|||
(insert "\n")
|
||||
|
||||
(package--print-help-section "Configs")
|
||||
(dolist (file (get package 'doom-files))
|
||||
(doom--describe-package-insert-button
|
||||
(abbreviate-file-name file)
|
||||
file
|
||||
(format "\\((\\(:?after!\\|def-package!\\)[ \t\n]*%s\\|^[ \t]*;; `%s'$\\)"
|
||||
package package))
|
||||
(insert "\n" indent))
|
||||
(delete-char -1)))))))
|
||||
(insert-text-button
|
||||
"See where this package is configured"
|
||||
'face 'link
|
||||
'follow-link t
|
||||
'action
|
||||
`(lambda (_) (doom/help-package-config ',package)))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/describe-symbol (symbol)
|
||||
"Show help for SYMBOL, a variable, function or macro."
|
||||
(defun doom/help-package-config (package)
|
||||
"Jump to a configuration block for PACKAGE."
|
||||
(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))))))
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'doom/help 'doom/open-manual)
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/open-manual ()
|
||||
"TODO"
|
||||
(interactive)
|
||||
(user-error "This command isn't implemented yet")
|
||||
;; (find-file (expand-file-name "index.org" doom-docs-dir))
|
||||
)
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/open-news ()
|
||||
"TODO"
|
||||
(interactive)
|
||||
(user-error "This command isn't implemented yet")
|
||||
;; (find-file (expand-file-name (concat "news/" doom-version) doom-docs-dir))
|
||||
)
|
||||
(list (doom--completing-package "Select package to search for: " current-prefix-arg)))
|
||||
(let* ((default-directory doom-emacs-dir)
|
||||
(results (shell-command-to-string
|
||||
(format "git grep --no-break --no-heading --line-number '%s %s\\($\\| \\)'"
|
||||
"\\(^;;;###package\\|(after!\\|(def-package!\\)"
|
||||
package)))
|
||||
(select (completing-read "Jump to config: " (split-string results "\n" t))))
|
||||
(cl-destructuring-bind (file line _match)
|
||||
(split-string select ":")
|
||||
(pop-to-buffer file)
|
||||
(goto-line line))))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue