Previous: Hanging Braces, Up: Hanging Braces

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); (iii) when calling a c-special-indent-hook function (see Other Indentation).

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.