all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Gregory Heytings <gregory@heytings.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: yantar92@posteo.net, mardani29@yahoo.es,
	Stefan Monnier <monnier@iro.umontreal.ca>,
	60568@debbugs.gnu.org
Subject: bug#60568: [FR] 30.0.50; Help buffers and function bodies for generated functions
Date: Fri, 06 Jan 2023 09:11:02 +0000	[thread overview]
Message-ID: <371ba1d0beb0ed44a9a6@heytings.org> (raw)
In-Reply-To: <83cz7sw4q1.fsf@gnu.org>

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


>>> I hope that in a more general case we could use something similar, 
>>> since every definition of a function should start from "defun " 
>>> followed by some part of its name, right?
>>
>> Not always, I can imagine functions defined with fset for example.
>>
>> What about the attached patch?  It seems to work well.
>
> SGTM.  With which cases did you test this?
>
> Adding Stefan, in case he has any comments.
>

Mainly with the original recipe and some variants of it.

I attach a slightly improved version of the patch.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Try-to-find-where-dynamically-defined-functions-were.patch --]
[-- Type: text/x-diff; name=Try-to-find-where-dynamically-defined-functions-were.patch, Size: 6329 bytes --]

From 841ad680dbbfa3a4a95a3b09a7409fcd9ce6cdd7 Mon Sep 17 00:00:00 2001
From: Gregory Heytings <gregory@heytings.org>
Date: Fri, 6 Jan 2023 08:54:34 +0000
Subject: [PATCH] Try to find where dynamically defined functions were defined

* lisp/help-mode.el
(help-function-def--find-probable-definition-place): New function.
(help-function-def--button-function): Use it.  See bug#60568.
---
 lisp/help-mode.el | 111 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 110 insertions(+), 1 deletion(-)

diff --git a/lisp/help-mode.el b/lisp/help-mode.el
index bf64d032b6..15fd23c1cd 100644
--- a/lisp/help-mode.el
+++ b/lisp/help-mode.el
@@ -252,6 +252,91 @@ 'help-customize-face
 		   (customize-face v))
   'help-echo (purecopy "mouse-2, RET: customize face"))
 
+(defun help-function-def--find-probable-definition-place (fun)
+  "Find the function in which FUN was likely defined.
+FUN is the symbol of a function.
+The current buffer must be visiting the file in which the
+function was defined (see `symbol-file').
+If the function in which FUN was likely defined is found, return
+a cons with its name and its beginning position.
+Otherwise, return nil."
+  (save-excursion
+    ;; Build a list of strings with the symbols (and strings) of FUN.
+    (let ((names
+           (mapcar (lambda (el)
+                     (concat
+                      "\\_<"
+                      (regexp-quote (format "%s" el))
+                      "\\_>"))
+                   (flatten-tree (symbol-function fun))))
+          results)
+      (delete-dups names)
+      (when names
+        ;; Build an alist with all functions in which each symbol is
+        ;; found.
+        (dolist (el names)
+          ;; Exclude symbols that are 3 characters or less.
+          (when (> (length el) 9)
+            (let (result)
+              (goto-char (point-min))
+              (while (re-search-forward el nil t)
+                (push (lisp-current-defun-name) result))
+              (delete-dups result)
+              (when result
+                (push (cons el result) results)))))
+        (when results
+          ;; First check if one of the symbols is found in a single
+          ;; function.
+          (let ((el (catch 'found
+                      (progn
+                      (mapcar
+                       (lambda (el)
+                         (if (= (length el) 2)
+                             (throw 'found (car el))))
+                       results)))))
+            (if (stringp el)
+                ;; If one such function was found, it's the function
+                ;; we are after.
+                (progn
+                  (goto-char (point-min))
+                  (re-search-forward el nil t)
+                  (beginning-of-defun)
+                  (cons (lisp-current-defun-name) (point)))
+              ;; Otherwise, find which function contains the most
+              ;; symbols in FUN.
+              (let (places)
+                (dolist (el results)
+                  (dolist (e (cdr el))
+                    (push e places)))
+                (let* ((sorted-places (sort places #'string<))
+                       (ptr sorted-places)
+                       (count 1)
+                       (max 0)
+                       result)
+                  (while ptr
+                    (if (string= (car ptr) (cadr ptr))
+                        (setq count (1+ count))
+                      (when (> count max)
+                        (setq max count)
+                        (setq result (car ptr)))
+                      (setq count 1))
+                    (setq ptr (cdr ptr)))
+                  (when result
+                    ;; Determine the beginning position of that
+                    ;; function.
+                    (goto-char (point-min))
+                    (when (catch 'found
+                            (while (re-search-forward
+                                    (concat "\\_<"
+                                            (regexp-quote result)
+                                            "\\_>"))
+                              (when (string= (lisp-current-defun-name)
+                                             result)
+                                (throw 'found t)))
+                            (throw 'found nil))
+                      (beginning-of-defun)
+                      (cons result (point)))))))))))))
+
 (defun help-function-def--button-function (fun &optional file type)
   (or file
       (setq file (find-lisp-object-file-name fun type)))
@@ -281,7 +366,31 @@ help-function-def--button-function
             (unless (= (point) position)
               (push-mark nil t))
             (goto-char position))
-        (message "Unable to find location in file")))))
+        (let ((probable-definition-place
+               (help-function-def--find-probable-definition-place fun)))
+          (when probable-definition-place
+            (goto-char (cdr probable-definition-place)))
+          (let ((help-buffer-under-preparation t))
+            (help-setup-xref (list #'help-function-def--button-function
+                                   fun file)
+		             (called-interactively-p 'interactive))
+	    (with-help-window (help-buffer)
+	      (insert (substitute-command-keys
+                       (format "Function %s could not be found in `%s'.\n\n"
+                              fun (file-name-nondirectory file))))
+              (setq help-mode--current-data (list :symbol fun
+                                                  :file file))
+	      (save-excursion
+	        (re-search-backward
+                 (substitute-command-keys "`\\([^`']+\\)'")
+                 nil t)
+	        (help-xref-button 1 'help-function-def fun file))
+              (when probable-definition-place
+                (insert (substitute-command-keys
+                         (format "It was probably defined by `%s'.\n\n"
+                                (car probable-definition-place)))))
+	      (insert "Function definition:\n\n")
+	      (insert (pp-to-string (symbol-function fun))))))))))
 
 (define-button-type 'help-function-def
   :supertype 'help-xref
-- 
2.39.0


  reply	other threads:[~2023-01-06  9:11 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-05  7:56 bug#60568: [FR] 30.0.50; Help buffers and function bodies for generated functions Ihor Radchenko
2023-01-05  8:09 ` Eli Zaretskii
2023-01-05  8:20   ` Ihor Radchenko
2023-01-05  8:32     ` Eli Zaretskii
2023-01-05 17:04       ` Jean Louis
2023-01-05 17:03   ` Jean Louis
2023-01-05  9:40 ` Gregory Heytings
2023-01-05  9:52   ` Gregory Heytings
2023-01-05 10:45 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-05 10:52   ` Ihor Radchenko
2023-01-05 11:20   ` Eli Zaretskii
2023-01-05 12:33     ` Gregory Heytings
2023-01-05 14:16       ` Eli Zaretskii
2023-01-05 14:27         ` Gregory Heytings
2023-01-05 15:10           ` Eli Zaretskii
2023-01-05 15:13             ` Gregory Heytings
2023-01-05 16:49               ` Eli Zaretskii
2023-01-05 20:44                 ` Gregory Heytings
2023-01-06  6:35                   ` Eli Zaretskii
2023-01-06  9:11                     ` Gregory Heytings [this message]
2023-01-06 17:27                       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-06 22:52                         ` Gregory Heytings
2023-01-07  0:36                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-07  6:55                             ` Eli Zaretskii
2023-01-07  9:42                               ` Gregory Heytings
2023-01-07 13:38                                 ` Ihor Radchenko
2023-01-07 14:00                                   ` Eli Zaretskii
2023-01-07 14:04                                   ` Gregory Heytings
2023-01-07 15:07                                     ` Ihor Radchenko
2023-01-07 15:14                                       ` Eli Zaretskii
2023-01-07 15:19                                         ` Ihor Radchenko
2023-01-07 15:23                                           ` Eli Zaretskii
2023-01-07 17:59                                             ` Eli Zaretskii
2023-01-07 13:14                               ` Ihor Radchenko
2023-01-07 13:55                                 ` Eli Zaretskii
2023-01-05 17:00 ` Jean Louis
2023-01-06  8:39   ` Ihor Radchenko
2023-01-06 16:44 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-07 11:32   ` Ihor Radchenko
2023-01-07 15:44     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-01-12 10:40       ` Ihor Radchenko

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

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

  git send-email \
    --in-reply-to=371ba1d0beb0ed44a9a6@heytings.org \
    --to=gregory@heytings.org \
    --cc=60568@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=mardani29@yahoo.es \
    --cc=monnier@iro.umontreal.ca \
    --cc=yantar92@posteo.net \
    /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 external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.