refactor!: move helpful from :core to :lang emacs-lisp

BREAKING CHANGE: This moves helpful.el out of core into :lang
emacs-lisp. Since most (all) people have this module enabled, this
shouldn't make a difference for most people, but if you're one of the
few that don't have :lang emacs-lisp enabled, Doom will revert to using
Emacs' built-in help.el and describe-* commands.

Others can also disable helpful with (package! helpful :disable t) if
they prefer Emacs' built-in help system, which wasn't possible before,
because it was a core package.

This was done as part of an ongoing effort to slim down Doom's core in
preparation for v3.
This commit is contained in:
Henrik Lissner 2024-08-30 01:56:03 -04:00
parent bf9e619533
commit 6671adc687
No known key found for this signature in database
GPG key ID: B60957CA074D39A3
13 changed files with 127 additions and 116 deletions

View file

@ -545,61 +545,6 @@ files, so this replace calls to `pp' with the much faster `prin1'."
(message ""))))) ; warn silently (message ""))))) ; warn silently
(funcall fn arg))))) (funcall fn arg)))))
(use-package! helpful
;; a better *help* buffer
:commands helpful--read-symbol
:hook (helpful-mode . visual-line-mode)
:init
;; Make `apropos' et co search more extensively. They're more useful this way.
(setq apropos-do-all t)
(global-set-key [remap describe-function] #'helpful-callable)
(global-set-key [remap describe-command] #'helpful-command)
(global-set-key [remap describe-variable] #'helpful-variable)
(global-set-key [remap describe-key] #'helpful-key)
(global-set-key [remap describe-symbol] #'helpful-symbol)
(defun doom-use-helpful-a (fn &rest args)
"Force FN to use helpful instead of the old describe-* commands."
(letf! ((#'describe-function #'helpful-function)
(#'describe-variable #'helpful-variable))
(apply fn args)))
(after! apropos
;; patch apropos buttons to call helpful instead of help
(dolist (fun-bt '(apropos-function apropos-macro apropos-command))
(button-type-put
fun-bt 'action
(lambda (button)
(helpful-callable (button-get button 'apropos-symbol)))))
(dolist (var-bt '(apropos-variable apropos-user-option))
(button-type-put
var-bt 'action
(lambda (button)
(helpful-variable (button-get button 'apropos-symbol))))))
;; DEPRECATED: Remove when support for 29 is dropped.
(when (= emacs-major-version 29)
(defadvice! doom--find-function-search-for-symbol-save-excursion-a (fn &rest args)
"Suppress cursor movement by `find-function-search-for-symbol'.
Addresses an unwanted side-effect in `find-function-search-for-symbol' on Emacs
29 where the cursor is moved to a variable's definition if it's defined in the
current buffer."
:around #'find-function-search-for-symbol
(let (buf pos)
(letf! (defun find-library-name (library)
(let ((filename (funcall find-library-name library)))
(with-current-buffer (find-file-noselect filename)
(setq buf (current-buffer)
pos (point)))
filename))
(prog1 (apply fn args)
(when (buffer-live-p buf)
(with-current-buffer buf (goto-char pos))))))))
:config
(setq helpful-set-variable-function #'setq!))
(use-package! smartparens (use-package! smartparens
;; Auto-close delimiters and blocks as you type. It's more powerful than that, ;; Auto-close delimiters and blocks as you type. It's more powerful than that,

View file

@ -97,10 +97,10 @@ selection of all minor-modes, active or not."
(let ((symbol (let ((symbol
(cond ((stringp mode) (intern mode)) (cond ((stringp mode) (intern mode))
((symbolp mode) mode) ((symbolp mode) mode)
((error "Expected a symbol/string, got a %s" (type-of mode)))))) ((error "Expected a symbol/string, got a %s" (type-of mode)))))
(if (fboundp symbol) (fn (if (fboundp symbol) #'describe-function #'describe-variable)))
(helpful-function symbol) (funcall (or (command-remapping fn) fn)
(helpful-variable symbol)))) symbol)))
;; ;;
@ -414,26 +414,44 @@ current file is in, or d) the module associated with the current major mode (see
(doom-project-browse (file-name-directory path))) (doom-project-browse (file-name-directory path)))
((user-error "Aborted module lookup"))))) ((user-error "Aborted module lookup")))))
(defun doom--help-variable-p (sym)
"TODO"
(or (get sym 'variable-documentation)
(and (boundp sym)
(not (keywordp sym))
(not (memq sym '(t nil))))))
;;;###autoload ;;;###autoload
(defun doom/help-custom-variable (var) (defun doom/help-custom-variable (var)
"Look up documentation for a custom variable. "Look up documentation for a custom variable.
Unlike `helpful-variable', which casts a wider net that includes internal Unlike `describe-variable' or `helpful-variable', which casts a wider net that
variables, this only lists variables that exist to be customized (defined with includes internal variables, this only lists variables that exist to be
`defcustom')." customized (defined with `defcustom')."
(interactive (interactive
(list (helpful--read-symbol (list
"Custom variable: " (intern (completing-read
(helpful--variable-at-point) "Custom variable: " obarray
(lambda (sym) (lambda (sym)
(and (helpful--variable-p sym) (and (doom--help-variable-p sym)
(custom-variable-p sym) (custom-variable-p sym)
;; Exclude minor mode state variables, which aren't meant to be ;; Exclude minor mode state variables, which aren't meant to
;; modified directly, but through their associated function. ;; be modified directly, but through their associated
;; function.
(not (or (and (string-suffix-p "-mode" (symbol-name sym)) (not (or (and (string-suffix-p "-mode" (symbol-name sym))
(fboundp sym)) (fboundp sym))
(eq (get sym 'custom-set) 'custom-set-minor-mode)))))))) (eq (get sym 'custom-set) 'custom-set-minor-mode)))))
(helpful-variable var)) t nil nil (let ((var (variable-at-point)))
;; `variable-at-point' uses 0 rather than nil to
;; signify no symbol at point (presumably because 'nil
;; is a symbol).
(unless (symbolp var)
(setq var nil))
(when (doom--help-variable-p var)
var))))))
(funcall (or (command-remapping #'describe-variable)
#'describe-variable)
var))
;; ;;

View file

@ -30,7 +30,6 @@
;; doom-editor.el ;; doom-editor.el
(package! better-jumper :pin "47622213783ece37d5337dc28d33b530540fc319") (package! better-jumper :pin "47622213783ece37d5337dc28d33b530540fc319")
(package! dtrt-indent :pin "a8aa356684804c52f26602d4e315f1306c6f3e59") (package! dtrt-indent :pin "a8aa356684804c52f26602d4e315f1306c6f3e59")
(package! helpful :pin "4ba24cac9fb14d5fdc32582cd947572040e82b2c")
(package! smartparens :pin "c7519a1b69f196050a13e2230b7532893b077086") (package! smartparens :pin "c7519a1b69f196050a13e2230b7532893b077086")
(package! ws-butler :pin "e3a38d93e01014cd47bf5af4924459bd145fd7c4") (package! ws-butler :pin "e3a38d93e01014cd47bf5af4924459bd145fd7c4")

View file

@ -102,11 +102,7 @@ Can be negative.")
(set-popup-rule! "^\\*helm" :vslot -100 :size 0.22 :ttl nil) (set-popup-rule! "^\\*helm" :vslot -100 :size 0.22 :ttl nil)
;; Hide minibuffer if `helm-echo-input-in-header-line' ;; Hide minibuffer if `helm-echo-input-in-header-line'
(add-hook 'helm-minibuffer-set-up-hook #'helm-hide-minibuffer-maybe) (add-hook 'helm-minibuffer-set-up-hook #'helm-hide-minibuffer-maybe))
;; Use helpful instead of describe-* to display documentation
(dolist (fn '(helm-describe-variable helm-describe-function))
(advice-add fn :around #'doom-use-helpful-a)))
(use-package! helm-posframe (use-package! helm-posframe

View file

@ -226,11 +226,6 @@ workable results ripgrep produces, despite the error."
(if (= code 2) 0 code))) (if (= code 2) 0 code)))
(apply fn args))) (apply fn args)))
;; Integrate with `helpful'
(setq counsel-describe-function-function #'helpful-callable
counsel-describe-variable-function #'helpful-variable
counsel-descbinds-function #'helpful-callable)
;; Decorate `doom/help-custom-variable' results the same way as ;; Decorate `doom/help-custom-variable' results the same way as
;; `counsel-describe-variable' (adds value and docstring columns). ;; `counsel-describe-variable' (adds value and docstring columns).
(ivy-configure 'doom/help-custom-variable :parent 'counsel-describe-variable) (ivy-configure 'doom/help-custom-variable :parent 'counsel-describe-variable)

View file

@ -553,9 +553,6 @@
"<" #'help-go-back "<" #'help-go-back
"n" #'forward-button "n" #'forward-button
"p" #'backward-button) "p" #'backward-button)
(:after helpful
:map helpful-mode-map
"o" #'link-hint-open-link)
(:after apropos (:after apropos
:map apropos-mode-map :map apropos-mode-map
"o" #'link-hint-open-link "o" #'link-hint-open-link

View file

@ -102,8 +102,6 @@
(:after help :map help-mode-map (:after help :map help-mode-map
:n "o" #'link-hint-open-link) :n "o" #'link-hint-open-link)
(:after helpful :map helpful-mode-map
:n "o" #'link-hint-open-link)
(:after info :map Info-mode-map (:after info :map Info-mode-map
:n "o" #'link-hint-open-link) :n "o" #'link-hint-open-link)
(:after apropos :map apropos-mode-map (:after apropos :map apropos-mode-map

View file

@ -165,8 +165,7 @@ buffers."
"Look up documentation for QUERY. "Look up documentation for QUERY.
If QUERY is in the format of an ex command, it will map it to the underlying If QUERY is in the format of an ex command, it will map it to the underlying
function and open its documentation with `helpful-function'. Otherwise, it will function and open its documentation.
search for it with `apropos'.
If QUERY is empty, this runs the equivalent of 'M-x apropos'. If BANG is If QUERY is empty, this runs the equivalent of 'M-x apropos'. If BANG is
non-nil, a search is preformed against Doom's manual (with non-nil, a search is preformed against Doom's manual (with
@ -180,7 +179,8 @@ non-nil, a search is preformed against Doom's manual (with
(or (command-remapping #'apropos) (or (command-remapping #'apropos)
#'apropos))) #'apropos)))
((string-match "^ *:\\([^ ]+\\)$" query) ((string-match "^ *:\\([^ ]+\\)$" query)
(helpful-function (funcall (or (command-remapping #'describe-function)
#'describe-function)
(evil-ex-completed-binding (match-string 1 query)))) (evil-ex-completed-binding (match-string 1 query))))
((message "Searching for %S, this may take a while..." query) ((message "Searching for %S, this may take a while..." query)
(apropos query t)))))) (apropos query t))))))

View file

@ -150,15 +150,6 @@ directives. By default, this only recognizes C directives.")
:after-until #'evil-global-marker-p :after-until #'evil-global-marker-p
(and (>= char ?2) (<= char ?9))) (and (>= char ?2) (<= char ?9)))
;; HACK Invoking helpful from evil-ex throws a "No recursive edit is in
;; progress" error because, between evil-ex and helpful,
;; `abort-recursive-edit' gets called one time too many.
(defadvice! +evil--fix-helpful-key-in-evil-ex-a (key-sequence)
:before #'helpful-key
(when (evil-ex-p)
(run-at-time 0.1 nil #'helpful-key key-sequence)
(abort-recursive-edit)))
;; Make J (evil-join) remove comment delimiters when joining lines. ;; Make J (evil-join) remove comment delimiters when joining lines.
(advice-add #'evil-join :around #'+evil-join-a) (advice-add #'evil-join :around #'+evil-join-a)
@ -464,9 +455,6 @@ directives. By default, this only recognizes C directives.")
:v "gR" #'+eval:replace-region :v "gR" #'+eval:replace-region
;; Restore these keybinds, since the blacklisted/overwritten gr/gR will ;; Restore these keybinds, since the blacklisted/overwritten gr/gR will
;; undo them: ;; undo them:
(:after helpful
:map helpful-mode-map
:n "gr" #'helpful-update)
(:after compile (:after compile
:map (compilation-mode-map compilation-minor-mode-map) :map (compilation-mode-map compilation-minor-mode-map)
:n "gr" #'recompile) :n "gr" #'recompile)

View file

@ -116,8 +116,14 @@ if it's callable, `apropos' otherwise."
'(outline org-fold-outline)) '(outline org-fold-outline))
(org-show-hidden-entry)))) (org-show-hidden-entry))))
'deferred)) 'deferred))
(thing (helpful-symbol (intern thing))) (thing
((call-interactively #'helpful-at-point)))) (funcall (or (command-remapping #'describe-symbol)
#'describe-symbol)
(intern thing)))
((call-interactively
(if (fboundp #'helpful-at-point)
#'helpful-at-point
#'describe-symbol)))))
;; DEPRECATED Remove when 28 support is dropped. ;; DEPRECATED Remove when 28 support is dropped.
(unless (fboundp 'lisp--local-defform-body-p) (unless (fboundp 'lisp--local-defform-body-p)

View file

@ -261,6 +261,77 @@ See `+emacs-lisp-non-package-mode' for details.")
"s" #'buttercup-run-at-point)) "s" #'buttercup-run-at-point))
(use-package! helpful
;; a better *help* buffer
:commands helpful--read-symbol
:hook (helpful-mode . visual-line-mode)
:init
;; Make `apropos' et co search more extensively. They're more useful this way.
(setq apropos-do-all t)
(global-set-key [remap describe-function] #'helpful-callable)
(global-set-key [remap describe-command] #'helpful-command)
(global-set-key [remap describe-variable] #'helpful-variable)
(global-set-key [remap describe-key] #'helpful-key)
(global-set-key [remap describe-symbol] #'helpful-symbol)
(defun doom-use-helpful-a (fn &rest args)
"Force FN to use helpful instead of the old describe-* commands."
(letf! ((#'describe-function #'helpful-function)
(#'describe-variable #'helpful-variable))
(apply fn args)))
(after! apropos
;; patch apropos buttons to call helpful instead of help
(dolist (fun-bt '(apropos-function apropos-macro apropos-command))
(button-type-put
fun-bt 'action
(lambda (button)
(helpful-callable (button-get button 'apropos-symbol)))))
(dolist (var-bt '(apropos-variable apropos-user-option))
(button-type-put
var-bt 'action
(lambda (button)
(helpful-variable (button-get button 'apropos-symbol))))))
;; DEPRECATED: Remove when support for 29 is dropped.
(when (= emacs-major-version 29)
(defadvice! doom--find-function-search-for-symbol-save-excursion-a (fn &rest args)
"Suppress cursor movement by `find-function-search-for-symbol'.
Addresses an unwanted side-effect in `find-function-search-for-symbol' on Emacs
29 where the cursor is moved to a variable's definition if it's defined in the
current buffer."
:around #'find-function-search-for-symbol
(let (buf pos)
(letf! (defun find-library-name (library)
(let ((filename (funcall find-library-name library)))
(with-current-buffer (find-file-noselect filename)
(setq buf (current-buffer)
pos (point)))
filename))
(prog1 (apply fn args)
(when (buffer-live-p buf)
(with-current-buffer buf (goto-char pos))))))))
:config
(setq helpful-set-variable-function #'setq!)
(cond ((modulep! :completion ivy)
(setq counsel-describe-function-function #'helpful-callable
counsel-describe-variable-function #'helpful-variable
counsel-descbinds-function #'helpful-callable))
((modulep! :completion helm)
(dolist (fn '(helm-describe-variable helm-describe-function))
(advice-add fn :around #'doom-use-helpful-a))))
;; Open help:* links with helpful-* instead of describe-*
(advice-add #'org-link--open-help :around #'doom-use-helpful-a)
(map! :map helpful-mode-map
:ng "o" #'link-hint-open-link
:n "gr" #'helpful-update))
;; ;;
;;; Project modes ;;; Project modes

View file

@ -7,6 +7,7 @@
(package! highlight-quoted :pin "24103478158cd19fbcfb4339a3f1fa1f054f1469") (package! highlight-quoted :pin "24103478158cd19fbcfb4339a3f1fa1f054f1469")
;; Tools ;; Tools
(package! helpful :pin "4ba24cac9fb14d5fdc32582cd947572040e82b2c")
(package! macrostep :pin "4939d88779761e8b5461b4cf73f86600172987db") (package! macrostep :pin "4939d88779761e8b5461b4cf73f86600172987db")
(package! overseer :pin "7fdcf1a6fba6b1569a09c1666b4e51bcde266ed9") (package! overseer :pin "7fdcf1a6fba6b1569a09c1666b4e51bcde266ed9")
(package! elisp-def :pin "1ad4baccbf3d0d13e7607d332ae6bc60a5dd7360") (package! elisp-def :pin "1ad4baccbf3d0d13e7607d332ae6bc60a5dd7360")

View file

@ -540,8 +540,8 @@ relative to `org-directory', unless it is an absolute path."
;; documentation -- especially Doom's! ;; documentation -- especially Doom's!
(letf! ((defun -call-interactively (fn) (letf! ((defun -call-interactively (fn)
(lambda (path _prefixarg) (lambda (path _prefixarg)
(funcall (funcall (or (command-remapping fn) fn)
fn (or (intern-soft path) (or (intern-soft path)
(user-error "Can't find documentation for %S" path)))))) (user-error "Can't find documentation for %S" path))))))
(org-link-set-parameters (org-link-set-parameters
"kbd" "kbd"
@ -553,12 +553,12 @@ relative to `org-directory', unless it is an absolute path."
:face 'help-key-binding) :face 'help-key-binding)
(org-link-set-parameters (org-link-set-parameters
"var" "var"
:follow (-call-interactively #'helpful-variable) :follow (-call-interactively #'describe-variable)
:activate-func #'+org-link--var-link-activate-fn :activate-func #'+org-link--var-link-activate-fn
:face '(font-lock-variable-name-face underline)) :face '(font-lock-variable-name-face underline))
(org-link-set-parameters (org-link-set-parameters
"fn" "fn"
:follow (-call-interactively #'helpful-callable) :follow (-call-interactively #'describe-function)
:activate-func #'+org-link--fn-link-activate-fn :activate-func #'+org-link--fn-link-activate-fn
:face '(font-lock-function-name-face underline)) :face '(font-lock-function-name-face underline))
(org-link-set-parameters (org-link-set-parameters
@ -739,9 +739,6 @@ mutating hooks on exported output, like formatters."
(add-to-list 'org-file-apps '(directory . emacs)) (add-to-list 'org-file-apps '(directory . emacs))
(add-to-list 'org-file-apps '(remote . emacs)) (add-to-list 'org-file-apps '(remote . emacs))
;; Open help:* links with helpful-* instead of describe-*
(advice-add #'org-link--open-help :around #'doom-use-helpful-a)
;; Some uses of `org-fix-tags-on-the-fly' occur without a check on ;; Some uses of `org-fix-tags-on-the-fly' occur without a check on
;; `org-auto-align-tags', such as in `org-self-insert-command' and ;; `org-auto-align-tags', such as in `org-self-insert-command' and
;; `org-delete-backward-char'. ;; `org-delete-backward-char'.