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

10. Indentation Engine Basics

This chapter will briefly cover how CC Mode indents lines of code. It is helpful 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 Customizing Indentation.

CC Mode has an indentation engine that provides a flexible and general mechanism for customizing indentation. When CC Mode indents a line of code, it separates its calculations into two steps:

  1. It analyzes the line to determine its syntactic symbol(s) (the kind of language construct it’s looking at) and its anchor position (the position earlier in the file that CC Mode will indent the line relative to). The anchor position might be the location of an opening brace in the previous line, for example. See section Syntactic Analysis.
  2. It looks up the syntactic symbol(s) in the configuration to get the corresponding offset(s). The symbol +, which means “indent this line one more level” is a typical offset. CC Mode then applies these offset(s) to the anchor position, giving the indentation for the line. The different sorts of offsets are described in c-offsets-alist.

In exceptional circumstances, the syntax directed indentation described here may be a nuisance rather than a help. You can disable it by setting c-syntactic-indentation to nil. (To set the variable interactively, Minor Modes).

User Option: c-syntactic-indentation

When this is non-nil (which it is by default), the indentation of code is done according to its syntactic structure. 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 current style (see section Configuration Basics) then has no effect on indentation, nor do any of the variables associated with indentation, not even c-special-indent-hook.


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

10.1 Syntactic Analysis

The first thing CC Mode does when indenting a line of code, is to analyze the line by calling c-guess-basic-syntax, determining the syntactic context of the (first) construct on that line. Although this function is mainly used internally, it can sometimes be useful in Line-up functions (see section Custom Line-Up Functions) or in functions on c-special-indent-hook (see section Other Special Indentations).

Function: c-guess-basic-syntax

Determine the syntactic context of the current line.

The syntactic context is a list of syntactic elements, where each syntactic element in turn is a list(33) Here is a brief and typical example:

 
((defun-block-intro 1959))

The first thing inside each syntactic element is always a syntactic symbol. It describes the kind of construct that was recognized, e.g. statement, substatement, class-open, class-close, etc. See section Syntactic Symbols, for a complete list of currently recognized syntactic symbols and their semantics. The remaining entries are various data associated with the recognized construct - there might be zero or more.

Conceptually, a line of code is always indented relative to some position higher up in the buffer (typically the indentation of the previous line). That position is the anchor position in the syntactic element. If there is an entry after the syntactic symbol in the syntactic element list then it’s either nil or that anchor position.

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

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

We can use C-c C-s (c-show-syntactic-information) to report what the syntactic analysis is for the current line:

C-c C-s (c-show-syntactic-information)

This command calculates the syntactic analysis of the current line and displays it in the minibuffer. The command also highlights the anchor position(s).

Running this command on line 4 of this example, we’d see in the echo area(35):

 
((statement 35))

and the ‘i’ of int on line 3 would be highlighted. This tells us that the line is a statement and it is indented relative to buffer position 35, the highlighted position. 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. (36)

Syntactic contexts can contain more than one element, and syntactic elements need not have anchor positions. The most common example of this is 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 context contains two syntactic elements. Notice that the first element, ‘(comment-intro)’, has no anchor position.

There are special ways of handling lines beginning with labels. Such a line gets a syntactic element beginning with label or substatement-label rather than the element(s) it would have had, were there no label on the line.

Also, a line beginning with a label (or a comment) is never the anchor position of a later line. Instead, that anchor position is the latest line at the same level of nesting before the labeled line without a leading label or comment. If there is no such line, the latest line containing an enclosing opening brace or parenthesis, which doesn’t start with a label or comment, provides the anchor postion. In this case extra syntactic element(s) with syntactic symbol defun-block-intro, statement-block-intro, or some other “-intro” symbol are inserted into the syntactic context to allow the correct indentation of the later line using that anchor position.

These conventions allow a style to indent labels specially, perhaps giving them greater visibility by indenting them less than the surrounding code.

For example, in the following pike fragment:

 
 1: int a()
 2: {
 3:   foo: {
 4:     bar: if (t)
 5:         x;
 6:       y;
 7:     }
 8:     y;
 9: }

Line 4 gets the syntactic context

 
((defun-block-intro 9) (label 9))

where position 9 is the brace on line 2, the latest line before line 4 without a label.


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

10.2 Syntactic Symbols

This section is a complete list of the syntactic symbols which appear in the c-offsets-alist style variable, along with brief descriptions. The previous section (see section Syntactic Analysis) states what syntactic symbols are and how the indentation engine uses them.

More detailed descriptions of these symbols, together with snippets of source code to which they apply, appear in the examples in the subsections below. Note that, in the interests of brevity, the anchor position associated with most syntactic symbols is not specified(37). In cases of doubt, type C-c C-s on a pertinent line—this highlights the anchor position.

The syntactic symbols which indicate brace constructs follow a general naming convention. When a line begins with an open or close brace, its syntactic symbol will contain the suffix -open or -close respectively. The first line within the brace block construct will contain the suffix -intro.

In constructs which can span several lines, a distinction is usually made between the first line that introduces the construct and the lines that continue it. The syntactic symbols that indicate these lines will contain the suffixes -intro or -cont respectively.

The best way to understand how all this works is by looking at some examples. Remember that you can see the syntax of any source code line by using C-c C-s.

string

Inside a multiline string. Comment String Label and Macro Symbols.

c

Inside a multiline C style block comment. Comment String Label and Macro Symbols.

defun-open

Brace that opens a top-level function definition. Function Symbols.

defun-close

Brace that closes a top-level function definition. Function Symbols.

defun-block-intro

The first line in a top-level defun. Function Symbols.

class-open

Brace that opens a class definition. Class related Symbols.

class-close

Brace that closes a class definition. Class related Symbols.

inline-open

Brace that opens an in-class inline method. Class related Symbols.

inline-close

Brace that closes an in-class inline method. Class related Symbols.

func-decl-cont

The region between a function definition’s argument list and the function opening brace (excluding K&R argument declarations). In C, you cannot put anything but whitespace and comments in this region, however in C++ and Java, throws declarations and other things can appear here. Comment String Label and Macro Symbols.

knr-argdecl-intro

First line of a K&R C argument declaration. K&R Symbols.

knr-argdecl

Subsequent lines in a K&R C argument declaration. K&R Symbols.

topmost-intro

The first line in a “topmost” definition. Function Symbols.

topmost-intro-cont

Topmost definition continuation lines. This is only used in the parts that aren’t covered by other symbols such as func-decl-cont and knr-argdecl. Function Symbols.

constraint-cont

Continuation line of a topmost C++20 concept or requires clause. C++ Constraint Symbols.

annotation-top-cont

Topmost definition continuation lines where all previous items are annotations. Java Symbols.

member-init-intro

First line in a member initialization list. Class related Symbols.

member-init-cont

Subsequent member initialization list lines. Class related Symbols.

class-field-cont

Lines continuing the first line inside a class/struct etc. definition. Class related Symbols.

inher-intro

First line of a multiple inheritance list. Class related Symbols.

inher-cont

Subsequent multiple inheritance lines. Class related Symbols.

block-open

Statement block open brace. Comment String Label and Macro Symbols.

block-close

Statement block close brace. Conditional Construct Symbols.

brace-list-open

Open brace of a static array list. Brace List Symbols.

brace-list-close

Close brace of a static array list. Brace List Symbols.

brace-list-intro

First line after the opening ‘{’ in a static array list. Brace List Symbols.

brace-list-entry

Subsequent lines in a static array list. Brace List Symbols.

brace-entry-open

Subsequent lines in a static array list where the line begins with an open brace. Brace List Symbols.

enum-open

Open brace of an enum list. Brace List Symbols.

enum-close

Close brace of an enum list. Brace List Symbols.

enum-intro

First line after the opening ‘{’ in an enum list. Brace List Symbols.

enum-entry

Subsequent lines in an enum ilst. Brace List Symbols.

statement

A statement. Function Symbols.

statement-cont

A continuation of a statement. Function Symbols.

annotation-var-cont

A continuation of a statement where all previous items are annotations. Java Symbols.

statement-block-intro

The first line in a new statement block. Conditional Construct Symbols.

statement-case-intro

The first line in a case block. Switch Statement Symbols.

statement-case-open

The first line in a case block that starts with a brace. Switch Statement Symbols.

substatement

The first line after a conditional or loop construct. Conditional Construct Symbols.

substatement-open

The brace that opens a substatement block. Conditional Construct Symbols.

substatement-label

The first line after a conditional or loop construct if it’s a label. Conditional Construct Symbols.

case-label

A label in a switch block. Switch Statement Symbols.

access-label

C++ access control label. Class related Symbols.

label

Any other label. Comment String Label and Macro Symbols.

do-while-closure

The while line that ends a do-while construct. Conditional Construct Symbols.

else-clause

The else line of an if-else construct. Conditional Construct Symbols.

catch-clause

The catch or finally (in Java) line of a try-catch construct. Conditional Construct Symbols.

comment-intro

A line containing only a comment introduction. Comment String Label and Macro Symbols.

arglist-intro

The first line in an argument list. Parenthesis (Argument) List Symbols.

arglist-cont

Subsequent argument list lines when no arguments follow on the same line as the arglist opening paren. Parenthesis (Argument) List Symbols.

arglist-cont-nonempty

Subsequent argument list lines when at least one argument follows on the same line as the arglist opening paren. Parenthesis (Argument) List Symbols.

arglist-close

The solo close paren of an argument list. Parenthesis (Argument) List Symbols.

stream-op

Lines continuing a stream operator (C++ only). Comment String Label and Macro Symbols.

inclass

The line is nested inside a class definition. Class related Symbols.

cpp-macro

The start of a preprocessor macro definition. Comment String Label and Macro Symbols.

cpp-define-intro

The first line inside a multiline preprocessor macro if c-syntactic-indentation-in-macros is set. Multiline Macro Symbols.

cpp-macro-cont

All lines inside multiline preprocessor macros if c-syntactic-indentation-in-macros is nil. Multiline Macro Symbols.

friend

A C++ friend declaration. Class related Symbols.

objc-method-intro

The first line of an Objective-C method definition. Objective-C Method Symbols.

objc-method-args-cont

Lines continuing an Objective-C method definition. Objective-C Method Symbols.

objc-method-call-cont

Lines continuing an Objective-C method call. Objective-C Method Symbols.

extern-lang-open

Brace that opens an extern block (e.g. extern "C" {...}). External Scope Symbols.

extern-lang-close

Brace that closes an extern block. External Scope Symbols.

inextern-lang

Analogous to inclass syntactic symbol, but used inside extern blocks. External Scope Symbols.

namespace-open
namespace-close
innamespace

These are analogous to the three extern-lang symbols above, but are returned for C++ namespace blocks. External Scope Symbols.

module-open
module-close
inmodule

Analogous to the above, but for CORBA IDL module blocks. External Scope Symbols.

composition-open
composition-close
incomposition

Analogous to the above, but for CORBA CIDL composition blocks. External Scope Symbols.

template-args-cont

C++ template argument list continuations. Class related Symbols.

inlambda

Analogous to inclass syntactic symbol, but used inside lambda (i.e. anonymous) functions. Used in C++ and Pike modes. Statement Block Symbols.

lambda-intro-cont

Lines continuing the header of a lambda function, i.e. between the lambda keyword and the function body. Only used in Pike mode. Statement Block Symbols.

inexpr-statement

A statement block inside an expression. The gcc C and C++ extension for this is recognized. It’s also used for the special functions that take a statement block as an argument in Pike. Statement Block Symbols.

inexpr-class

A class definition inside an expression. This is used for anonymous classes in Java. It’s also used for anonymous array initializers in Java. Java Symbols.


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

10.2.1 Function Symbols

This example shows a typical function declaration.

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

Line 1 shows a topmost-intro since it is the first line that introduces a top-level construct. Line 2 is a continuation of the top-level construct introduction so it has the syntax topmost-intro-cont. Line 3 shows a defun-open since it is the brace that opens a top-level function definition. Line 9 is the corresponding defun-close since it contains the brace that closes the top-level function definition. Line 4 is a defun-block-intro, i.e. it is the first line of a brace-block, enclosed in a top-level function definition.

Lines 5, 6, and 7 are all given statement syntax since there isn’t much special about them. Note however that line 8 is given statement-cont syntax since it continues the statement begun on the previous line.


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

10.2.2 Class related Symbols

Here’s an example which illustrates some C++ class syntactic symbols:

 
 1: class Bass
 2:     : public Guitar,
 3:       public Amplifiable
 4: {
 5: public:
 6:     Bass()
 7:         : eString( new BassString( 0.105 )),
 8:           aString( new BassString( 0.085 )),
 9:           dString( new BassString( 0.065 )),
10:           gString( new BassString( 0.045 ))
11:     {
12:         eString.tune( 'E' );
13:         aString.tune( 'A' );
14:         dString.tune( 'D' );
15:         gString.tune( 'G' );
16:     }
17:     friend class Luthier;
18: };

As in the previous example, line 1 has the topmost-intro syntax. Here however, the brace that opens a C++ class definition on line 4 is assigned the class-open syntax. Note that in C++, classes, structs, and unions are essentially equivalent syntactically (and are very similar semantically), so replacing the class keyword in the example above with struct or union would still result in a syntax of class-open for line 4 (38). Similarly, line 18 is assigned class-close syntax.

Note that class-open and class-close syntactic elements have two anchor points. The first is the position of the beginning of the statement, the second is the position of the keyword which defines the construct (e.g. class). These are usually the same position, but differ when the statement starts off with template (C++ Mode) or generic (Java Mode) or similar.

Line 2 introduces the inheritance list for the class so it is assigned the inher-intro syntax, and line 3, which continues the inheritance list is given inher-cont syntax.

Hitting C-c C-s on line 5 shows the following analysis:

 
((inclass 58) (access-label 58))

The primary syntactic symbol for this line is access-label as this is a label keyword that specifies access protection in C++. However, because this line is also a top-level construct inside a class definition, the analysis actually shows two syntactic symbols. The other syntactic symbol assigned to this line is inclass. Similarly, line 6 is given both inclass and topmost-intro syntax:

 
((inclass 58) (topmost-intro 60))

Line 7 introduces a C++ member initialization list and as such is given member-init-intro syntax. Note that in this case it is not assigned inclass since this is not considered a top-level construct. Lines 8 through 10 are all assigned member-init-cont since they continue the member initialization list started on line 7.

Line 11’s analysis is a bit more complicated:

 
((inclass 58) (inline-open))

This line is assigned a syntax of both inline-open and inclass because it opens an in-class C++ inline method definition. This is distinct from, but related to, the C++ notion of an inline function in that its definition occurs inside an enclosing class definition, which in C++ implies that the function should be inlined. However, if the definition of the Bass constructor appeared outside the class definition, the construct would be given the defun-open syntax, even if the keyword inline appeared before the method name, as in:

 
 1: class Bass
 2:     : public Guitar,
 3:       public Amplifiable
 4: {
 5: public:
 6:     Bass();
 7: };
 8:
 9: inline
10: Bass::Bass()
11:     : eString( new BassString( 0.105 )),
12:       aString( new BassString( 0.085 )),
13:       dString( new BassString( 0.065 )),
14:       gString( new BassString( 0.045 ))
15: {
16:     eString.tune( 'E' );
17:     aString.tune( 'A' );
18:     dString.tune( 'D' );
19:     gString.tune( 'G' );
20: }

Returning to the previous example, line 16 is given inline-close syntax, while line 12 is given defun-block-open syntax, and lines 13 through 15 are all given statement syntax. Line 17 is interesting in that its syntactic analysis list contains three elements:

 
((inclass 58) (topmost-intro 380) (friend))

The friend and inline-open syntactic symbols are modifiers that do not have anchor positions.

In the following example, line 1 gets the syntax topmost-intro, and line 2 ((inclass 1) (topmost-intro 1)) as expected. Lines 3, 4, and 5 are given the syntax (class-field-cont 18 12) rather than topmost-intro-cont. This makes it easier to indent several comma separated fields with respect to their defining type, when topmost-intro-cont would tend to leave elements directly underneath their type. See section Function Symbols. The anchor points are the positions of the type and the enclosing class’s brace.

 
 1. struct foo {
 2.     long
 3.         a,
 4.         b,
 5.         c;
 6. };

Template definitions introduce yet another syntactic symbol:

 
 1: ThingManager <int,
 2:    Framework::Callback *,
 3:    Mutex> framework_callbacks;

Here, line 1 is analyzed as a topmost-intro, but lines 2 and 3 are both analyzed as template-args-cont lines.


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

10.2.3 Conditional Construct Symbols

Here is a (totally contrived) example which illustrates how syntax is assigned to various conditional constructs:

 
 1: void spam( int index )
 2: {
 3:     for( int i=0; i<index; i++ )
 4:     {
 5:         if( i == 10 )
 6:             do_something_special();
 7:         else
 8:           silly_label:
 9:             do_something( i );
10:     }
11:     do {
12:         another_thing( i-- );
13:     }
14:     while( i > 0 );
15: }

Only the lines that illustrate new syntactic symbols will be discussed.

Line 4 has a brace which opens a conditional’s substatement block. It is thus assigned substatement-open syntax, and since line 5 is the first line in the substatement block, it is assigned statement-block-intro syntax. Line 10 contains the brace that closes the inner substatement block, and is therefore given the syntax block-close(39). Line 13 is treated the same way.

Lines 6 and 9 are also substatements of conditionals, but since they don’t start blocks they are given substatement syntax instead of substatement-open.

Line 8 contains a label, which is normally given label syntax. This one is however a bit special since it’s between a conditional and its substatement. It’s analyzed as substatement-label to let you handle this rather odd case differently from normal labels.

Line 7 start with an else that matches the if statement on line 5. It is therefore given the else-clause syntax and is anchored on the matching if. The try-catch constructs in C++ and Java are treated this way too, except that catch and (in Java) finally, are marked with catch-clause.

The while construct on line 14 that closes a do conditional is given the special syntax do-while-closure if it appears on a line by itself. Note that if the while appeared on the same line as the preceding close brace, that line would still have block-close syntax.


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

10.2.4 Switch Statement Symbols

Switch statements have their own set of syntactic symbols. Here’s an example:

 
 1: void spam( enum Ingredient i )
 2: {
 3:     switch( i ) {
 4:     case Ham:
 5:         be_a_pig();
 6:         break;
 7:     case Salt:
 8:         drink_some_water();
 9:         break;
10:     default:
11:         {
12:             what_is_it();
13:             break;
14:         }
15:     }
14: }

Here, lines 4, 7, and 10 are all assigned case-label syntax, while lines 5 and 8 are assigned statement-case-intro. Line 11 is treated slightly differently since it contains a brace that opens a block — it is given statement-case-open syntax.


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

10.2.5 Brace List Symbols

There is a set of syntactic symbols that is used to recognize constructs inside of brace lists. A brace list is defined as an aggregate initializer list, such as might statically initialize an array of structs. Note that an enum construct is (since 2024-09) no longer parsed as a brace list. Instead it now has its own syntactic symbols. Enum Symbols. The three special aggregate constructs in Pike, ({ }), ([ ]) and (< >), are treated as brace lists too. An example:

 
 1: static char* ingredients[] =
 2: {
 3:     "Ham",
 4:     "Salt",
 5:     NULL
 6: };

Following convention, line 2 in this example is assigned brace-list-open syntax, and line 3 is assigned brace-list-intro syntax. Likewise, line 6 is assigned brace-list-close syntax. Lines 4 and 5 however, are assigned brace-list-entry syntax, as would all subsequent lines in this initializer list.

Your static initializer might be initializing nested structures, for example:

 
 1: struct intpairs[] =
 2: {
 3:     { 1, 2 },
 4:     {
 5:         3,
 6:         4
 7:     }
 8:     { 1,
 9:       2 },
10:     { 3, 4 }
11: };

Here, you’ve already seen the analysis of lines 1, 2, 3, and 11. On line 4, things get interesting; this line is assigned brace-entry-open syntactic symbol because it’s a bracelist entry line that starts with an open brace. Lines 5 and 6 are pretty standard, and line 7 is a brace-list-close as you’d expect. Once again, line 8 is assigned as brace-entry-open as is line 10. Line 9 is assigned two syntactic elements, brace-list-intro with anchor point at the ‘{’ of line 8(40), and brace-list-entry anchored on the ‘1’ of line 8.


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

10.2.6 Enum Symbols

There is a set of syntactic symbols that characterize the components of enum constructs. These are very like the brace list symbols(41) (see section Brace List Symbols).

 
 1: enum test
 2: {
 3:   GOOD,
 4:   BETTER,
 5:   BEST
 6: };

Line 2 is assigned enum-open sytax, and line 6 enum-close. The first enum element on line 3 is assigned enum-intro sytax, and the remaining elements, on lines 4 and 5 are assigned enum-entry.

When the first enum element follows the ‘{’ of the enum, all on the opening line of the construct, the parsing is a little more involved.

 
 1: enum test { GOOD,
 2:   BETTER,
 3:   BEST
 4: };

Here, line 2 is assigned a syntactic context with two elements: enum-intro anchored on the beginning of indentation of line 1, and enum-entry anchored on the first element GOOD on line 1. Line 3 is enum-entry and line 4 enum-close as you’d expect.


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

10.2.7 External Scope Symbols

External language definition blocks also have their own syntactic symbols. In this example:

 
 1: extern "C"
 2: {
 3:     int thing_one( int );
 4:     int thing_two( double );
 5: }

line 2 is given the extern-lang-open syntax, while line 5 is given the extern-lang-close syntax. The analysis for line 3 yields:

 
((inextern-lang) (topmost-intro 14))

where inextern-lang is a modifier similar in purpose to inclass.

There are various other top level blocks like extern, and they are all treated in the same way except that the symbols are named after the keyword that introduces the block. E.g. C++ namespace blocks get the three symbols namespace-open, namespace-close and innamespace. The currently recognized top level blocks are:

extern-lang-open, extern-lang-close, inextern-lang

extern blocks in C and C++.(42)

namespace-open, namespace-close, innamespace

namespace blocks in C++.

module-open, module-close, inmodule

module blocks in CORBA IDL.

composition-open, composition-close, incomposition

composition blocks in CORBA CIDL.


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

10.2.8 Parenthesis (Argument) List Symbols

A number of syntactic symbols are associated with parenthesis lists, a.k.a argument lists, as found in function declarations and function calls. This example illustrates these:

 
 1: void a_function( int line1,
 2:                  int line2 );
 3:
 4: void a_longer_function(
 5:     int line1,
 6:     int line2
 7:     );
 8:
 9: void call_them( int line1, int line2 )
10: {
11:     a_function(
12:         line1,
13:         line2
14:         );
15:
16:     a_longer_function( line1,
17:                        line2 );
18: }

Lines 5 and 12 are assigned arglist-intro syntax since they are the first line following the open parenthesis, and lines 7 and 14 are assigned arglist-close syntax since they contain the parenthesis that closes the argument list.

Lines that continue argument lists can be assigned one of two syntactic symbols. For example, Lines 2 and 17 are assigned arglist-cont-nonempty syntax. What this means is that they continue an argument list, but that the line containing the parenthesis that opens the list is not empty following the open parenthesis. Contrast this against lines 6 and 13 which are assigned arglist-cont syntax. This is because the parenthesis that opens their argument lists is the last character on that line.

Syntactic elements with arglist-intro, arglist-cont-nonempty, and arglist-close contain two buffer positions: the anchor position (the beginning of the declaration or statement) and the position of the open parenthesis. The latter position can be used in a line-up function (see section Line-Up Functions).

Note that there is no arglist-open syntax. This is because any parenthesis that opens an argument list, appearing on a separate line, is assigned the statement-cont syntax instead.


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

10.2.9 Comment String Label and Macro Symbols

A few miscellaneous syntactic symbols that haven’t been previously covered are illustrated by this C++ example:

 
 1: void Bass::play( int volume )
 2: const
 3: {
 4:     /* this line starts a multiline
 5:      * comment.  This line should get `c' syntax */
 6:
 7:     char* a_multiline_string = "This line starts a multiline \
 8: string.  This line should get `string' syntax.";
 9:
10:   note:
11:     {
12: #ifdef LOCK
13:         Lock acquire();
14: #endif // LOCK
15:         slap_pop();
16:         cout << "I played "
17:              << "a note\n";
18:     }
19: }

The lines to note in this example include:


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

10.2.10 Multiline Macro Symbols

Multiline preprocessor macro definitions are normally handled just like other code, i.e. the lines inside them are indented according to the syntactic analysis of the preceding lines inside the macro. The first line inside a macro definition (i.e. the line after the starting line of the cpp directive itself) gets cpp-define-intro. In this example:

 
 1: #define LIST_LOOP(cons, listp)                         \
 2:   for (cons = listp; !NILP (cons); cons = XCDR (cons)) \
 3:     if (!CONSP (cons))                                 \
 4:       signal_error ("Invalid list format", listp);     \
 5:     else

line 1 is given the syntactic symbol cpp-macro. The first line of a cpp directive is always given that symbol. Line 2 is given cpp-define-intro, so that you can give the macro body as a whole some extra indentation. Lines 3 through 5 are then analyzed as normal code, i.e. substatement on lines 3 and 4, and else-clause on line 5.

The syntactic analysis inside macros can be turned off with c-syntactic-indentation-in-macros (see section Customizing Macros). In that case, lines 2 through 5 would all be given cpp-macro-cont with an anchor position pointing to the # which starts the cpp directive(43).

See section Customizing Macros, for more info about the treatment of macros.


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

10.2.11 Objective-C Method Symbols

In Objective-C buffers, there are three additional syntactic symbols assigned to various message calling constructs. Here’s an example illustrating these:

 
 1: - (void)setDelegate:anObject
 2:           withStuff:stuff
 3: {
 4:     [delegate masterWillRebind:self
 5:               toDelegate:anObject
 6:               withExtraStuff:stuff];
 7: }

Here, line 1 is assigned objc-method-intro syntax, and line 2 is assigned objc-method-args-cont syntax. Lines 5 and 6 are both assigned objc-method-call-cont syntax.


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

10.2.12 Java Symbols

Java has a concept of anonymous classes which can look something like this:

 
 1:  @Test
 2:  public void watch(Observable o) {
 3:      @NonNull
 4:      Observer obs = new Observer() {
 5:          public void update(Observable o, Object arg) {
 6:              history.addElement(arg);
 7:          }
 8:      };
 9:      o.addObserver(obs);
 10: }

The brace following the new operator opens the anonymous class. Lines 5 and 8 are assigned the inexpr-class syntax, besides the inclass symbol used in normal classes. Thus, the class will be indented just like a normal class, with the added indentation given to inexpr-class. An inexpr-class syntactic element doesn’t have an anchor position.

Line 2 is assigned the annotation-top-cont syntax, due to it being a continuation of a topmost introduction with an annotation symbol preceding the current line. Similarly, line 4 is assigned the annotation-var-cont syntax due to it being a continuation of a variable declaration where preceding the declaration is an annotation.


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

10.2.13 C++ Constraint Symbols

The C++20 standard introduced the notion of concepts and requirements, a typical instance of which looks something like this:

 
 1: template <typename T>
 2: requires
 3:   requires (T t) {
 4:     { ++t; }
 5:   }
 6:   && std::is_integral<T>
 7:   int foo();

Line 1 is assigned the familiar topmost-intro. Line 2 gets topmost-intro-cont, being the keyword which introduces a requires clause. Lines 3, 6, and 7 are assigned the syntax constraint-cont, being continuations of the requires clause started on line 2. Lines 4 and 5 get the syntaxes defun-block-intro and defun-close, being analyzed as though part of a function.

Note that the requires on Line 3 begins a requires expression, not a a requires clause, hence its components are not assigned constraint-cont. See https://en.cppreference.com/w/cpp/language/requires.


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

10.2.14 Statement Block Symbols

There are a few occasions where a statement block might be used inside an expression. One is in C or C++ code using the gcc extension for this, e.g:

 
 1: int res = ({
 2:         int y = foo (); int z;
 3:         if (y > 0) z = y; else z = - y;
 4:         z;
 5:     });

Lines 2 and 5 get the inexpr-statement syntax, besides the symbols they’d get in a normal block. Therefore, the indentation put on inexpr-statement is added to the normal statement block indentation. An inexpr-statement syntactic element doesn’t contain an anchor position.

C++11’s lambda expressions involve a block inside a statement. For example:

 
 1:  std::for_each(someList.begin(), someList.end(), [&total](int x) {
 2:                                                     total += x;
 3:                                                 });

Here a lambda expressions begins at the open bracket on line 1 and ends at the closing brace on line 3. Line 2, in addition to the familiar defun-block-intro syntactic element, is also prefixed by an inlambda element, which is typically used to indent the entire lambda expression to under the opening bracket.

In Pike code, there are a few other situations where blocks occur inside statements, as illustrated here:

 
 1: array itgob()
 2: {
 3:     string s = map (backtrace()[-2][3..],
 4:                     lambda
 5:                         (mixed arg)
 6:                     {
 7:                         return sprintf ("%t", arg);
 8:                     }) * ", " + "\n";
 9:     return catch {
10:             write (s + "\n");
11:         };
12: }

Lines 4 through 8 contain a lambda function, which CC Mode recognizes by the lambda keyword. If the function argument list is put on a line of its own, as in line 5, it gets the lambda-intro-cont syntax. The function body is handled as an inline method body, with the addition of the inlambda syntactic symbol. This means that line 6 gets inlambda and inline-open, and line 8 gets inline-close(44).

On line 9, catch is a special function taking a statement block as its argument. The block is handled as an in-expression statement with the inexpr-statement syntax, just like the gcc extended C example above. The other similar special function, gauge, is handled like this too.


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

10.2.15 K&R Symbols

Two other syntactic symbols can appear in old style, non-prototyped C code (45):

 
 1: int add_three_integers(a, b, c)
 2:      int a;
 3:      int b;
 4:      int c;
 5: {
 6:     return a + b + c;
 7: }

Here, line 2 is the first line in an argument declaration list and so is given the knr-argdecl-intro syntactic symbol. Subsequent lines (i.e. lines 3 and 4 in this example), are given knr-argdecl syntax.


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

10.3 Indentation Calculation

Indentation for a line is calculated from the syntactic context (see section 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 section 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 section 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.


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

This document was generated on September 26, 2026 using texi2html 1.82.