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:
Henrik Lissner 2019-04-23 20:46:58 -04:00
parent 5df4a2f18e
commit fa7f7042b0
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
3 changed files with 227 additions and 112 deletions

View file

@ -1,7 +1,8 @@
;;; core/autoload/help.el -*- lexical-binding: t; -*- ;;; core/autoload/help.el -*- lexical-binding: t; -*-
(defvar doom--module-mode-alist (defvar doom--help-major-mode-module-alist
'((dockerfile-mode :tools docker) '((dockerfile-mode :tools docker)
(agda2-mode :lang agda)
(haxor-mode :lang assembly) (haxor-mode :lang assembly)
(mips-mode :lang assembly) (mips-mode :lang assembly)
(nasm-mode :lang assembly) (nasm-mode :lang assembly)
@ -27,12 +28,14 @@
(go-mode :lang go) (go-mode :lang go)
(haskell-mode :lang haskell) (haskell-mode :lang haskell)
(hy-mode :lang hy) (hy-mode :lang hy)
(idris-mode :lang idris)
(java-mode :lang java) (java-mode :lang java)
(js2-mode :lang javascript) (js2-mode :lang javascript)
(rjsx-mode :lang javascript) (rjsx-mode :lang javascript)
(typescript-mode :lang javascript) (typescript-mode :lang javascript)
(coffee-mode :lang javascript) (coffee-mode :lang javascript)
(julia-mode :lang julia) (julia-mode :lang julia)
(kotlin-mode :lang kotlin)
(latex-mode :lang latex) (latex-mode :lang latex)
(LaTeX-mode :lang latex) (LaTeX-mode :lang latex)
(ledger-mode :lang ledger) (ledger-mode :lang ledger)
@ -61,12 +64,14 @@
(scss-mode :lang web) (scss-mode :lang web)
(sass-mode :lang web) (sass-mode :lang web)
(less-css-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") "TODO")
;; ;;
;; Helpers ;;; Helpers
;;;###autoload ;;;###autoload
(defun doom-active-minor-modes () (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 ;;;###autoload
(defun doom/describe-autodefs (autodef) (defun doom/describe-active-minor-mode (mode)
"Open the documentation of Doom autodefs. "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 ;;;###autoload
containing module is disabled (in which case it will safely no-op). This (defun doom/describe-symbol (symbol)
syntactic sugar lets you use them without needing to check if they are "Show help for SYMBOL, a variable, function or macro."
available." (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 (interactive
(let* ((settings (let* ((settings
(cl-loop with case-fold-search = nil (cl-loop with case-fold-search = nil
@ -133,26 +253,15 @@ available."
(describe-function fn)))) (describe-function fn))))
;;;###autoload ;;;###autoload
(defun doom/describe-active-minor-mode (mode) (defun doom/help-modules (category module)
"Get information on an active minor mode. Use `describe-minor-mode' for a "Open the documentation for a Doom module.
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.
CATEGORY is a keyword and MODULE is a symbol. e.g. :editor and 'evil. 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 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 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 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 (interactive
(let* ((module (let* ((module
(cond ((and buffer-file-name (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 ((and buffer-file-name
(when-let* ((mod (doom-module-from-path buffer-file-name))) (when-let* ((mod (doom-module-from-path buffer-file-name)))
(format "%s %s" (car mod) (cdr mod))))) (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" (format "%s %s"
(symbol-name (car mod)) (symbol-name (car mod))
(symbol-name (cadr 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) for format = (format "%s %s" cat mod)
if (doom-module-p cat mod) if (doom-module-p cat mod)
collect format collect format
else else if (and cat mod)
collect (propertize format 'face 'font-lock-comment-face)) collect (propertize format 'face 'font-lock-comment-face))
nil t nil nil module)) nil t nil nil module))
(key (split-string module-string " "))) (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) (doom-project-browse path)
(user-error "Aborted module lookup"))))) (user-error "Aborted module lookup")))))
;;
;;; `doom/help-packages'
(defun doom--describe-package-insert-button (label path &optional regexp) (defun doom--describe-package-insert-button (label path &optional regexp)
(declare (indent defun)) (declare (indent defun))
(insert-text-button (insert-text-button
@ -223,49 +336,61 @@ current file is in, or d) the module associated with the current major mode (see
(recenter) (recenter)
(message "Couldn't find the config block")))))))) (message "Couldn't find the config block"))))))))
;;;###autoload (defun doom--completing-package (&optional prompt refresh)
(global-set-key [remap describe-package] #'doom/describe-package) (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 ;;;###autoload
(defun doom/describe-package (package) (defun doom/help-packages (package)
"Like `describe-packages', but is Doom aware. "Like `describe-package', but for packages installed by Doom modules.
Only shows installed packages. Includes information about where packages are Only shows installed packages. Includes information about where packages are
defined and configured. defined and configured.
If prefix arg is prsent, refresh the cache." If prefix arg is present, refresh the cache."
(interactive (interactive
(list (list (doom--completing-package nil current-prefix-arg)))
(let* ((guess (or (function-called-at-point) (if (or (package-desc-p package)
(symbol-at-point)))) (and (symbolp package)
(require 'finder-inf nil t) (or (assq package package-alist)
(require 'core-packages) (assq package package-archive-contents)
(doom-initialize-packages) (assq package package--builtins))))
(let ((packages (describe-package package)
(or (unless current-prefix-arg doom--describe-package-list-cache) (doom--describe-package package))
(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)
(save-excursion (save-excursion
(with-current-buffer (help-buffer) (with-current-buffer (help-buffer)
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
@ -275,7 +400,7 @@ If prefix arg is prsent, refresh the cache."
(end-of-line) (end-of-line)
(let ((indent (make-string (length (match-string 0)) ? ))) (let ((indent (make-string (length (match-string 0)) ? )))
(insert "\n" indent "Installed by the following Doom modules:\n") (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) (insert indent)
(doom--describe-package-insert-button (doom--describe-package-insert-button
(format " %s %s" (car m) (or (cdr m) "")) (format " %s %s" (car m) (or (cdr m) ""))
@ -293,45 +418,25 @@ If prefix arg is prsent, refresh the cache."
(insert "\n") (insert "\n")
(package--print-help-section "Configs") (package--print-help-section "Configs")
(dolist (file (get package 'doom-files)) (insert-text-button
(doom--describe-package-insert-button "See where this package is configured"
(abbreviate-file-name file) 'face 'link
file 'follow-link t
(format "\\((\\(:?after!\\|def-package!\\)[ \t\n]*%s\\|^[ \t]*;; `%s'$\\)" 'action
package package)) `(lambda (_) (doom/help-package-config ',package)))))))))
(insert "\n" indent))
(delete-char -1)))))))
;;;###autoload ;;;###autoload
(defun doom/describe-symbol (symbol) (defun doom/help-package-config (package)
"Show help for SYMBOL, a variable, function or macro." "Jump to a configuration block for PACKAGE."
(interactive (interactive
(list (helpful--read-symbol "Symbol: " #'helpful--bound-p))) (list (doom--completing-package "Select package to search for: " current-prefix-arg)))
(let* ((sym (intern-soft symbol)) (let* ((default-directory doom-emacs-dir)
(bound (boundp sym)) (results (shell-command-to-string
(fbound (fboundp sym))) (format "git grep --no-break --no-heading --line-number '%s %s\\($\\| \\)'"
(cond ((and sym bound (not fbound)) "\\(^;;;###package\\|(after!\\|(def-package!\\)"
(helpful-variable sym)) package)))
((and sym fbound (not bound)) (select (completing-read "Jump to config: " (split-string results "\n" t))))
(helpful-callable sym)) (cl-destructuring-bind (file line _match)
((apropos (format "^%s\$" symbol))) (split-string select ":")
((apropos (format "%s" symbol)))))) (pop-to-buffer file)
(goto-line line))))
;;;###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))
)

View file

@ -219,9 +219,9 @@ files."
(push (cons name (push (cons name
(plist-put plist :modules (plist-put plist :modules
(cond ((file-in-directory-p file doom-private-dir) (cond ((file-in-directory-p file doom-private-dir)
(list :private)) '((:private)))
((file-in-directory-p file doom-core-dir) ((file-in-directory-p file doom-core-dir)
(list :core)) '((:core)))
((doom-module-from-path file))))) ((doom-module-from-path file)))))
doom-packages)))))) doom-packages))))))
((debug error) ((debug error)

View file

@ -183,9 +183,8 @@
(define-key! help-map (define-key! help-map
;; new keybinds ;; new keybinds
"'" #'describe-char "'" #'describe-char
"A" #'doom/describe-autodefs
"B" #'doom/open-bug-report "B" #'doom/open-bug-report
"D" #'doom/open-manual "D" #'doom/help
"E" #'doom/open-vanilla-sandbox "E" #'doom/open-vanilla-sandbox
"M" #'doom/describe-active-minor-mode "M" #'doom/describe-active-minor-mode
"O" #'+lookup/online "O" #'+lookup/online
@ -195,7 +194,6 @@
"C-k" #'describe-key-briefly "C-k" #'describe-key-briefly
"C-l" #'describe-language-environment "C-l" #'describe-language-environment
"C-m" #'info-emacs-manual "C-m" #'info-emacs-manual
"C-v" #'doom/version
;; Unbind `help-for-help'. Conflicts with which-key's help command for the ;; Unbind `help-for-help'. Conflicts with which-key's help command for the
;; <leader> h prefix. It's already on ? and F1 anyway. ;; <leader> h prefix. It's already on ? and F1 anyway.
@ -210,22 +208,34 @@
"rf" #'doom/reload-font "rf" #'doom/reload-font
"re" #'doom/reload-env "re" #'doom/reload-env
;; replaces `apropos-documentation' b/c `apropos' covers this
"d" nil
"d/" #'doom/help-search
"da" #'doom/help-autodefs
"dd" #'doom/toggle-debug-mode
"df" #'doom/help-faq
"dh" #'doom/help
"dm" #'doom/help-modules
"dn" #'doom/help-news
"dp" #'doom/help-packages
"dc" #'doom/help-package-config
"dt" #'doom/toggle-profiler
"dv" #'doom/version
;; replaces `apropos-command' ;; replaces `apropos-command'
"a" #'apropos "a" #'apropos
;; replaces `describe-copying' b/c not useful ;; replaces `describe-copying' b/c not useful
"C-c" #'describe-coding-system "C-c" #'describe-coding-system
;; replaces `apropos-documentation' b/c `apropos' covers this
"d" #'doom/describe-module
;; replaces `Info-got-emacs-command-node' b/c redundant w/ `Info-goto-node' ;; replaces `Info-got-emacs-command-node' b/c redundant w/ `Info-goto-node'
"F" #'describe-face "F" #'describe-face
;; replaces `view-hello-file' b/c annoying ;; replaces `view-hello-file' b/c annoying
"h" #'doom/describe-symbol "h" #'doom/help
;; replaces `describe-language-environment' b/c remapped to C-l ;; replaces `describe-language-environment' b/c remapped to C-l
"L" #'global-command-log-mode "L" #'global-command-log-mode
;; replaces `view-emacs-news' b/c it's on C-n too ;; replaces `view-emacs-news' b/c it's on C-n too
"n" #'doom/open-news "n" #'doom/help-news
;; replaces `finder-by-keyword' ;; replaces `finder-by-keyword'
;; "p" #'doom/describe-package "p" #'doom/describe-package
;; replaces `describe-package' b/c redundant w/ `doom/describe-package' ;; replaces `describe-package' b/c redundant w/ `doom/describe-package'
"P" #'find-library) "P" #'find-library)