Democratize can now import shortdoc, bringing demos of native Emacs functions

A new release of Democratize is out, bringing with it support for the shortdoc format as a source. As a consequence, the hundreds of usage examples that come with the shortdoc library itself (shortdoc.el) are immediately democratizable, ready to show up in your Helpful (or regular Help) buffers.

A quick FAQ

What is shortdoc?

There's shortdoc (the library), shortdoc (the format), and shortdoc (a collection of short documentation groups that any library can provide).

The library, shortdoc.el, does many things:

  1. It defines the shortdoc format (the macro #'define-short-documentation-group).
  2. It defines functions to display groups (a group is defined by using the macro above).
  3. It defines 17 groups (each of which provides usage examples of functions from native libraries).

Other libraries can, of course, also define groups in shortdoc format.

What sort of functions come with shortdoc.el?

At the time of this release, more than 500 examples are defined in shortdoc.el for more than 400 functions.

After democratizing it, a quick check tells me that most functions there are primitives (C source code). The rest is spread over about a dozen native Emacs libraries. You can have an idea of which ones with:

(->> (f-expand "shortdoc.org" democratize--extracted-dir)
     democratize--list-symbols-in-file
     (-map #'symbol-file)  -non-nil  -uniq
     (-map (-compose #'read #'f-base))
     (-sort #'string<))

How many functions come from each of these libraries?

Most non-primitives come from seq, subr, and files.

An alist with a sorted count for each originating native library can be generated with:

(->> (f-expand "shortdoc.org" democratize--extracted-dir)
     democratize--list-symbols-in-file
     (--map (--when-let (symbol-file it)
              (read (f-base it))))
     -frequencies  ; <--- recent dash is needed for this one
     (-sort (-on #'> #'cdr)))

The nils in the result represent functions for which no source could be found through symbol-file. These are either primitives (such as car and string<) or non-existent (since some of the shortdoc functions won't be available to you if you're on an older version of Emacs).

But I want to know exactly! How can I look into these non-nils?

Ok, ok. Let's generate a nice report:

(defun democratize--shortdoc-el-original-libs ()
  "Show shortdoc.el's functions sorted by their original library."
  (interactive)
  (unless (memq 'shortdoc (democratize--list-democratized-libraries))
    (error "This will only work after having democratized shortdoc"))
  (let* ((sdoc (f-expand "shortdoc.org" democratize--extracted-dir))
         (syms (democratize--list-symbols-in-file sdoc))
         (tbuf (get-buffer-create "*shortdoc.el's functions*"))
         (titl "shortdoc.el's functions sorted by their original library")
         (htbl (h-new))
         (libr) (tree))
    (dolist (sym syms)
      (setq libr (if (subrp (symbol-function sym))
                     "[primitive]"
                   (--if-let (symbol-file sym)
                       (read (f-base it))
                     "[not found]")))
      (h-put-add! htbl libr sym))
    (setq tree (with-output-to-string
                 (princ "* ") (princ titl) (terpri)
                 (->> htbl  (h--hmap key (-list value))  h->alist
                      (-sort (-on #'> (-compose #'length #'cdr)))
                      (mapc (-lambda ((key . value))
                              (princ (format "** %3s %s\n" (length value) key))
                              (dolist (sym (-sort #'string< value))
                                (princ "*** ") (princ sym) (terpri)))))))
    (with-current-buffer tbuf
      (widen)
      (erase-buffer)
      (save-excursion (insert tree))
      (org-mode)
      (outline-hide-subtree)
      (outline-show-children))
    (switch-to-buffer tbuf)))

Expected output of M-x democratize--shortdoc-el-original-libs RET: an org buffer with a tree containing all functions for which there are examples in shortdoc.el grouped by the libraries they originally came from (or marked as primitive, or marked as not found), sorted in decreasing order of function count by library.

(This command was written just for this post, so it's not in the package.)

Cool! So how do I democratize shortdoc.el?

After installing democratize, simply M-x democratize-library RET shortdoc RET.

Would I need to have shortdoc installed? I'm on an older Emacs.

No need. If your Emacs version is older than 28, you can still have access to shortdoc examples. If you don't have shortdoc installed, running the command above will "fail" and suggest instructions to fetch online the latest shortdoc source for the library. That done, run the democratize-library command again, and the examples should become available.

What do you mean by "latest shortdoc source for the library"?

Democratize can import from any library that defines documentation groups in shortdoc format. shortdoc.el itself is one such library, as is Emacs' native treesit.el.

Therefore, "latest shortdoc source for the library" is a file containing the latest shortdoc sexps for that library. The library may be shortdoc.el itself, treesit.el, or any other shortdoc-based library that may become democratizable in the future.

Why would I want to democratize shortdoc sources?

Because:

  • You may be in an older version of Emacs and not have shortdoc installed, and therefore not able to see any shortdoc examples directly.
  • And regardless of whether you have shortdoc installed:
    • With democratize you'll have syntax-highlighted examples. Highlighted code is easier to read. (If either dash-fontify-mode or exemplify-ert-fontify-mode is on, the arrow pointing to the results will be highlighted as well.)

      Here's how the mapcar examples look like in my Helpful buffer:

      (mapcar #'identity "123")
      => (49 50 51)
      (mapcar #'list '(1 2 3))
      => ((1) (2) (3))
      (mapcar #'identity [1 2 3])
      => (1 2 3)
      

      Democratize gathered these from three different shortdoc groups (strings, list, vector), each of which has one example. For comparison, in a shortdoc buffer the "list" one will look like this:

      (mapcar function sequence)
        Apply FUNCTION to each element of SEQUENCE, and make a list of the results.
        (mapcar (function list) (quote (1 2 3)))
          ⇒ ((1) (2) (3))
      

      (Note that Helpful itself also shows the function's signature and docstring. Democratize adds the examples.)

    • The Helpful buffer (but not the Help one) adds a link to the related shortdoc group.

      Without democratize, you'd need to click on it, and then search your function among the many others in the group. With democratize, the examples for that specific function will already show up in the Helpful or Help buffer. (And if you want, you can still click to open shortdoc and see other functions from that group.)

    • You'll be able to launch an org buffer with a high-level tree-structured overview of all the available functions of a democratized library. Try M-x democratize-overview-library RET shortdoc RET. You can then put point over any leaf and launch helpful-at-point.

How do I make the examples show up in my Help buffers?

A library that I like has shortdoc. Could it become democratizable?

Probably! To share your suggestion, simply open a ticket or contact me directly.

Acknowledgments

I'd like to thank Adam Porter for having suggested that I look at shortdoc to consider whether I could somehow use it with democratize. I was aware of shortdoc, but hadn't considered adding support for the format until his suggestion.