unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: npostavs@users.sourceforge.net
To: Dmitry Alexandrov <321942@gmail.com>
Cc: 26894@debbugs.gnu.org
Subject: bug#26894: 25.1, 26.0.50; ‘eshell/which’ abuses ‘describe-function’
Date: Sat, 03 Jun 2017 23:47:50 -0400	[thread overview]
Message-ID: <87shjgza55.fsf@users.sourceforge.net> (raw)
In-Reply-To: <871sr01n59.fsf@users.sourceforge.net> (npostavs@users.sourceforge.net's message of "Sat, 03 Jun 2017 22:50:58 -0400")

[-- Attachment #1: Type: text/plain, Size: 452 bytes --]

npostavs@users.sourceforge.net writes:

> Dmitry Alexandrov <321942@gmail.com> writes:
>
>> ‘eshell/which’ in its part, that locates built-in commands (‘$ which
>> which’ for example) and elisp functions in general, looks like a dirty
>> hack [0]: it calls interactive ‘describe-function’ command and parses
>> *Help* buffer.
>
> Yeah, that's not great.  Here's a patch.

Sorry, I sent a broken version, here's the right one.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch --]
[-- Type: text/x-diff, Size: 8398 bytes --]

From ce259d2b7518a6822f5e0271ccf66d0fb53e63a1 Mon Sep 17 00:00:00 2001
From: Noam Postavsky <npostavs@gmail.com>
Date: Sat, 3 Jun 2017 22:15:19 -0400
Subject: [PATCH v2] Don't read eshell/which output from *Help* buffer
 (Bug#26894)

* lisp/help-fns.el (help-fns--analyse-function)
(describe-function-header): New functions, extracted from
describe-function-1.
(describe-function-1): Use them.
* lisp/eshell/esh-cmd.el (eshell/which): Use
`describe-function-header' instead of `describe-function-1'.
---
 lisp/eshell/esh-cmd.el |  31 ++++++---------
 lisp/help-fns.el       | 103 +++++++++++++++++++++++++++----------------------
 2 files changed, 69 insertions(+), 65 deletions(-)

diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 86e7b83c28..91e41b7224 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -1148,6 +1148,8 @@ (defun eshell-do-eval (form &optional synchronous-p)
 
 ;; command invocation
 
+(declare-function describe-function-header "help-fns")
+
 (defun eshell/which (command &rest names)
   "Identify the COMMAND, and where it is located."
   (dolist (name (cons command names))
@@ -1164,25 +1166,16 @@ (defun eshell/which (command &rest names)
 		(concat name " is an alias, defined as \""
 			(cadr alias) "\"")))
       (unless program
-	(setq program (eshell-search-path name))
-	(let* ((esym (eshell-find-alias-function name))
-	       (sym (or esym (intern-soft name))))
-	  (if (and (or esym (and sym (fboundp sym)))
-		   (or eshell-prefer-lisp-functions (not direct)))
-	      (let ((desc (let ((inhibit-redisplay t))
-			    (save-window-excursion
-			      (prog1
-				  (describe-function sym)
-				(message nil))))))
-		(setq desc (if desc (substring desc 0
-					       (1- (or (string-match "\n" desc)
-						       (length desc))))
-			     ;; This should not happen.
-			     (format "%s is defined, \
-but no documentation was found" name)))
-		(if (buffer-live-p (get-buffer "*Help*"))
-		    (kill-buffer "*Help*"))
-		(setq program (or desc name))))))
+        (setq program
+              (let* ((esym (eshell-find-alias-function name))
+                     (sym (or esym (intern-soft name))))
+                (if (and (or esym (and sym (fboundp sym)))
+                         (or eshell-prefer-lisp-functions (not direct)))
+                    (require 'help-fns)
+                    (or (with-output-to-string
+                          (describe-function-header sym))
+                        name)
+                  (eshell-search-path name)))))
       (if (not program)
 	  (eshell-error (format "which: no %s in (%s)\n"
 				name (getenv "PATH")))
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 2c635ffa50..66e06df677 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -560,8 +560,9 @@ (defun help-fns-short-filename (filename)
             (setq short rel))))
     short))
 
-;;;###autoload
-(defun describe-function-1 (function)
+(defun help-fns--analyse-function (function)
+  "Return information about FUNCTION.
+Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
   (let* ((advised (and (symbolp function)
 		       (featurep 'nadvice)
 		       (advice--p (advice--symbol-function function))))
@@ -594,22 +595,24 @@ (defun describe-function-1 (function)
                          (setq f (symbol-function f)))
                        f))
 		    ((subrp def) (intern (subr-name def)))
-		    (t def)))
-	 (sig-key (if (subrp def)
-                      (indirect-function real-def)
-                    real-def))
-	 (file-name (find-lisp-object-file-name function (if aliased 'defun
-                                                           def)))
-         (pt1 (with-current-buffer (help-buffer) (point)))
-	 (beg (if (and (or (byte-code-function-p def)
-			   (keymapp def)
-			   (memq (car-safe def) '(macro lambda closure)))
-		       (stringp file-name)
-		       (help-fns--autoloaded-p function file-name))
-		  (if (commandp def)
-		      "an interactive autoloaded "
-		    "an autoloaded ")
-		(if (commandp def) "an interactive " "a "))))
+                    (t def))))
+    (list real-function def aliased real-def)))
+
+(defun describe-function-header (function)
+  "Print a line describing FUNCTION to `standard-output'."
+  (pcase-let* ((`(,_real-function ,def ,aliased ,real-def)
+                (help-fns--analyse-function function))
+               (file-name (find-lisp-object-file-name function (if aliased 'defun
+                                                                 def)))
+               (beg (if (and (or (byte-code-function-p def)
+                                 (keymapp def)
+                                 (memq (car-safe def) '(macro lambda closure)))
+                             (stringp file-name)
+                             (help-fns--autoloaded-p function file-name))
+                        (if (commandp def)
+                            "an interactive autoloaded "
+                          "an autoloaded ")
+                      (if (commandp def) "an interactive " "a "))))
 
     ;; Print what kind of function-like object FUNCTION is.
     (princ (cond ((or (stringp def) (vectorp def))
@@ -676,34 +679,42 @@ (defun describe-function-1 (function)
 	    (re-search-backward (substitute-command-keys "`\\([^`']+\\)'")
                                 nil t)
 	    (help-xref-button 1 'help-function-def function file-name))))
-      (princ ".")
-      (with-current-buffer (help-buffer)
-	(fill-region-as-paragraph (save-excursion (goto-char pt1) (forward-line 0) (point))
-				  (point)))
-      (terpri)(terpri)
-
-      (let ((doc-raw (documentation function t))
-            (key-bindings-buffer (current-buffer)))
-
-	;; If the function is autoloaded, and its docstring has
-	;; key substitution constructs, load the library.
-	(and (autoloadp real-def) doc-raw
-	     help-enable-auto-load
-	     (string-match "\\([^\\]=\\|[^=]\\|\\`\\)\\\\[[{<]" doc-raw)
-	     (autoload-do-load real-def))
-
-        (help-fns--key-bindings function)
-        (with-current-buffer standard-output
-          (let ((doc (help-fns--signature function doc-raw sig-key
-                                          real-function key-bindings-buffer)))
-            (run-hook-with-args 'help-fns-describe-function-functions function)
-            (insert "\n"
-                    (or doc "Not documented."))
-            ;; Avoid asking the user annoying questions if she decides
-            ;; to save the help buffer, when her locale's codeset
-            ;; isn't UTF-8.
-            (unless (memq text-quoting-style '(straight grave))
-              (set-buffer-file-coding-system 'utf-8))))))))
+      (princ "."))))
+
+;;;###autoload
+(defun describe-function-1 (function)
+  (let ((pt1 (with-current-buffer (help-buffer) (point))))
+    (describe-function-header function)
+    (with-current-buffer (help-buffer)
+      (fill-region-as-paragraph (save-excursion (goto-char pt1) (forward-line 0) (point))
+                                (point))))
+  (terpri)(terpri)
+
+  (pcase-let ((`(,real-function ,def ,_aliased ,real-def)
+               (help-fns--analyse-function function))
+              (doc-raw (documentation function t))
+              (key-bindings-buffer (current-buffer)))
+
+    ;; If the function is autoloaded, and its docstring has
+    ;; key substitution constructs, load the library.
+    (and (autoloadp real-def) doc-raw
+         help-enable-auto-load
+         (string-match "\\([^\\]=\\|[^=]\\|\\`\\)\\\\[[{<]" doc-raw)
+         (autoload-do-load real-def))
+
+    (help-fns--key-bindings function)
+    (with-current-buffer standard-output
+      (let ((doc (help-fns--signature
+                  function doc-raw
+                  (if (subrp def) (indirect-function real-def) real-def)
+                  real-function key-bindings-buffer)))
+        (run-hook-with-args 'help-fns-describe-function-functions function)
+        (insert "\n" (or doc "Not documented.")))
+      ;; Avoid asking the user annoying questions if she decides
+      ;; to save the help buffer, when her locale's codeset
+      ;; isn't UTF-8.
+      (unless (memq text-quoting-style '(straight grave))
+        (set-buffer-file-coding-system 'utf-8)))))
 
 ;; Add defaults to `help-fns-describe-function-functions'.
 (add-hook 'help-fns-describe-function-functions #'help-fns--obsolete)
-- 
2.11.1


  reply	other threads:[~2017-06-04  3:47 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-12  2:18 bug#26894: 25.1, 26.0.50; ‘eshell/which’ abuses ‘describe-function’ Dmitry Alexandrov
2017-06-04  2:50 ` npostavs
2017-06-04  3:47   ` npostavs [this message]
2017-06-24 20:20     ` npostavs
2017-06-28  0:38       ` npostavs

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87shjgza55.fsf@users.sourceforge.net \
    --to=npostavs@users.sourceforge.net \
    --cc=26894@debbugs.gnu.org \
    --cc=321942@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).