10.3 Indentation Calculation

Indentation for a line is calculated from the syntactic context (see Syntactic Analysis).

First, a buffer position is found whose column will be the base for the indentation calculation. It’s the anchor position in the first syntactic element that provides one that is used. If no syntactic element has an anchor position then column zero is used.

Second, the syntactic symbols in each syntactic element are looked up in the c-offsets-alist style variable (see c-offsets-alist), which is an association list of syntactic symbols and the offsets to apply for those symbols. These offsets are added together with the base column to produce the new indentation column.

Let’s use our two code examples above to see how this works. Here is our first example again:

 1: void swap( int& a, int& b )
 2: {
 3:     int tmp = a;
 4:     a = b;
 5:     b = tmp;
 6: }

Let’s say point is on line 3 and we hit the TAB key to reindent the line. The syntactic context for that line is:

((defun-block-intro 29))

Since buffer position 29 is the first and only anchor position in the list, CC Mode goes there and asks for the current column. This brace is in column zero, so CC Mode uses ‘0’ as the base column.

Next, CC Mode looks up defun-block-intro in the c-offsets-alist style variable. Let’s say it finds the value ‘4’; it adds this to the base column ‘0’, yielding a running total indentation of 4 spaces.

Since there is only one syntactic element on the list for this line, indentation calculation is complete, and the total indentation for the line is 4 spaces.

Here’s another example:

 1: int add( int val, int incr, int doit )
 2: {
 3:     if( doit )
 4:         {
 5:             return( val + incr );
 6:         }
 7:     return( val );
 8: }

If we were to hit TAB on line 4 in the above example, the same basic process is performed, despite the differences in the syntactic context. The context for this line is:

((substatement-open 46))

Here, CC Mode goes to buffer position 46, which is the ‘i’ in if on line 3. This character is in the fourth column on that line so the base column is ‘4’. Then CC Mode looks up the substatement-open symbol in c-offsets-alist. Let’s say it finds the value ‘4’. It’s added with the base column and yields an indentation for the line of 8 spaces.

Simple, huh?

Actually, it’s a bit more complicated than that since the entries on c-offsets-alist can be much more than plain offsets. See c-offsets-alist, for the full story.

Anyway, the mode usually just does The Right Thing without you having to think about it in this much detail. But when customizing indentation, it’s helpful to understand the general indentation model being used.

As you configure CC Mode, you might want to set the variable c-echo-syntactic-information-p to non-nil so that the syntactic context and calculated offset always is echoed in the minibuffer when you hit TAB.