Subject: Re: bug#61877: [PATCH] Extract Lisp function examples from shortdoc information

From: Daniel Martín <[email-masked]>
Date: Sun, 12 Mar 2023 13:55:49 +0100

Eli Zaretskii <[email-masked]> writes:

> Btw, something seems amiss: "C-h f" for string-fill, which has 2
> examples in shortdoc, still says "Example:", not "Examples:", as I'd
> expect.  Can you take a look?

That is because some functions have more than one example per group (for
example, string-lessp is documented in the "comparison" and "string"
groups), but the "s" is added when a function is documented in _more
than one group_.

I think a more accurate logic to add the "s" is to count the number of
"arrow characters" that separate the form from the example.

Could you give a try to the attached patch, and install it for me if all
works correctly?  Thanks.

>From c3ca21707f38f1bc82939fc05e381dfc1131026d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Mart=C3=ADn?= <[email-masked]>
Date: Sun, 12 Mar 2023 13:38:34 +0100
Subject: [PATCH] Fix pluralization in shortdoc-help-fns-examples-function

* lisp/emacs-lisp/shortdoc.el (shortdoc-help-fns-examples-function):
Implement a better logic to pluralize "Example", by counting the
number of arrow characters in the example string. (Bug#61877)
* test/lisp/emacs-lisp/shortdoc-tests.el
(shortdoc-help-fns-examples-function-test): Add a test.
---
 lisp/emacs-lisp/shortdoc.el            | 35 ++++++++++++++++++++++----
 test/lisp/emacs-lisp/shortdoc-tests.el | 15 +++++++++++
 2 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 6e3ebc7c6a2..9a6f5dd12ce 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1621,13 +1621,38 @@ shortdoc-help-fns-examples-function
 You can add this function to the `help-fns-describe-function-functions'
 hook to show examples of using FUNCTION in *Help* buffers produced
 by \\[describe-function]."
-  (let ((examples (shortdoc-function-examples function))
-        (times 0))
+  (let* ((examples (shortdoc-function-examples function))
+         (num-examples (length examples))
+         (times 0))
     (dolist (example examples)
       (when (zerop times)
-        (if (eq (length examples) 1)
-            (insert "\n  Example:\n\n")
-          (insert "\n  Examples:\n\n")))
+        (if (> num-examples 1)
+            (insert "\n  Examples:\n\n")
+          ;; Some functions have more than one example per group.
+          ;; Count the number of arrows to know if we need to
+          ;; pluralize "Example".
+          (let* ((text (cdr example))
+                 (count 0)
+                 (pos 0)
+                 (end (length text))
+                 (double-arrow (if (char-displayable-p ?⇒)
+                                   "    ⇒"
+                                 "    =>"))
+                 (double-arrow-example (if (char-displayable-p ?⇒)
+                                           "    e.g. ⇒"
+                                         "    e.g. =>"))
+                 (single-arrow (if (char-displayable-p ?→)
+                                   "    →"
+                                 "    ->")))
+            (while (and (< pos end)
+                        (or (string-match double-arrow text pos)
+                            (string-match double-arrow-example text pos)
+                            (string-match single-arrow text pos)))
+              (setq count (1+ count)
+                    pos (match-end 0)))
+            (if (> count 1)
+                (insert "\n  Examples:\n\n")
+              (insert "\n  Example:\n\n")))))
       (setq times (1+ times))
       (insert "  ")
       (insert (cdr example))
diff --git a/test/lisp/emacs-lisp/shortdoc-tests.el b/test/lisp/emacs-lisp/shortdoc-tests.el
index a65a4a5ddc3..d2dfbc66864 100644
--- a/test/lisp/emacs-lisp/shortdoc-tests.el
+++ b/test/lisp/emacs-lisp/shortdoc-tests.el
@@ -75,6 +75,21 @@ shortdoc-function-examples-test
   (should (equal '((regexp . "(string-match-p \"^[fo]+\" \"foobar\")\n    => 0"))
                  (shortdoc-function-examples 'string-match-p))))
 
+(ert-deftest shortdoc-help-fns-examples-function-test ()
+  "Test that `shortdoc-help-fns-examples-function' correctly prints ELisp function examples."
+  (with-temp-buffer
+    (shortdoc-help-fns-examples-function 'string-fill)
+    (should (equal "\n  Examples:\n\n  (string-fill \"Three short words\" 12)\n    => \"Three short\\nwords\"\n  (string-fill \"Long-word\" 3)\n    => \"Long-word\"\n\n"
+                   (buffer-substring-no-properties (point-min) (point-max))))
+    (erase-buffer)
+    (shortdoc-help-fns-examples-function 'assq)
+    (should (equal "\n  Examples:\n\n  (assq 'foo '((foo . bar) (zot . baz)))\n    => (foo . bar)\n\n  (assq 'b '((a . 1) (b . 2)))\n    => (b . 2)\n\n"
+                   (buffer-substring-no-properties (point-min) (point-max))))
+    (erase-buffer)
+    (shortdoc-help-fns-examples-function 'string-trim)
+    (should (equal "\n  Example:\n\n  (string-trim \" foo \")\n    => \"foo\"\n\n"
+                   (buffer-substring-no-properties (point-min) (point-max))))))
+
 (provide 'shortdoc-tests)
 
 ;;; shortdoc-tests.el ends here
-- 
2.34.1