stderr

secondary output stream of a software developer

YARD Documentation with Emacs

In Emacs, the fill-paragraph command lets you reformat a chunk of text to break lines at a certain width. Bound to M-q by default, it is a handy way to enforce consistent line widths inside text documents.

Recently, I've been editing a lot of inline documentation in Ruby code using YARD. A typical doc comment looks like this:

# Reverses the contents of a String or IO object. 
# 
# @param [String, #read] contents the contents to reverse 
# @return [String] the contents reversed lexically 
def reverse(contents) 
  # ...
end

As descriptions got longer, I found myself wishing to reformat paragraphs. While Emacs knows how to fill paragraphs inside Ruby comments, hitting M-q still turned text into unreadable gibberish:

# Reverses the contents of a String or IO object.  @param [String,
# #read] contents the contents to reverse @return [String] the
# contents reversed lexically

Turns out there is an easy way to tell Emacs how to recognize paragraphs: paragraph-separate and paragraph-start. Let's define a function that sets these variables to YARD specific values. The concatenate call is only there to improve readability.

(defun yard-paragraph-boundaries ()
  (interactive)
  ; Paragraphs are separated by lines containing only a # character
  (setq paragraph-separate "[ \t]*#[ \t]*$")
  ; Paragraphs start with YARD tags or list items
  (setq paragraph-start
      (concatenate
       'string
       "^[ \t]*"         ; some whitespace
       "#[ \t]*"         ; a # character followed by whitespace
       "\\("
         "@[[:alpha:]]+" ; a YARD tag
       "\\|"             ; or
         "-"             ; a list item
       "\\)"
       "\\([ \t]+.*\\)?" ; an optional text
       "[ \t]*$")))      ; some more whitespace

Finally, we can call the function whenever ruby-mode is entered:

(add-hook 'ruby-mode-hook
      '(lambda ()
        (yard-paragraph-boundaries)))

Now text inside YARD comments can be reformatted with a single key stroke. Emacs even preserves custom indentation levels:

# @param [String] A really long description text which spans
#   multiple lines and has a custom indentation, which is
#   preserved even when the paragraph is reformatted.
comments powered by Disqus