Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make vim indent C preprocessor directives the same as other statements

General info

(Note: Please read this all the way through, because I spent a bit of time organizing it, making sure I addressed each individual problem I'm having and why one proposed solution doesn't work for me.)

I'm using cindent in vim to automagically do indentation. It works great most of the time. However, cindent does three Bad Things (in my opinion) involving C preprocessor directives (statements starting with a hash ('#')).

In case it's relevant, I use tabs for indentation, and I my .vimrc contains filetype indent on.

Bad Thing 1

As soon as I type a preprocessor directive, vim puts it in column 1 (it completely un-indents it). For example, here's what vim does to my code as I type it:

int main(void)
{
    while(1) {
        /* normal things */
#ifdef DEBUG
        printDebugInfo();
#endif
        /* normal things */
    }
}

However, I want it look like this:

int main(void)
{
    while(1) {
        /* normal things */
        #ifdef DEBUG
        printDebugInfo();
        #endif
        /* normal things */
    }
}

In other words, I'd prefer that vim treat preprocessor directives like any other C/C++ statement.

Bad Thing 2

When I use == on (or [movement]= across) a line with a preprocessor directive, vim puts it back in column 1. (This is consistent with Bad Thing 1 but still a problem.)

Bad Thing 3

If (because of Bad Thing 1 or 2 or the use of <<) a preprocessor directive ends up in column 1, it becomes "stuck" there and isn't affected by >>. The only way to increase the indentation is I<Tab> or i<Ctrl-t>. It then becomes "un-stuck" and I can move it with << or >>.

Failed solutions

One solution suggests putting set cinkeys-=0# in my .vimrc. This fixes Bad Things 1 - 3, but adds a new one:

Bad Thing 4 (only with cinkeys-=0#)

Preprocessor directives in column 1 aren't affected by == or [movement]=, meaning I still can't automagically fix their indentation until I manually indent them with >> or by inserting a tab character.

Question

Is there a way to resolve Bad Things 1 - 3 without introducing Bad Thing 4? Can I force vim to treat lines starting with '#' like ordinary C statements?

(Or am I just using #ifdefs in a harmful way, and this is vim's way of telling me to stop?)

I'd prefer not to patch vim and/or recompile, but I will if I have to.

like image 492
Dr Kitty Avatar asked Apr 16 '13 21:04

Dr Kitty


People also ask

Should preprocessor directives be indented?

C static code analysis: Preprocessor directives should not be indented.

What is the difference between preprocessor and directives?

Preprocessing is an initial phase to process text before compilation. Preprocessor directives are lines of the source file where the first non-whitespace character is # , which distinguishes them from other lines of text.

What is the difference between a macro and the preprocessor directives used in C?

Macro: a word defined by the #define preprocessor directive that evaluates to some other expression. Preprocessor directive: a special #-keyword, recognized by the preprocessor. Show activity on this post. preprocessor modifies the source file before handing it over the compiler.

What is preprocessor directive write short note on #define and #include?

Preprocessor directives are lines included in a program that begin with the character #, which make them different from a typical source code text. They are invoked by the compiler to process some programs before compilation.


2 Answers

From the Vim documentation, under cinoptions:

Vim puts a line in column 1 if:

  • It starts with '#' (preprocessor directives), if 'cinkeys' contains '#'.
  • It starts with a label (a keyword followed by ':', other than "case" and "default") and 'cinoptions' does not contain an 'L' entry with a positive value.
  • Any combination of indentations causes the line to have less than 0 indentation.

So, removing 0# from cinkeys should override that default behavior. (This idea turns up in enough places on the interwebs.)

set cinkeys=0{,0},0),:,!^F,o,O,e

With that change to cinkeys, here's what I got, exactly what you're looking for:

int main(void)
{
    while(1) {
        /* normal things */
        #ifdef DEBUG
        printDebugInfo();
        #endif
        /* normal things */
    }
}
like image 152
Mogsdad Avatar answered Sep 27 '22 17:09

Mogsdad


Solution for Bad Thing 4

set cinoptions+=#1s

This will indent by 1 shiftwidth if you use == or [movement]=. Combining it with the option cinkeys-=0# worked for me.

like image 38
leo Avatar answered Sep 27 '22 15:09

leo