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.