Last week I wrote about Comment Boxes In Emacs and gave some examples of how the comment-box
command provides an easy way to draw a box around a comment. The only problem is that I want the boxes to extend almost to the right hand margin. Instead of
########################################## # get-cred -- Get the user's credentials # ########################################## (defun get-cred () ...)
I want
########################################################################## # get-cred -- Get the user's credentials # ########################################################################## (defun get-cred () ...)
One could argue, I suppose, that this adds nothing except some useless blanks to the file but I’ve always done it that way and as Henry Higgins might say, “I’ve grown accustomed to its face.” So, how to do it?
My idea was simple: pad the first line with blanks out to the fill column, and then call comment-box
to draw the actual box. There’s nothing special about using the fill column as the right hand edge but it makes the function behave well for any size window.
I thought I’d knock off a quick bit of Elisp and be done. It didn’t work out that way. I kept getting a mysterious error that appeared to come from save-restriction
(see the code below). After that lot of mucking about I discovered that the real problem was the call to comment-box
. The documentation says that there’s an optional third argument to add extra space and, indeed, the beginning of the function is
(defun comment-box (beg end &optional arg) ...)
so I didn’t bother specifying the third argument. It turns out, though, that in the comment-box
function we have this line
(comment-region beg end (+ comment-add arg))
so that the optional argument is always used. It works OK in the interactive case because the call to interactive
is
(interactive "*r\np")
which causes the prefix argument to be passed to arg
. When no prefix argument is specified, this results in a 1
being passed to arg
so arg
is never nil
the way it is if you call comment-box
from Elisp with only two arguments. That’s obviously a bug but it’s a small one. At least it’s a small one once you figure out what’s happening.
In any event, once I solved that problem it was easy to write the function:
(defun jcs-comment-box () "Draw a box comment around the region but arrange for the region to extend to at least the fill column. Place the point after the comment box." (interactive) (with-region-or-buffer (b e) (save-restriction (narrow-to-region b e) (goto-char b) (end-of-line) (insert-char ? (- fill-column (current-column))) (comment-box b (point-max) 1) (goto-char (point-max)))))
As you can see, we first move to the beginning of the first line, then to its end, and then we pad the line with blanks out to fill-column
. A few comments on the rest of the code:
- It would probably be easier to use
(interactive "r")
rather than the
with-region-or-buffer
macro but I write that almost automatically when I’m dealing with a possible region so I just kept it. insert-char
does nothing if the count is not positive so I didn’t have to worry about whether or not the first line already extended to or past the fill column.- Using the
narrow-to-region
function makes it really easy to move around the buffer and helps deal with the fact that I’m changing the size of the region as I go. This problem was described by Xah Lee. - Notice that even the
narrow-to-region
doesn’t completely insulate me from the effects of changing the buffer size. I have to use(point-max)
as the end of the region (instead ofb
) in the call tocomment-box
becauseb
no longer points to the end of the region.