aboutsummaryrefslogtreecommitdiff
path: root/helpful.el
diff options
context:
space:
mode:
authorWilfred Hughes <me@wilfred.me.uk>2020-09-23 00:05:14 -0700
committerWilfred Hughes <me@wilfred.me.uk>2020-09-30 16:11:22 -0700
commit5a5eb62ae1f9cfdd4897ec6e878ec96231c52bdd (patch)
tree435dad49e9291e34fd44925a37fb4d7962b866f0 /helpful.el
parentf4b838c1080174e05a9e5f8672c4510a6d8298dc (diff)
Choose the default symbol more intelligently0.18
Fixes #163 Closes #245 Particular thanks to @matzebond for the first implementation of this feature!
Diffstat (limited to 'helpful.el')
-rw-r--r--helpful.el124
1 files changed, 101 insertions, 23 deletions
diff --git a/helpful.el b/helpful.el
index da344fa..b24637d 100644
--- a/helpful.el
+++ b/helpful.el
@@ -2535,22 +2535,26 @@ escapes that are used by `substitute-command-keys'."
(documentation-property sym 'variable-documentation t)))
docstring))
-(defun helpful--read-symbol (prompt predicate)
- (let* ((sym-here (symbol-at-point))
- (default-val
- (when (funcall predicate sym-here)
- (symbol-name sym-here))))
- (when default-val
- ;; TODO: Only modify the prompt when we don't have ido/ivy/helm,
- ;; because the default is obvious for them.
- (setq prompt
- (replace-regexp-in-string
- (rx ": " eos)
- (format " (default: %s): " default-val)
- prompt)))
- (intern (completing-read prompt obarray
- predicate t nil nil
- default-val))))
+(defun helpful--read-symbol (prompt default-val predicate)
+ "Read a symbol from the minibuffer, with completion.
+Returns the symbol."
+ (when (and default-val
+ (not (funcall predicate default-val)))
+ (setq default-val nil))
+ (when default-val
+ ;; `completing-read' expects a string.
+ (setq default-val (symbol-name default-val))
+
+ ;; TODO: Only modify the prompt when we don't have ido/ivy/helm,
+ ;; because the default is obvious for them.
+ (setq prompt
+ (replace-regexp-in-string
+ (rx ": " eos)
+ (format " (default: %s): " default-val)
+ prompt)))
+ (intern (completing-read prompt obarray
+ predicate t nil nil
+ default-val)))
;;;###autoload
(defun helpful-function (symbol)
@@ -2558,7 +2562,10 @@ escapes that are used by `substitute-command-keys'."
See also `helpful-macro', `helpful-command' and `helpful-callable'."
(interactive
- (list (helpful--read-symbol "Function: " #'functionp)))
+ (list (helpful--read-symbol
+ "Function: "
+ (helpful--callable-at-point)
+ #'functionp)))
(funcall helpful-switch-buffer-function (helpful--buffer symbol t))
(helpful-update))
@@ -2568,7 +2575,10 @@ See also `helpful-macro', `helpful-command' and `helpful-callable'."
See also `helpful-function'."
(interactive
- (list (helpful--read-symbol "Command: " #'commandp)))
+ (list (helpful--read-symbol
+ "Command: "
+ (helpful--callable-at-point)
+ #'commandp)))
(funcall helpful-switch-buffer-function (helpful--buffer symbol t))
(helpful-update))
@@ -2594,7 +2604,10 @@ See also `helpful-function'."
(defun helpful-macro (symbol)
"Show help for macro named SYMBOL."
(interactive
- (list (helpful--read-symbol "Macro: " #'macrop)))
+ (list (helpful--read-symbol
+ "Macro: "
+ (helpful--callable-at-point)
+ #'macrop)))
(funcall helpful-switch-buffer-function (helpful--buffer symbol t))
(helpful-update))
@@ -2604,7 +2617,10 @@ See also `helpful-function'."
See also `helpful-macro', `helpful-function' and `helpful-command'."
(interactive
- (list (helpful--read-symbol "Callable: " #'fboundp)))
+ (list (helpful--read-symbol
+ "Callable: "
+ (helpful--callable-at-point)
+ #'fboundp)))
(funcall helpful-switch-buffer-function (helpful--buffer symbol t))
(helpful-update))
@@ -2663,7 +2679,10 @@ nil if SYMBOL doesn't begin with \"F\" or \"V\"."
See also `helpful-callable' and `helpful-variable'."
(interactive
- (list (helpful--read-symbol "Symbol: " #'helpful--bound-p)))
+ (list (helpful--read-symbol
+ "Symbol: "
+ (helpful--symbol-at-point)
+ #'helpful--bound-p)))
(let ((c-var-sym (helpful--convert-c-name symbol t))
(c-fn-sym (helpful--convert-c-name symbol nil)))
(cond
@@ -2688,15 +2707,74 @@ See also `helpful-callable' and `helpful-variable'."
(defun helpful-variable (symbol)
"Show help for variable named SYMBOL."
(interactive
- (list (helpful--read-symbol "Variable: " #'helpful--variable-p)))
+ (list (helpful--read-symbol
+ "Variable: "
+ (helpful--variable-at-point)
+ #'helpful--variable-p)))
(funcall helpful-switch-buffer-function (helpful--buffer symbol nil))
(helpful-update))
+(defun helpful--variable-at-point-exactly ()
+ "Return the symbol at point, if it's a bound variable."
+ (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 (helpful--variable-p var)
+ var)))
+
+(defun helpful--variable-defined-at-point ()
+ "Return the variable defined in the form enclosing point."
+ ;; TODO: do the same thing if point is just before a top-level form.
+ (save-excursion
+ (save-restriction
+ (widen)
+ (let* ((ppss (syntax-ppss))
+ (sexp-start (nth 1 ppss))
+ sexp)
+ (when sexp-start
+ (goto-char sexp-start)
+ (setq sexp (read (current-buffer)))
+ (when (memq (car-safe sexp)
+ (list 'defvar 'defvar-local 'defcustom 'defconst))
+ (nth 1 sexp)))))))
+
+(defun helpful--variable-at-point ()
+ "Return the variable exactly under point, or defined at point."
+ (let ((var (helpful--variable-at-point-exactly)))
+ (if var
+ var
+ (let ((var (helpful--variable-defined-at-point)))
+ (when (helpful--variable-p var)
+ var)))))
+
+(defun helpful--callable-at-point ()
+ (let ((sym (symbol-at-point))
+ (enclosing-sym (function-called-at-point)))
+ (if (fboundp sym)
+ sym
+ enclosing-sym)))
+
+(defun helpful--symbol-at-point-exactly ()
+ "Return the symbol at point, if it's bound."
+ (let ((sym (symbol-at-point)))
+ (when (helpful--bound-p sym)
+ sym)))
+
+(defun helpful--symbol-at-point ()
+ "Find the most relevant symbol at or around point.
+Returns nil if nothing found."
+ (or
+ (helpful--symbol-at-point-exactly)
+ (helpful--callable-at-point)
+ (helpful--variable-at-point)))
+
;;;###autoload
(defun helpful-at-point ()
"Show help for the symbol at point."
(interactive)
- (-if-let (symbol (symbol-at-point))
+ (-if-let (symbol (helpful--symbol-at-point))
(helpful-symbol symbol)
(user-error "There is no symbol at point.")))