[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3. Indentation Engine

CC Mode has an indentation engine that provides a flexible and general mechanism for customizing indentation. It separates indentation calculation into two steps: first, CC Mode analyzes the line of code being indented to determine the kind of language construct it's looking at, then it applies user defined offsets to the current line based on this analysis.

This section will briefly cover how indentation is calculated in CC Mode. It is important to understand the indentation model being used so that you will know how to customize CC Mode for your personal coding style. All the details are in 9. Customizing Indentation, and later chapters.

User Option: c-syntactic-indentation
Syntactic analysis for indentation is done when this is non-nil (which is the default). When it's nil every line is just indented to the same level as the previous one, and TAB (c-indent-command) adjusts the indentation in steps of c-basic-offset. The indentation style has no effect, nor any of the indentation associated variables, e.g. c-special-indent-hook.

3.1 Syntactic Analysis  
3.2 Indentation Calculation  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.1 Syntactic Analysis

The first thing CC Mode does when indenting a line of code, is to analyze the line, determining the syntactic component list of the construct on that line. A syntactic component consists of a pair of elements (in lisp parlance, a cons cell), the first being a syntactic symbol, the second being a relative buffer position. Syntactic symbols describe elements of C code (2), e.g. statement, substatement, class-open, class-close, etc. See section 10. Syntactic Symbols, for a complete list of currently recognized syntactic symbols and their semantics. The style variable c-offsets-alist also contains the list of currently supported syntactic symbols.

Conceptually, a line of C code is always indented relative to the indentation of some line higher up in the buffer. This is represented by the relative buffer position in the syntactic component.

Here is an example. Suppose we had the following code as the only thing in a C++ buffer (3):

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

We can use the command C-c C-s (bound to c-show-syntactic-information) to simply report what the syntactic analysis is for the current line. Running this command on line 4 of this example, we'd see in the echo area(4):

 
((statement 35))

This tells us that the line is a statement and it is indented relative to buffer position 35, which happens to be the `i' in int on line 3. If you were to move point to line 3 and hit C-c C-s, you would see:

 
((defun-block-intro 29))

This indicates that the `int' line is the first statement in a top level function block, and is indented relative to buffer position 29, which is the brace just after the function header.

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: }

Hitting C-c C-s on line 4 gives us:

 
((substatement-open 46))

which tells us that this is a brace that opens a substatement block. (5)

Syntactic component lists can contain more than one component, and individual syntactic components need not have relative buffer positions. The most common example of this is a line that contains a comment only line.

 
 1: void draw_list( List<Drawables>& drawables )
 2: {
 3:         // call the virtual draw() method on each element in list
 4:     for( int i=0; i < drawables.count(), ++i )
 5:     {
 6:         drawables[i].draw();
 7:     }
 8: }

Hitting C-c C-s on line 3 of this example gives:

 
((comment-intro) (defun-block-intro 46))

and you can see that the syntactic component list contains two syntactic components. Also notice that the first component, `(comment-intro)' has no relative buffer position.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.2 Indentation Calculation

Indentation for a line is calculated using the syntactic component list derived in step 1 above (see section 3.1 Syntactic Analysis). Each component contributes to the final total indentation of the line in two ways.

First, the syntactic symbols are looked up in the c-offsets-alist style variable, which is an association list of syntactic symbols and the offsets to apply for those symbols. These offsets are added to a running total.

Second, if the component has a relative buffer position, CC Mode adds the column number of that position to the running total. By adding up the offsets and columns for every syntactic component on the list, the final total indentation for the current line is computed.

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. Remember that the syntactic component list for that line is:

 
((defun-block-intro 29))

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 running total (initialized to zero), yielding a running total indentation of 4 spaces.

Next CC Mode goes to buffer position 29 and asks for the current column. This brace is in column zero, so CC Mode adds `0' to the running total. Since there is only one syntactic component 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 component list. Remember that the list for this line is:

 
((substatement-open 46))

Here, CC Mode first looks up the substatement-open symbol in c-offsets-alist. Let's say it finds the value `4'. This yields a running total of 4. CC Mode then 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 adding this to the running total yields an indentation for the line of 8 spaces.

Simple, huh?

Actually, 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 component list and calculated offset will always be echoed in the minibuffer when you hit TAB.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by XEmacs shared group account on December, 19 2009 using texi2html 1.65.