Search code examples
cemacsdocumentation

Documenting c functions in emacs


Is there a way to automatically provide a documentation template for a C function in emacs? For example, let's say I have this function:

const bool are_equal_int_float(const int a, const float b)
{
  bool result = false;

  // Do work

  return result;
}

I want to put the cursor somewhere inside the function and run a command that will parse the declaration and use it to create an explanation above the function. I would end up with something like this (it doesn't have to be the same format):

/* are_equal_int_float
 *
 * explanation: 
 *
 * params
 * a: 
 * b: 
 * 
 * returns: 
 */
const bool are_equal_int_float(const int a, const float b)
{
bool result = false;

// Do work

return result;
}

Solution

  • I just wrote an emacs-lisp function called jd-document-c-function-in-emacs.

    Once the emacs-lisp function is evaluated, just put the cursor anywhere inside the C function and type:

    M-x jd-document-c-function-in-emacs RET

    Note that my function works only in a buffer opened with some C-mode, since, in fundamental mode, for example, the function beginning-of-defun goes to the opening curve brace instead of the "real" beginning of the C function.

    (defun jd-document-c-function-in-emacs ()
      (interactive)
      (save-excursion
        (save-restriction
          (unless (beginning-of-defun)
            (error "Could not find %s" 'beginning-of-defun))
          ;; Narrow to <beginning of fun> <end of arg list>
          (narrow-to-region (point) (progn (forward-list) (point)))
          (let* ((bod     (point-min))
                 (eolarg  (point-max))
                 (bolarg  (progn (goto-char (point-max)) (backward-list) (point)))
                 (bofname (progn (backward-sexp) (point)))
                 (eofname (progn (forward-sexp)  (point)))
                 (fname   (buffer-substring bofname eofname))
                 (eoftype (progn
                            (goto-char bofname)
                            (backward-word)
                            (forward-word)
                            (min (point) bofname)))
                 (ftype   (buffer-substring bod eoftype))
                 (arg-re  (concat "[[:space:]]*"
                                  "\\([^,)]*\\)"
                                  "[[:space:]]+"
                                  "\\([^[:space:]]+\\)"
                                  "[,)]"))
                 (largt   (list))
                 (largn   (list))
                 (dformat (concat "/* %s\n" " *\n" " * explanation:\n" " *\n"
                                  " * params\n"))
                 (aformat (concat " * %s:" " (%s)" "\n"))
                 (rformat (concat " *\n" " * returns:" " (%s)" "\n" " */\n"))
                 )
            (goto-char bolarg)
            (forward-char)                  ; skip lpar
            (while (re-search-forward arg-re eolarg 'noerror)
              (let ((argt (buffer-substring (match-beginning 1) (match-end 1)))
                    (argn (buffer-substring (match-beginning 2) (match-end 2))))
                (setq largt (nconc largt (list argt)))
                (setq largn (nconc largn (list argn)))))
            (goto-char bod)
            (insert (format dformat fname))
            (cl-mapc (lambda (argn argt) (insert (format aformat argn argt)))
                     largn largt)
            (insert (format rformat (if (string-blank-p ftype) "void" ftype)))))))
    

    HTH