8.1.1 Custom Brace Hanging

Syntactic symbols aren’t the only place where you can customize CC Mode with the lisp equivalent of callback functions. Remember that actions are usually a list containing some combination of the symbols before and after (see Hanging Braces). For more flexibility, you can instead specify brace “hanginess” by giving a syntactic symbol an action function in c-hanging-braces-alist; this function determines the “hanginess” of a brace, usually by looking at the code near it.

An action function is called with two arguments: the syntactic symbol for the brace (e.g., substatement-open), and the buffer position where the brace has been inserted. Point is undefined on entry to an action function, but the function must preserve it (e.g., by using save-excursion). The return value should be a list containing some combination of before and after, including neither of them (i.e., nil).

Variable: c-syntactic-context

During the call to the indentation or brace hanging action function, this variable is bound to the full syntactic analysis list. This might be, for example, ‘((block-close 73))’. Don’t ever give c-syntactic-context a value yourself—this would disrupt the proper functioning of CC Mode.

This variable is also bound in three other circumstances: (i) when calling a c-hanging-semi&comma-criteria function (see Hanging Semicolons and Commas); (ii) when calling a line-up function (see Custom Line-Up Functions); (iii) when calling a c-special-indent-hook function (see Other Special Indentations).

As an example, CC Mode itself uses this feature to dynamically determine the hanginess of braces which close “do-while” constructs:

void do_list( int count, char** atleast_one_string )
{
    int i=0;
    do {
        handle_string( atleast_one_string[i] );
        i++;
    } while( i < count );
}

CC Mode assigns the block-close syntactic symbol to the brace that closes the do construct, and normally we’d like the line that follows a block-close brace to begin on a separate line. However, with “do-while” constructs, we want the while clause to follow the closing brace. To do this, we associate the block-close symbol with the action function c-snug-do-while:

(defun c-snug-do-while (syntax pos)
  "Dynamically calculate brace hanginess for do-while statements."
  (save-excursion
    (let (langelem)
      (if (and (eq syntax 'block-close)
               (setq langelem (assq 'block-close c-syntactic-context))
               (progn (goto-char (cdr langelem))
                      (if (= (following-char) ?{)
                          (forward-sexp -1))
                      (looking-at "\\<do\\>[^_]")))
          '(before)
        '(before after)))))

This function simply looks to see if the brace closes a “do-while” clause and if so, returns the list ‘(before)’ indicating that a newline should be inserted before the brace, but not after it. In all other cases, it returns the list ‘(before after)’ so that the brace appears on a line by itself.