Block indentation in Emacs

There are several small things Emacs could be doing to make it nicer to write code. One I was missing was making it possible to go with one press of the return key between braces in a C derived language from this:

if (test) { }

to this:

if (test) {
   <-- insertion point here
}

That is, pressing return before the closing parentheses, brace or bracket should move the closing character two lines down, indent it properly, and move the insertion point to the new empty line in the middle and indent it property. The way TextMate does it.

Here are a few of elisp functions to accomplish this:

(defun char-isws (c)
  "Is character c a whitespace character?"
  (or (char-equal c ?\ )
      (char-equal c ?\t)
      (char-equal c ?\n)))

(defun line-next-non-ws ()
  "Return the next non-whitespace character on the current line or nil."
  (let ((cc (char-after)))
    (if (and cc (char-isws cc))
        (save-excursion
          (if (re-search-forward "[^[:space:]]" (save-excursion     (end-of-line) (point)) t)
              (char-before)
            nil))
      cc)))

(defun newline-and-indent-extra-for-closing-paren ()
  "Insert a newline and indent. If the next non-whitespace character is a closing paren, insert two newlines and indent the two  new lines correctly, placing the point on the first of the two new lines."
  (interactive)
  (let ((nc (line-next-non-ws)))
    (if (or (null nc)
            (not (= (char-syntax nc) ?\))))
        (newline-and-indent)
      (progn
        (just-one-space)
        (newline-and-indent)
        (newline-and-indent)
        (previous-line)
        (indent-for-tab-command)))))

Now you can bind return to newline-and-indent-extra-for-closing-paren in a suitable language keymap. I've been using this with scala-mode and it works well there.

© Juri Pakaste 2023