summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/shortdoc.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp/shortdoc.el')
-rw-r--r--lisp/emacs-lisp/shortdoc.el470
1 files changed, 365 insertions, 105 deletions
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 99035c9e892..ed4e205d204 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1,6 +1,6 @@
;;; shortdoc.el --- Short function summaries -*- lexical-binding: t -*-
-;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
+;; Copyright (C) 2020-2023 Free Software Foundation, Inc.
;; Keywords: lisp, help
;; Package: emacs
@@ -22,6 +22,15 @@
;;; Commentary:
+;; This package lists functions based on various groupings.
+;;
+;; For instance, `string-trim' and `mapconcat' are `string' functions,
+;; so `M-x shortdoc RET string RET' will give an overview of functions
+;; that operate on strings.
+;;
+;; The documentation groups are created with the
+;; `define-short-documentation-group' macro.
+
;;; Code:
(require 'seq)
@@ -41,40 +50,78 @@
'((t :inherit variable-pitch))
"Face used for a section.")
-(defvar shortdoc--groups nil)
+;;;###autoload
+(progn
+ (defvar shortdoc--groups nil)
-(defmacro define-short-documentation-group (group &rest functions)
- "Add GROUP to the list of defined documentation groups.
+ (defmacro define-short-documentation-group (group &rest functions)
+ "Add GROUP to the list of defined documentation groups.
FUNCTIONS is a list of elements on the form:
- (fun
+ (FUNC
:no-manual BOOL
:args ARGS
- :eval EXAMPLE-FORM
+ :eval EVAL
:no-eval EXAMPLE-FORM
- :no-eval* EXAMPLE-FORM
:no-value EXAMPLE-FORM
+ :no-eval* EXAMPLE-FORM
:result RESULT-FORM
- :result-string RESULT-FORM
+ :result-string RESULT-STRING
:eg-result RESULT-FORM
- :eg-result-string RESULT-FORM)
+ :eg-result-string RESULT-STRING)
+
+FUNC is the function being documented.
-BOOL should be non-nil if the function isn't documented in the
+NO-MANUAL should be non-nil if FUNC isn't documented in the
manual.
-ARGS is optional; the function's signature is displayed if ARGS
-is not present.
+ARGS is optional list of function FUNC's arguments. FUNC's
+signature is displayed automatically if ARGS is not present.
+Specifying ARGS might be useful where you don't want to document
+some of the uncommon arguments a function might have.
-If EVAL isn't a string, it will be printed with `prin1', and then
-evaluated to give a result, which is also printed. If it's a
-string, it'll be inserted as is, then the string will be `read',
-and then evaluated.
+While the `:no-manual' and `:args' property can be used for
+any (FUNC ..) form, all of the other properties shown above
+cannot be used simultaneously in such a form.
-There can be any number of :example/:result elements."
- `(progn
- (setq shortdoc--groups (delq (assq ',group shortdoc--groups)
- shortdoc--groups))
- (push (cons ',group ',functions) shortdoc--groups)))
+Here are some common forms with examples of properties that go
+together:
+
+1. Document a form or string, and its evaluated return value.
+ (FUNC
+ :eval EVAL)
+
+If EVAL is a string, it will be inserted as is, and then that
+string will be `read' and evaluated.
+
+2. Document a form or string, but manually document its evaluation
+ result. The provided form will not be evaluated.
+
+ (FUNC
+ :no-eval EXAMPLE-FORM
+ :result RESULT-FORM) ;Use `:result-string' if value is in string form
+
+Using `:no-value' is the same as using `:no-eval'.
+
+Use `:no-eval*' instead of `:no-eval' where the successful
+execution of the documented form depends on some conditions.
+
+3. Document a form or string EXAMPLE-FORM. Also manually
+ document an example result. This result could be unrelated to
+ the documented form.
+
+ (FUNC
+ :no-eval EXAMPLE-FORM
+ :eg-result RESULT-FORM) ;Use `:eg-result-string' if value is in string form
+
+A FUNC form can have any number of `:no-eval' (or `:no-value'),
+`:no-eval*', `:result', `:result-string', `:eg-result' and
+`:eg-result-string' properties."
+ (declare (indent defun))
+ `(progn
+ (setq shortdoc--groups (delq (assq ',group shortdoc--groups)
+ shortdoc--groups))
+ (push (cons ',group ',functions) shortdoc--groups))))
(define-short-documentation-group alist
"Alist Basics"
@@ -195,19 +242,33 @@ There can be any number of :example/:result elements."
:eval (substring-no-properties (propertize "foobar" 'face 'bold) 0 3))
(try-completion
:eval (try-completion "foo" '("foobar" "foozot" "gazonk")))
+ "Unicode Strings"
+ (string-glyph-split
+ :eval (string-glyph-split "Hello, πŸ‘ΌπŸ»πŸ§‘πŸΌβ€πŸ€β€πŸ§‘πŸ»"))
+ (string-glyph-compose
+ :eval (string-glyph-compose "Å"))
+ (string-glyph-decompose
+ :eval (string-glyph-decompose "β„«"))
"Predicates for Strings"
(string-equal
- :eval (string-equal "foo" "foo"))
- (eq
- :eval (eq "foo" "foo"))
- (eql
- :eval (eql "foo" "foo"))
+ :eval (string-equal "abc" "abc")
+ :eval (string-equal "abc" "ABC"))
+ (string-equal-ignore-case
+ :eval (string-equal-ignore-case "foo" "FOO"))
(equal
:eval (equal "foo" "foo"))
(cl-equalp
:eval (cl-equalp "Foo" "foo"))
(stringp
+ :eval (stringp "a")
+ :eval (stringp 'a)
:eval "(stringp ?a)")
+ (string-or-null-p
+ :eval (string-or-null-p "a")
+ :eval (string-or-null-p nil))
+ (char-or-string-p
+ :eval "(char-or-string-p ?a)"
+ :eval (char-or-string-p "a"))
(string-empty-p
:no-manual t
:eval (string-empty-p ""))
@@ -215,11 +276,16 @@ There can be any number of :example/:result elements."
:no-manual t
:eval (string-blank-p " \n"))
(string-lessp
- :eval (string-lessp "foo" "bar"))
+ :eval (string-lessp "abc" "def")
+ :eval (string-lessp "pic4.png" "pic32.png")
+ :eval (string-lessp "1.1" "1.2"))
(string-greaterp
:eval (string-greaterp "foo" "bar"))
(string-version-lessp
- :eval (string-version-lessp "pic4.png" "pic32.png"))
+ :eval (string-version-lessp "pic4.png" "pic32.png")
+ :eval (string-version-lessp "1.9.3" "1.10.2"))
+ (string-collate-lessp
+ :eval (string-collate-lessp "abc" "abd"))
(string-prefix-p
:eval (string-prefix-p "foo" "foobar"))
(string-suffix-p
@@ -236,12 +302,23 @@ There can be any number of :example/:result elements."
"Converting Strings"
(string-to-number
:eval (string-to-number "42")
- :eval (string-to-number "deadbeef" 16))
+ :eval (string-to-number "deadbeef" 16)
+ :eval (string-to-number "2.5e+03"))
(number-to-string
:eval (number-to-string 42))
+ (char-uppercase-p
+ :eval "(char-uppercase-p ?A)"
+ :eval "(char-uppercase-p ?a)")
"Data About Strings"
(length
- :eval (length "foo"))
+ :eval (length "foo")
+ :eval (length "avocado: πŸ₯‘"))
+ (string-width
+ :eval (string-width "foo")
+ :eval (string-width "avocado: πŸ₯‘"))
+ (string-pixel-width
+ :eval (string-pixel-width "foo")
+ :eval (string-pixel-width "avocado: πŸ₯‘"))
(string-search
:eval (string-search "bar" "foobarzot"))
(assoc-string
@@ -271,6 +348,9 @@ There can be any number of :example/:result elements."
:eval (file-name-base "/tmp/foo.txt"))
(file-relative-name
:eval (file-relative-name "/tmp/foo" "/tmp"))
+ (file-name-split
+ :eval (file-name-split "/tmp/foo")
+ :eval (file-name-split "foo/bar"))
(make-temp-name
:eval (make-temp-name "/tmp/foo-"))
(file-name-concat
@@ -293,6 +373,11 @@ There can be any number of :example/:result elements."
(abbreviate-file-name
:no-eval (abbreviate-file-name "/home/some-user")
:eg-result "~some-user")
+ (file-name-parent-directory
+ :eval (file-name-parent-directory "/foo/bar")
+ :eval (file-name-parent-directory "/foo/")
+ :eval (file-name-parent-directory "foo/bar")
+ :eval (file-name-parent-directory "foo"))
"Quoted File Names"
(file-name-quote
:args (name)
@@ -336,8 +421,8 @@ There can be any number of :example/:result elements."
(file-readable-p
:no-eval (file-readable-p "/tmp/foo")
:eg-result t)
- (file-writeable-p
- :no-eval (file-writeable-p "/tmp/foo")
+ (file-writable-p
+ :no-eval (file-writable-p "/tmp/foo")
:eg-result t)
(file-accessible-directory-p
:no-eval (file-accessible-directory-p "/tmp")
@@ -348,6 +433,9 @@ There can be any number of :example/:result elements."
(file-newer-than-file-p
:no-eval (file-newer-than-file-p "/tmp/foo" "/tmp/bar")
:eg-result nil)
+ (file-has-changed-p
+ :no-eval (file-has-changed-p "/tmp/foo")
+ :eg-result t)
(file-equal-p
:no-eval (file-equal-p "/tmp/foo" "/tmp/bar")
:eg-result nil)
@@ -405,7 +493,9 @@ There can be any number of :example/:result elements."
:no-eval* (directory-files-and-attributes "/tmp/foo"))
(file-expand-wildcards
:no-eval (file-expand-wildcards "/tmp/*.png")
- :eg-result ("/tmp/foo.png" "/tmp/zot.png"))
+ :eg-result ("/tmp/foo.png" "/tmp/zot.png")
+ :no-eval (file-expand-wildcards "/*/foo.png")
+ :eg-result ("/tmp/foo.png" "/var/foo.png"))
(locate-dominating-file
:no-eval (locate-dominating-file "foo.png" "/tmp/foo/bar/zot")
:eg-result "/tmp/foo.png")
@@ -429,7 +519,7 @@ There can be any number of :example/:result elements."
(set-file-modes
:no-value "(set-file-modes \"/tmp/foo\" #o644)")
(set-file-times
- :no-value (set-file-times "/tmp/foo" (current-time)))
+ :no-value (set-file-times "/tmp/foo"))
"File Modes"
(set-default-file-modes
:no-value "(set-default-file-modes #o755)")
@@ -523,6 +613,10 @@ There can be any number of :example/:result elements."
:eval (nth 1 '(one two three)))
(nthcdr
:eval (nthcdr 1 '(one two three)))
+ (take
+ :eval (take 3 '(one two three four)))
+ (ntake
+ :eval (ntake 3 (list 'one 'two 'three 'four)))
(elt
:eval (elt '(one two three) 1))
(car-safe
@@ -542,8 +636,7 @@ There can be any number of :example/:result elements."
(nconc
:eval (nconc (list 1) (list 2 3 4)))
(delq
- :eval (delq 2 (list 1 2 3 4))
- :eval (delq "a" (list "a" "b" "c" "d")))
+ :eval (delq 'a (list 'a 'b 'c 'd)))
(delete
:eval (delete 2 (list 1 2 3 4))
:eval (delete "a" (list "a" "b" "c" "d")))
@@ -559,8 +652,8 @@ There can be any number of :example/:result elements."
:eval (mapcan #'list '(1 2 3)))
(mapc
:eval (mapc #'insert '("1" "2" "3")))
- (reduce
- :eval (reduce #'+ '(1 2 3)))
+ (seq-reduce
+ :eval (seq-reduce #'+ '(1 2 3) 0))
(mapconcat
:eval (mapconcat #'identity '("foo" "bar") "|"))
"Predicates"
@@ -585,29 +678,25 @@ There can be any number of :example/:result elements."
:eval (nlistp '(1 . 2)))
"Finding Elements"
(memq
- :eval (memq 2 '(1 2 3))
- :eval (memq 2.0 '(1.0 2.0 3.0))
- :eval (memq "b" '("a" "b" "c")))
+ :eval (memq 'b '(a b c)))
+ (memql
+ :eval (memql 2.0 '(1.0 2.0 3.0)))
(member
:eval (member 2 '(1 2 3))
:eval (member "b" '("a" "b" "c")))
(remq
- :eval (remq 2 '(1 2 3 2 4 2))
- :eval (remq "b" '("a" "b" "c")))
- (memql
- :eval (memql 2.0 '(1.0 2.0 3.0)))
+ :eval (remq 'b '(a b c)))
(member-ignore-case
:eval (member-ignore-case "foo" '("bar" "Foo" "zot")))
"Association Lists"
(assoc
- :eval (assoc 'b '((a 1) (b 2))))
+ :eval (assoc "b" '(("a" . 1) ("b" . 2))))
(rassoc
- :eval (rassoc '2 '((a . 1) (b . 2))))
+ :eval (rassoc "b" '((1 . "a") (2 . "b"))))
(assq
- :eval (assq 'b '((a 1) (b 2)))
- :eval (assq "a" '(("a" 1) ("b" 2))))
+ :eval (assq 'b '((a . 1) (b . 2))))
(rassq
- :eval (rassq '2 '((a . 1) (b . 2))))
+ :eval (rassq 'b '((1 . a) (2 . b))))
(assoc-string
:eval (assoc-string "foo" '(("a" 1) (foo 2))))
(alist-get
@@ -626,11 +715,6 @@ There can be any number of :example/:result elements."
(plist-put
:no-eval (setq plist (plist-put plist 'd 4))
:eq-result (a 1 b 2 c 3 d 4))
- (lax-plist-get
- :eval (lax-plist-get '("a" 1 "b" 2 "c" 3) "b"))
- (lax-plist-put
- :no-eval (setq plist (lax-plist-put plist "d" 4))
- :eq-result '("a" 1 "b" 2 "c" 3 "d" 4))
(plist-member
:eval (plist-member '(a 1 b 2 c 3) 'b))
"Data About Lists"
@@ -645,6 +729,88 @@ There can be any number of :example/:result elements."
(safe-length
:eval (safe-length '(a b c))))
+(define-short-documentation-group symbol
+ "Making symbols"
+ (intern
+ :eval (intern "abc"))
+ (intern-soft
+ :eval (intern-soft "Phooey!"))
+ (make-symbol
+ :eval (make-symbol "abc"))
+ "Comparing symbols"
+ (eq
+ :eval (eq 'abc 'abc)
+ :eval (eq 'abc 'abd))
+ (eql
+ :eval (eql 'abc 'abc))
+ (equal
+ :eval (equal 'abc 'abc))
+ "Name"
+ (symbol-name
+ :eval (symbol-name 'abc)))
+
+(define-short-documentation-group comparison
+ "General-purpose"
+ (eq
+ :eval (eq 'a 'a)
+ :eval "(eq ?A ?A)"
+ :eval (let ((x (list 'a "b" '(c) 4 5.0)))
+ (eq x x)))
+ (eql
+ :eval (eql 2 2)
+ :eval (eql 2.0 2.0)
+ :eval (eql 2.0 2))
+ (equal
+ :eval (equal "abc" "abc")
+ :eval (equal 2.0 2.0)
+ :eval (equal 2.0 2)
+ :eval (equal '(a "b" (c) 4.0) '(a "b" (c) 4.0)))
+ (cl-equalp
+ :eval (cl-equalp 2 2.0)
+ :eval (cl-equalp "ABC" "abc"))
+ "Numeric"
+ (=
+ :args (number &rest numbers)
+ :eval (= 2 2)
+ :eval (= 2.0 2.0)
+ :eval (= 2.0 2)
+ :eval (= 4 4 4 4))
+ (/=
+ :eval (/= 4 4))
+ (<
+ :args (number &rest numbers)
+ :eval (< 4 4)
+ :eval (< 1 2 3))
+ (<=
+ :args (number &rest numbers)
+ :eval (<= 4 4)
+ :eval (<= 1 2 2 3))
+ (>
+ :args (number &rest numbers)
+ :eval (> 4 4)
+ :eval (> 3 2 1))
+ (>=
+ :args (number &rest numbers)
+ :eval (>= 4 4)
+ :eval (>= 3 2 2 1))
+ "String"
+ (string-equal
+ :eval (string-equal "abc" "abc")
+ :eval (string-equal "abc" "ABC"))
+ (string-equal-ignore-case
+ :eval (string-equal-ignore-case "abc" "ABC"))
+ (string-lessp
+ :eval (string-lessp "abc" "abd")
+ :eval (string-lessp "abc" "abc")
+ :eval (string-lessp "pic4.png" "pic32.png"))
+ (string-greaterp
+ :eval (string-greaterp "abd" "abc")
+ :eval (string-greaterp "abc" "abc"))
+ (string-version-lessp
+ :eval (string-version-lessp "pic4.png" "pic32.png")
+ :eval (string-version-lessp "1.9.3" "1.10.2"))
+ (string-collate-lessp
+ :eval (string-collate-lessp "abc" "abd")))
(define-short-documentation-group vector
"Making Vectors"
@@ -753,7 +919,7 @@ There can be any number of :example/:result elements."
(seq-set-equal-p
:eval (seq-set-equal-p '(1 2 3) '(3 1 2)))
(seq-some
- :eval (seq-some #'cl-evenp '(1 2 3)))
+ :eval (seq-some #'floatp '(1 2.0 3)))
"Building Sequences"
(seq-concatenate
:eval (seq-concatenate 'vector '(1 2) '(c d)))
@@ -773,6 +939,10 @@ There can be any number of :example/:result elements."
:eval (seq-find #'numberp '(a b 3 4 f 6)))
(seq-position
:eval (seq-position '(a b c) 'c))
+ (seq-positions
+ :eval (seq-positions '(a b c a d) 'a)
+ :eval (seq-positions '(a b c a d) 'z)
+ :eval (seq-positions '(11 5 7 12 9 15) 10 #'>=))
(seq-length
:eval (seq-length "abcde"))
(seq-max
@@ -813,10 +983,15 @@ There can be any number of :example/:result elements."
:eval (seq-drop-while #'numberp '(1 2 c d 5)))
(seq-filter
:eval (seq-filter #'numberp '(a b 3 4 f 6)))
+ (seq-keep
+ :eval (seq-keep #'car-safe '((1 2) 3 t (a . b))))
(seq-remove
:eval (seq-remove #'numberp '(1 2 c d 5)))
+ (seq-remove-at-position
+ :eval (seq-remove-at-position '(a b c d e) 3)
+ :eval (seq-remove-at-position [a b c d e] 0))
(seq-group-by
- :eval (seq-group-by #'cl-plusp '(-1 2 3 -4 -5 6)))
+ :eval (seq-group-by #'natnump '(-1 2 3 -4 -5 6)))
(seq-union
:eval (seq-union '(1 2 3) '(3 5)))
(seq-difference
@@ -829,8 +1004,10 @@ There can be any number of :example/:result elements."
:eval (seq-subseq '(a b c d e) 2 4))
(seq-take
:eval (seq-take '(a b c d e) 3))
+ (seq-split
+ :eval (seq-split [0 1 2 3 5] 2))
(seq-take-while
- :eval (seq-take-while #'cl-evenp [2 4 9 6 5]))
+ :eval (seq-take-while #'integerp [1 2 3.0 4]))
(seq-uniq
:eval (seq-uniq '(a b d b a c))))
@@ -866,12 +1043,24 @@ There can be any number of :example/:result elements."
:eval (point-min))
(point-max
:eval (point-max))
+ (pos-bol
+ :eval (pos-bol))
+ (pos-eol
+ :eval (pos-eol))
+ (bolp
+ :eval (bolp))
+ (eolp
+ :eval (eolp))
(line-beginning-position
:eval (line-beginning-position))
(line-end-position
:eval (line-end-position))
(buffer-size
:eval (buffer-size))
+ (bobp
+ :eval (bobp))
+ (eobp
+ :eval (eobp))
"Moving Around"
(goto-char
:no-eval (goto-char (point-max))
@@ -897,8 +1086,13 @@ There can be any number of :example/:result elements."
(following-char
:no-eval (following-char)
:eg-result 67)
+ (preceding-char
+ :no-eval (preceding-char)
+ :eg-result 38)
(char-after
:eval (char-after 45))
+ (char-before
+ :eval (char-before 13))
(get-byte
:no-eval (get-byte 45)
:eg-result-string "#xff")
@@ -907,6 +1101,8 @@ There can be any number of :example/:result elements."
:no-value (delete-region (point-min) (point-max)))
(erase-buffer
:no-value (erase-buffer))
+ (delete-line
+ :no-value (delete-line))
(insert
:no-value (insert "This string will be inserted in the buffer\n"))
(subst-char-in-region
@@ -1021,13 +1217,10 @@ There can be any number of :example/:result elements."
:args (number &rest numbers)
:eval (= 4 4)
:eval (= 4.0 4.0)
- :eval (= 4 5 6 7))
- (eq
- :eval (eq 4 4)
- :eval (eq 4.0 4.0))
+ :eval (= 4 4.0)
+ :eval (= 4 4 4 4))
(eql
:eval (eql 4 4)
- :eval (eql 4 "4")
:eval (eql 4.0 4.0))
(/=
:eval (/= 4 4))
@@ -1038,15 +1231,15 @@ There can be any number of :example/:result elements."
(<=
:args (number &rest numbers)
:eval (<= 4 4)
- :eval (<= 1 2 3))
+ :eval (<= 1 2 2 3))
(>
:args (number &rest numbers)
:eval (> 4 4)
- :eval (> 1 2 3))
+ :eval (> 3 2 1))
(>=
:args (number &rest numbers)
:eval (>= 4 4)
- :eval (>= 1 2 3))
+ :eval (>= 3 2 2 1))
(zerop
:eval (zerop 0))
(cl-plusp
@@ -1110,9 +1303,6 @@ There can be any number of :example/:result elements."
(ash
:eval (ash 1 4)
:eval (ash 16 -1))
- (lsh
- :eval (lsh 1 4)
- :eval (lsh 16 -1))
(logand
:no-eval "(logand #b10 #b111)"
:result-string "#b10")
@@ -1206,17 +1396,54 @@ There can be any number of :example/:result elements."
(text-property-search-backward
:no-eval (text-property-search-backward 'face nil t)))
+(define-short-documentation-group keymaps
+ "Defining keymaps"
+ (define-keymap
+ :no-eval (define-keymap "C-c C-c" #'quit-buffer))
+ (defvar-keymap
+ :no-eval (defvar-keymap my-keymap "C-c C-c" #'quit-buffer))
+ "Setting keys"
+ (keymap-set
+ :no-eval (keymap-set map "C-c C-c" #'quit-buffer))
+ (keymap-local-set
+ :no-eval (keymap-local-set "C-c C-c" #'quit-buffer))
+ (keymap-global-set
+ :no-eval (keymap-global-set "C-c C-c" #'quit-buffer))
+ (keymap-unset
+ :no-eval (keymap-unset map "C-c C-c"))
+ (keymap-local-unset
+ :no-eval (keymap-local-unset "C-c C-c"))
+ (keymap-global-unset
+ :no-eval (keymap-global-unset "C-c C-c"))
+ (keymap-substitute
+ :no-eval (keymap-substitute map "C-c C-c" "M-a"))
+ (keymap-set-after
+ :no-eval (keymap-set-after map "<separator-2>" menu-bar-separator))
+ "Predicates"
+ (keymapp
+ :eval (keymapp (define-keymap)))
+ (key-valid-p
+ :eval (key-valid-p "C-c C-c")
+ :eval (key-valid-p "C-cC-c"))
+ "Lookup"
+ (keymap-lookup
+ :eval (keymap-lookup (current-global-map) "C-x x g")))
+
;;;###autoload
-(defun shortdoc-display-group (group &optional function)
+(defun shortdoc-display-group (group &optional function same-window)
"Pop to a buffer with short documentation summary for functions in GROUP.
-If FUNCTION is non-nil, place point on the entry for FUNCTION (if any)."
+If FUNCTION is non-nil, place point on the entry for FUNCTION (if any).
+If SAME-WINDOW, don't pop to a new window."
(interactive (list (completing-read "Show summary for functions in: "
(mapcar #'car shortdoc--groups))))
(when (stringp group)
(setq group (intern group)))
(unless (assq group shortdoc--groups)
(error "No such documentation group %s" group))
- (pop-to-buffer (format "*Shortdoc %s*" group))
+ (funcall (if same-window
+ #'pop-to-buffer-same-window
+ #'pop-to-buffer)
+ (format "*Shortdoc %s*" group))
(let ((inhibit-read-only t)
(prev nil))
(erase-buffer)
@@ -1230,13 +1457,20 @@ If FUNCTION is non-nil, place point on the entry for FUNCTION (if any)."
(unless (bobp)
(insert "\n"))
(insert (propertize
- (concat (substitute-command-keys data) "\n\n")
+ (substitute-command-keys data)
+ 'face 'shortdoc-heading
+ 'shortdoc-section t
+ 'outline-level 1))
+ (insert (propertize
+ "\n\n"
'face 'shortdoc-heading
'shortdoc-section t)))
;; There may be functions not yet defined in the data.
((fboundp (car data))
(when prev
- (insert (make-separator-line)))
+ (insert (make-separator-line)
+ ;; This helps with hidden outlines (bug#53981)
+ (propertize "\n" 'face '(:height 0))))
(setq prev t)
(shortdoc--display-function data))))
(cdr (assq group shortdoc--groups))))
@@ -1245,12 +1479,15 @@ If FUNCTION is non-nil, place point on the entry for FUNCTION (if any)."
(text-property-search-forward 'shortdoc-function function t)
(beginning-of-line)))
+;;;###autoload
+(defalias 'shortdoc #'shortdoc-display-group)
+
(defun shortdoc--display-function (data)
(let ((function (pop data))
(start-section (point))
arglist-start)
;; Function calling convention.
- (insert (propertize "(" 'shortdoc-function function))
+ (insert (propertize "(" 'shortdoc-function function 'outline-level 2))
(if (plist-get data :no-manual)
(insert-text-button
(symbol-name function)
@@ -1258,15 +1495,15 @@ If FUNCTION is non-nil, place point on the entry for FUNCTION (if any)."
'action (lambda (_)
(describe-function function))
'follow-link t
- 'help-echo (purecopy "mouse-1, RET: describe function"))
+ 'help-echo "mouse-1, RET: describe function")
(insert-text-button
(symbol-name function)
'face 'button
'action (lambda (_)
(info-lookup-symbol function 'emacs-lisp-mode))
'follow-link t
- 'help-echo (purecopy "mouse-1, RET: show \
-function's documentation in the Info manual")))
+ 'help-echo "mouse-1, RET: show \
+function's documentation in the Info manual"))
(setq arglist-start (point))
(insert ")\n")
;; Doc string.
@@ -1286,14 +1523,16 @@ function's documentation in the Info manual")))
do
(cl-case type
(:eval
+ (insert " ")
(if (stringp value)
- (insert " " value "\n")
- (insert " ")
- (prin1 value (current-buffer))
- (insert "\n")
- (insert " " double-arrow " ")
- (prin1 (eval value) (current-buffer))
- (insert "\n")))
+ (insert value)
+ (prin1 value (current-buffer)))
+ (insert "\n " double-arrow " ")
+ (let ((expr (if (stringp value)
+ (car (read-from-string value))
+ value)))
+ (prin1 (eval expr) (current-buffer)))
+ (insert "\n"))
(:no-eval*
(if (stringp value)
(insert " " value "\n")
@@ -1351,11 +1590,14 @@ function's documentation in the Info manual")))
If GROUP doesn't exist, it will be created.
If SECTION doesn't exist, it will be added.
+ELEM is a Lisp form. See `define-short-documentation-group' for
+details.
+
Example:
(shortdoc-add-function
- 'file \"Predicates\"
- '(file-locked-p :no-eval (file-locked-p \"/tmp\")))"
+ \\='file \"Predicates\"
+ \\='(file-locked-p :no-eval (file-locked-p \"/tmp\")))"
(let ((glist (assq group shortdoc--groups)))
(unless glist
(setq glist (list group))
@@ -1369,18 +1611,22 @@ Example:
(setq slist (cdr slist)))
(setcdr slist (cons elem (cdr slist))))))
-(defvar shortdoc-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "n") 'shortdoc-next)
- (define-key map (kbd "p") 'shortdoc-previous)
- (define-key map (kbd "C-c C-n") 'shortdoc-next-section)
- (define-key map (kbd "C-c C-p") 'shortdoc-previous-section)
- map)
- "Keymap for `shortdoc-mode'.")
+(defvar-keymap shortdoc-mode-map
+ :doc "Keymap for `shortdoc-mode'."
+ "n" #'shortdoc-next
+ "p" #'shortdoc-previous
+ "N" #'shortdoc-next-section
+ "P" #'shortdoc-previous-section
+ "C-c C-n" #'shortdoc-next-section
+ "C-c C-p" #'shortdoc-previous-section
+ "w" #'shortdoc-copy-function-as-kill)
(define-derived-mode shortdoc-mode special-mode "shortdoc"
"Mode for shortdoc."
- :interactive nil)
+ :interactive nil
+ (setq-local outline-search-function #'outline-search-level
+ outline-level (lambda ()
+ (get-text-property (point) 'outline-level))))
(defun shortdoc--goto-section (arg sym &optional reverse)
(unless (natnump arg)
@@ -1389,35 +1635,49 @@ Example:
(funcall
(if reverse 'text-property-search-backward
'text-property-search-forward)
- sym nil t t)
+ sym nil t)
(setq arg (1- arg))))
(defun shortdoc-next (&optional arg)
- "Move cursor to the next function.
-With ARG, do it that many times."
+ "Move point to the next function.
+With prefix numeric argument ARG, do it that many times."
(interactive "p" shortdoc-mode)
(shortdoc--goto-section arg 'shortdoc-function))
(defun shortdoc-previous (&optional arg)
- "Move cursor to the previous function.
-With ARG, do it that many times."
+ "Move point to the previous function.
+With prefix numeric argument ARG, do it that many times."
(interactive "p" shortdoc-mode)
(shortdoc--goto-section arg 'shortdoc-function t)
(backward-char 1))
(defun shortdoc-next-section (&optional arg)
- "Move cursor to the next section.
-With ARG, do it that many times."
+ "Move point to the next section.
+With prefix numeric argument ARG, do it that many times."
(interactive "p" shortdoc-mode)
(shortdoc--goto-section arg 'shortdoc-section))
(defun shortdoc-previous-section (&optional arg)
- "Move cursor to the previous section.
-With ARG, do it that many times."
+ "Move point to the previous section.
+With prefix numeric argument ARG, do it that many times."
(interactive "p" shortdoc-mode)
(shortdoc--goto-section arg 'shortdoc-section t)
(forward-line -2))
+(defun shortdoc-copy-function-as-kill ()
+ "Copy name of the function near point into the kill ring."
+ (interactive)
+ (save-excursion
+ (goto-char (pos-bol))
+ (when-let* ((re (rx bol "(" (group (+ (not (in " "))))))
+ (string
+ (and (or (looking-at re)
+ (re-search-backward re nil t))
+ (match-string 1))))
+ (set-text-properties 0 (length string) nil string)
+ (kill-new string)
+ (message string))))
+
(provide 'shortdoc)
;;; shortdoc.el ends here