Generate emacs-lisp documentation
Posted October 17, 2014 at 02:39 PM | categories: emacs_lisp | tags:
Emacs has some pretty amazing features to get help on a function (describe-function), to navigate quickly to functions in an elisp file (speedbar and imenu). Other languages have tools for generating documentation for all the functions in a file, e.g. epydoc, javadoc, Doxygen,… I have not found an equivalent to this in emacs-lisp. Here, we explore some options to get something similar to this. Our goal will be to take an emacs-lisp file, and generate an org-file of documentation, and then convert that to PDF for reading.
Say we have a function, jmax-bibtex-next-entry, and we want some information about it. Here are three functions that give us the argument list, documentation string, and function definition.
(help-function-arglist 'jmax-bibtex-next-entry)
&optional | n |
(documentation 'jmax-bibtex-next-entry)
Jump to the beginning of the next bibtex entry. N is a prefix argument. If it is numeric, jump that many entries forward. Negative numbers do nothing.
(symbol-function 'jmax-bibtex-next-entry)
lambda | (&optional n) | Jump to the beginning of the next bibtex entry. N is a prefix\nargument. If it is numeric, jump that many entries\nforward. Negative numbers do nothing. | (interactive P) | (if (= (point) (save-excursion (bibtex-beginning-of-entry))) (progn (forward-char) (bibtex-next-entry))) | (if (re-search-forward bibtex-entry-head nil t (and (numberp n) n)) (progn (bibtex-beginning-of-entry))) |
That will not always be the code we wrote, but it is functionally similar.
So we could create an org-entry like this:
(defun fun2org (function-symbol) (let ((args (help-function-arglist function-symbol)) (doc (documentation function-symbol)) (code (symbol-function function-symbol))) (format "** %s %s %s #+BEGIN_SRC emacs-lisp %S #+END_SRC " function-symbol args doc code))) (fun2org 'jmax-bibtex-next-entry)
** jmax-bibtex-next-entry (&optional n) Jump to the beginning of the next bibtex entry. N is a prefix argument. If it is numeric, jump that many entries forward. Negative numbers do nothing. #+BEGIN_SRC emacs-lisp (lambda (&optional n) "Jump to the beginning of the next bibtex entry. N is a prefix argument. If it is numeric, jump that many entries forward. Negative numbers do nothing." (interactive "P") (if (= (point) (save-excursion (bibtex-beginning-of-entry))) (progn (forward-char) (bibtex-next-entry))) (if (re-search-forward bibtex-entry-head nil t (and (numberp n) n)) (progn (bibtex-beginning-of-entry)))) #+END_SRC
The code is not that beautifully indented, but it is optional.
For variables, there are similar functions to get their documentation:
(documentation-property 'jmax-bibtex-journal-abbreviations 'variable-documentation)
List of (string journal-full-name journal-abbreviation). Find abbreviations at http://cassi.cas.org/search.jsp.
The problem still is, you have to know the variable and function names in advance. I want to take a file, and generate this for each function, and variable.
I posted a question on StackOverflow on how to get the functions defined in a file. The most feasible suggestion was to use the variable load-history, which contains a history of the variables and functions loaded, and the files they are in.
Here is an example of getting the entries associated with jmax-bibtex.el
(cdr (assoc "/Users/jkitchin/Dropbox/kitchingroup/jmax/jmax-bibtex.el" load-history ))
(jmax-bibtex-journal-abbreviations (defun . jmax-bibtex-generate-longtitles) (defun . jmax-bibtex-generate-shorttitles) (defun . jmax-stringify-journal-name) (defun . jmax-set-journal-string) jmax-nonascii-latex-replacements (defun . jmax-replace-nonascii) jmax-lower-case-words (defun . jmax-title-case-article) (defun . jmax-sentence-case-article) (defun . jmax-bibtex-next-entry) (defun . jmax-bibtex-previous-entry) (defun . jmax-bibtex-mode-keys) (provide . jmax-bibtex))
Each element in this case is either a variable, defun or provide. Here, we can use this to print some information about the variables defined in this file. I think it is sufficient to check if the element in the list is a symbol, because all the other elements are cons elements. I suppose there are other possibilities, including defcustom, defgroup, defalias, defsubst, and maybe others.
(dolist (element (cdr (assoc "/Users/jkitchin/Dropbox/kitchingroup/jmax/jmax-bibtex.el" load-history ))) (when (symbolp element) (princ (format "%s Documentation: %s " element (documentation-property element 'variable-documentation)))))
jmax-bibtex-journal-abbreviations Documentation: List of (string journal-full-name journal-abbreviation). Find abbreviations at http://cassi.cas.org/search.jsp. jmax-nonascii-latex-replacements Documentation: Cons list of non-ascii characters and their LaTeX representations jmax-lower-case-words Documentation: List of words to keep lowercase
We can handle functions by checking if an element is a cons cell with a first element of defun.
(dolist (element (cdr (assoc "/Users/jkitchin/Dropbox/kitchingroup/jmax/jmax-bibtex.el" load-history ))) (when (and (consp element) (eq (car element) 'defun)) (princ (format "%s is a function\n" (cdr element))))))
jmax-bibtex-generate-longtitles is a function jmax-bibtex-generate-shorttitles is a function jmax-stringify-journal-name is a function jmax-set-journal-string is a function jmax-replace-nonascii is a function jmax-title-case-article is a function jmax-sentence-case-article is a function jmax-bibtex-next-entry is a function jmax-bibtex-previous-entry is a function jmax-bibtex-mode-keys is a function
So, we have the important pieces to mash up what I am looking for. Let us refine the goal. I want to create a PDF documentation of what is in an elisp file with a section on variables, and a section on functions.
(let* ((elements (cdr (assoc "/Users/jkitchin/Dropbox/kitchingroup/jmax/jmax-bibtex.el" load-history))) (vars (-filter 'symbolp elements)) (funcons (-filter (lambda (x) (and (consp x) (eq 'defun (car x)))) elements)) (funcs (mapcar 'cdr funcons))) (switch-to-buffer "*org-doc*") (erase-buffer) (insert (format "#+TITLE: Documentation for %s #+OPTIONS: toc:nil \\maketitle \\tableofcontents " "/Users/jkitchin/Dropbox/kitchingroup/jmax/jmax-bibtex.el")) (insert "* Variables\n") (dolist (var (sort vars 'string-lessp)) (insert (format "** %s Documentation: %s\n\n" var (documentation-property var 'variable-documentation)))) (insert "* Functions\n\n") (dolist (funcs (sort funcs 'string-lessp)) (insert (format "** %s %s Documentation: %s Code: #+BEGIN_SRC emacs-lisp %S #+END_SRC " funcs (or (help-function-arglist funcs) "") (documentation funcs) (symbol-function funcs)))) (org-mode) (write-file "jmax-bibtex-doc.org") (org-export-to-file 'latex "jmax-bibtex-doc.tex") (org-latex-compile "jmax-bibtex-doc.tex") (kill-buffer "*org-doc*") (kill-buffer "jmax-bibtex-doc.org"))
Here is the resulting pdf: jmax-bibtex-doc.pdf . It is not too bad. The code is not beautiful, and it would take some work to get that looking nice. It might be nice to find all instances of '` and replace them with links to variable names, but I leave that for another day. There is also no information about the header comments, but I leave this for another day to.
Copyright (C) 2014 by John Kitchin. See the License for information about copying.
Org-mode version = 8.2.7c