diff options
| author | Daniel Martín | 2023-02-28 23:15:40 +0100 |
|---|---|---|
| committer | Eli Zaretskii | 2023-03-12 09:54:06 +0200 |
| commit | 29227e7c19100bed30b3410b399ee6a2c1ca7213 (patch) | |
| tree | 4cfde01d3e6841d9ea54194c1e3bb785d464c8b7 | |
| parent | 31f18480ca7291070837a305c64685c3e76afde3 (diff) | |
| download | emacs-29227e7c19100bed30b3410b399ee6a2c1ca7213.tar.gz emacs-29227e7c19100bed30b3410b399ee6a2c1ca7213.zip | |
Add functions to query Emacs Lisp examples registered in shortdoc
* lisp/emacs-lisp/shortdoc.el (shortdoc--display-function): Add
a new shortdoc-example text property so that ELisp examples can
be searched for later.
(shortdoc--insert-group-in-buffer): New function extracted from
the buffer insertion code in 'shortdoc-display-group'.
(shortdoc-display-group): Implement in terms of
'shortdoc--insert-group-in-buffer'.
(shortdoc-function-examples): New function that returns an alist
of Emacs Lisp examples from shortdoc.
(shortdoc-help-fns-examples-function): New function to insert
Emacs Lisp function examples in *Help* buffers, if added to
'help-fns-describe-function-functions'.
*
test/lisp/emacs-lisp/shortdoc-tests.el (shortdoc-function-examples-test):
Test it.
* doc/emacs/help.texi (Name Help): Document in the user manual.
* doc/lispref/help.texi (Documentation Groups): Document it.
* etc/NEWS: Advertise it. (Bug#61877)
| -rw-r--r-- | doc/emacs/help.texi | 9 | ||||
| -rw-r--r-- | doc/lispref/help.texi | 26 | ||||
| -rw-r--r-- | etc/NEWS | 18 | ||||
| -rw-r--r-- | lisp/emacs-lisp/shortdoc.el | 122 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/shortdoc-tests.el | 10 |
5 files changed, 149 insertions, 36 deletions
diff --git a/doc/emacs/help.texi b/doc/emacs/help.texi index 2513e6be271..10c007eb635 100644 --- a/doc/emacs/help.texi +++ b/doc/emacs/help.texi | |||
| @@ -316,6 +316,15 @@ there's a doc string there. | |||
| 316 | by using the @kbd{M-x shortdoc} command. This will prompt you for an | 316 | by using the @kbd{M-x shortdoc} command. This will prompt you for an |
| 317 | area of interest, e.g., @code{string}, and pop you to a buffer where | 317 | area of interest, e.g., @code{string}, and pop you to a buffer where |
| 318 | many of the functions relevant for handling strings are listed. | 318 | many of the functions relevant for handling strings are listed. |
| 319 | Here's an example you can include in your initialization file | ||
| 320 | (@pxref{Init File}) that uses @code{shortdoc} to insert Emacs Lisp | ||
| 321 | function examples into regular @file{*Help*} buffers when you use | ||
| 322 | @kbd{C-h f}: | ||
| 323 | |||
| 324 | @example | ||
| 325 | (add-hook 'help-fns-describe-function-functions | ||
| 326 | #'shortdoc-help-fns-examples-function) | ||
| 327 | @end example | ||
| 319 | 328 | ||
| 320 | @kindex C-h v | 329 | @kindex C-h v |
| 321 | @findex describe-variable | 330 | @findex describe-variable |
diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi index 59b6b6dab1d..3175f66122e 100644 --- a/doc/lispref/help.texi +++ b/doc/lispref/help.texi | |||
| @@ -989,3 +989,29 @@ in the function group to insert the function into. | |||
| 989 | If @var{group} doesn't exist, it will be created. If @var{section} | 989 | If @var{group} doesn't exist, it will be created. If @var{section} |
| 990 | doesn't exist, it will be added to the end of the function group. | 990 | doesn't exist, it will be added to the end of the function group. |
| 991 | @end defun | 991 | @end defun |
| 992 | |||
| 993 | You can also query the examples of use of functions defined in | ||
| 994 | shortdoc groups. | ||
| 995 | |||
| 996 | @defun shortdoc-function-examples function | ||
| 997 | This function returns all shortdoc examples for @var{function}. The | ||
| 998 | result is an alist with items of the form | ||
| 999 | |||
| 1000 | @example | ||
| 1001 | (@var{group} . @var{examples}) | ||
| 1002 | @end example | ||
| 1003 | |||
| 1004 | @noindent | ||
| 1005 | where @var{group} is a documentation group where @var{function} | ||
| 1006 | appears in and @var{examples} is a string with the examples of use of | ||
| 1007 | @var{function} defined in @var{group}. | ||
| 1008 | |||
| 1009 | @code{shortdoc-function-examples} returns @code{nil} if @var{function} | ||
| 1010 | is not a function or if it doesn’t contain shortdoc information. | ||
| 1011 | @end defun | ||
| 1012 | |||
| 1013 | @defun shortdoc-help-fns-examples-function function | ||
| 1014 | This function queries the registered documentation groups and inserts | ||
| 1015 | examples of use of a given Emacs Lisp function into the current | ||
| 1016 | buffer. | ||
| 1017 | @end defun | ||
| @@ -220,6 +220,24 @@ asynchronously (which is the default behavior). | |||
| 220 | *** New face 'doc-view-svg-face'. | 220 | *** New face 'doc-view-svg-face'. |
| 221 | This replaces 'doc-view-svg-foreground' and 'doc-view-svg-background'. | 221 | This replaces 'doc-view-svg-foreground' and 'doc-view-svg-background'. |
| 222 | 222 | ||
| 223 | ** Shortdoc | ||
| 224 | |||
| 225 | +++ | ||
| 226 | *** New function 'shortdoc-function-examples'. | ||
| 227 | This function queries the registered documentation groups and returns | ||
| 228 | examples of use of a given Emacs Lisp function. | ||
| 229 | |||
| 230 | +++ | ||
| 231 | *** New function 'shortdoc-help-fns-examples-function'. | ||
| 232 | This function queries the registered documentation groups and inserts | ||
| 233 | examples of use of a given Emacs Lisp function into the current | ||
| 234 | buffer. If you want to insert Emacs Lisp function examples into | ||
| 235 | regular *Help* buffers when you use 'describe-function', add the | ||
| 236 | following to you init file: | ||
| 237 | |||
| 238 | (add-hook 'help-fns-describe-function-functions | ||
| 239 | #'shortdoc-help-fns-examples-function) | ||
| 240 | |||
| 223 | 241 | ||
| 224 | * New Modes and Packages in Emacs 30.1 | 242 | * New Modes and Packages in Emacs 30.1 |
| 225 | 243 | ||
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index c49960c2ee6..cf66a43fc35 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el | |||
| @@ -1443,45 +1443,51 @@ If SAME-WINDOW, don't pop to a new window." | |||
| 1443 | (setq group (intern group))) | 1443 | (setq group (intern group))) |
| 1444 | (unless (assq group shortdoc--groups) | 1444 | (unless (assq group shortdoc--groups) |
| 1445 | (error "No such documentation group %s" group)) | 1445 | (error "No such documentation group %s" group)) |
| 1446 | (funcall (if same-window | 1446 | (let ((buf (get-buffer-create (format "*Shortdoc %s*" group)))) |
| 1447 | #'pop-to-buffer-same-window | 1447 | (shortdoc--insert-group-in-buffer group buf) |
| 1448 | #'pop-to-buffer) | 1448 | (funcall (if same-window |
| 1449 | (format "*Shortdoc %s*" group)) | 1449 | #'pop-to-buffer-same-window |
| 1450 | (let ((inhibit-read-only t) | 1450 | #'pop-to-buffer) |
| 1451 | (prev nil)) | 1451 | buf)) |
| 1452 | (erase-buffer) | ||
| 1453 | (shortdoc-mode) | ||
| 1454 | (button-mode) | ||
| 1455 | (mapc | ||
| 1456 | (lambda (data) | ||
| 1457 | (cond | ||
| 1458 | ((stringp data) | ||
| 1459 | (setq prev nil) | ||
| 1460 | (unless (bobp) | ||
| 1461 | (insert "\n")) | ||
| 1462 | (insert (propertize | ||
| 1463 | (substitute-command-keys data) | ||
| 1464 | 'face 'shortdoc-heading | ||
| 1465 | 'shortdoc-section t | ||
| 1466 | 'outline-level 1)) | ||
| 1467 | (insert (propertize | ||
| 1468 | "\n\n" | ||
| 1469 | 'face 'shortdoc-heading | ||
| 1470 | 'shortdoc-section t))) | ||
| 1471 | ;; There may be functions not yet defined in the data. | ||
| 1472 | ((fboundp (car data)) | ||
| 1473 | (when prev | ||
| 1474 | (insert (make-separator-line) | ||
| 1475 | ;; This helps with hidden outlines (bug#53981) | ||
| 1476 | (propertize "\n" 'face '(:height 0)))) | ||
| 1477 | (setq prev t) | ||
| 1478 | (shortdoc--display-function data)))) | ||
| 1479 | (cdr (assq group shortdoc--groups)))) | ||
| 1480 | (goto-char (point-min)) | 1452 | (goto-char (point-min)) |
| 1481 | (when function | 1453 | (when function |
| 1482 | (text-property-search-forward 'shortdoc-function function t) | 1454 | (text-property-search-forward 'shortdoc-function function t) |
| 1483 | (beginning-of-line))) | 1455 | (beginning-of-line))) |
| 1484 | 1456 | ||
| 1457 | (defun shortdoc--insert-group-in-buffer (group &optional buf) | ||
| 1458 | "Insert a short documentation summary for functions in GROUP in buffer BUF." | ||
| 1459 | (with-current-buffer (or buf (current-buffer)) | ||
| 1460 | (let ((inhibit-read-only t) | ||
| 1461 | (prev nil)) | ||
| 1462 | (erase-buffer) | ||
| 1463 | (shortdoc-mode) | ||
| 1464 | (button-mode) | ||
| 1465 | (mapc | ||
| 1466 | (lambda (data) | ||
| 1467 | (cond | ||
| 1468 | ((stringp data) | ||
| 1469 | (setq prev nil) | ||
| 1470 | (unless (bobp) | ||
| 1471 | (insert "\n")) | ||
| 1472 | (insert (propertize | ||
| 1473 | (substitute-command-keys data) | ||
| 1474 | 'face 'shortdoc-heading | ||
| 1475 | 'shortdoc-section t | ||
| 1476 | 'outline-level 1)) | ||
| 1477 | (insert (propertize | ||
| 1478 | "\n\n" | ||
| 1479 | 'face 'shortdoc-heading | ||
| 1480 | 'shortdoc-section t))) | ||
| 1481 | ;; There may be functions not yet defined in the data. | ||
| 1482 | ((fboundp (car data)) | ||
| 1483 | (when prev | ||
| 1484 | (insert (make-separator-line) | ||
| 1485 | ;; This helps with hidden outlines (bug#53981) | ||
| 1486 | (propertize "\n" 'face '(:height 0)))) | ||
| 1487 | (setq prev t) | ||
| 1488 | (shortdoc--display-function data)))) | ||
| 1489 | (cdr (assq group shortdoc--groups)))))) | ||
| 1490 | |||
| 1485 | ;;;###autoload | 1491 | ;;;###autoload |
| 1486 | (defalias 'shortdoc #'shortdoc-display-group) | 1492 | (defalias 'shortdoc #'shortdoc-display-group) |
| 1487 | 1493 | ||
| @@ -1521,7 +1527,8 @@ function's documentation in the Info manual")) | |||
| 1521 | "=>")) | 1527 | "=>")) |
| 1522 | (single-arrow (if (char-displayable-p ?→) | 1528 | (single-arrow (if (char-displayable-p ?→) |
| 1523 | "→" | 1529 | "→" |
| 1524 | "->"))) | 1530 | "->")) |
| 1531 | (start-example (point))) | ||
| 1525 | (cl-loop for (type value) on data by #'cddr | 1532 | (cl-loop for (type value) on data by #'cddr |
| 1526 | do | 1533 | do |
| 1527 | (cl-case type | 1534 | (cl-case type |
| @@ -1572,7 +1579,8 @@ function's documentation in the Info manual")) | |||
| 1572 | (:eg-result-string | 1579 | (:eg-result-string |
| 1573 | (insert " e.g. " double-arrow " ") | 1580 | (insert " e.g. " double-arrow " ") |
| 1574 | (princ value (current-buffer)) | 1581 | (princ value (current-buffer)) |
| 1575 | (insert "\n"))))) | 1582 | (insert "\n")))) |
| 1583 | (add-text-properties start-example (point) `(shortdoc-example ,function))) | ||
| 1576 | ;; Insert the arglist after doing the evals, in case that's pulled | 1584 | ;; Insert the arglist after doing the evals, in case that's pulled |
| 1577 | ;; in the function definition. | 1585 | ;; in the function definition. |
| 1578 | (save-excursion | 1586 | (save-excursion |
| @@ -1582,6 +1590,48 @@ function's documentation in the Info manual")) | |||
| 1582 | (insert " " (symbol-name param))) | 1590 | (insert " " (symbol-name param))) |
| 1583 | (add-face-text-property arglist-start (point) 'shortdoc-section t)))) | 1591 | (add-face-text-property arglist-start (point) 'shortdoc-section t)))) |
| 1584 | 1592 | ||
| 1593 | (defun shortdoc-function-examples (function) | ||
| 1594 | "Return all shortdoc examples for FUNCTION. | ||
| 1595 | The result is an alist with items of the form (GROUP . EXAMPLES), | ||
| 1596 | where GROUP is a shortdoc group where FUNCTION appears in and | ||
| 1597 | EXAMPLES is a string with the usage examples of FUNCTION defined | ||
| 1598 | in GROUP. Return nil if FUNCTION is not a function or if it | ||
| 1599 | doesn't contain shortdoc information." | ||
| 1600 | (let ((groups (and (symbolp function) | ||
| 1601 | (shortdoc-function-groups function))) | ||
| 1602 | (examples nil)) | ||
| 1603 | (mapc | ||
| 1604 | (lambda (group) | ||
| 1605 | (with-temp-buffer | ||
| 1606 | (shortdoc--insert-group-in-buffer group) | ||
| 1607 | (goto-char (point-min)) | ||
| 1608 | (setq match (text-property-search-forward | ||
| 1609 | 'shortdoc-example function t)) | ||
| 1610 | (push `(,group . ,(string-trim | ||
| 1611 | (buffer-substring-no-properties | ||
| 1612 | (prop-match-beginning match) | ||
| 1613 | (prop-match-end match)))) | ||
| 1614 | examples))) | ||
| 1615 | groups) | ||
| 1616 | examples)) | ||
| 1617 | |||
| 1618 | (defun shortdoc-help-fns-examples-function (function) | ||
| 1619 | "Insert Emacs Lisp examples for FUNCTION into the current buffer. | ||
| 1620 | You can add this function to the | ||
| 1621 | `help-fns-describe-function-functions' list to show function | ||
| 1622 | example documentation in *Help* buffers." | ||
| 1623 | (let ((examples (shortdoc-function-examples function)) | ||
| 1624 | (times 0)) | ||
| 1625 | (dolist (example examples) | ||
| 1626 | (when (zerop times) | ||
| 1627 | (if (eq (length examples) 1) | ||
| 1628 | (insert " Example:\n\n") | ||
| 1629 | (insert " Examples:\n\n"))) | ||
| 1630 | (setq times (1+ times)) | ||
| 1631 | (insert " ") | ||
| 1632 | (insert (cdr example)) | ||
| 1633 | (insert "\n\n")))) | ||
| 1634 | |||
| 1585 | (defun shortdoc-function-groups (function) | 1635 | (defun shortdoc-function-groups (function) |
| 1586 | "Return all shortdoc groups FUNCTION appears in." | 1636 | "Return all shortdoc groups FUNCTION appears in." |
| 1587 | (cl-loop for group in shortdoc--groups | 1637 | (cl-loop for group in shortdoc--groups |
diff --git a/test/lisp/emacs-lisp/shortdoc-tests.el b/test/lisp/emacs-lisp/shortdoc-tests.el index 516d095767f..a65a4a5ddc3 100644 --- a/test/lisp/emacs-lisp/shortdoc-tests.el +++ b/test/lisp/emacs-lisp/shortdoc-tests.el | |||
| @@ -65,6 +65,16 @@ | |||
| 65 | (when buf | 65 | (when buf |
| 66 | (kill-buffer buf)))))) | 66 | (kill-buffer buf)))))) |
| 67 | 67 | ||
| 68 | (ert-deftest shortdoc-function-examples-test () | ||
| 69 | "Test the extraction of usage examples of some Elisp functions." | ||
| 70 | (should (equal '((list . "(delete 2 (list 1 2 3 4))\n => (1 3 4)\n (delete \"a\" (list \"a\" \"b\" \"c\" \"d\"))\n => (\"b\" \"c\" \"d\")")) | ||
| 71 | (shortdoc-function-examples 'delete))) | ||
| 72 | (should (equal '((alist . "(assq 'foo '((foo . bar) (zot . baz)))\n => (foo . bar)") | ||
| 73 | (list . "(assq 'b '((a . 1) (b . 2)))\n => (b . 2)")) | ||
| 74 | (shortdoc-function-examples 'assq))) | ||
| 75 | (should (equal '((regexp . "(string-match-p \"^[fo]+\" \"foobar\")\n => 0")) | ||
| 76 | (shortdoc-function-examples 'string-match-p)))) | ||
| 77 | |||
| 68 | (provide 'shortdoc-tests) | 78 | (provide 'shortdoc-tests) |
| 69 | 79 | ||
| 70 | ;;; shortdoc-tests.el ends here | 80 | ;;; shortdoc-tests.el ends here |