No namespace indent for C++ with Vim

(NOTE: There’s a more up to date version of this in the General C++ Settings section.)

Finally! Vim’s decision to add a ‘shiftwidth‘ to everything I type when I’m inside a namespace is thoroughly annoying and there appears to be no “standard” way to fix this in Vim aside from writing your own function for use in the ‘indentexpr‘ option.

Well I finally got around to writing this up and, while extremely crude, it appears to work alright. You’ll find the function definition below as well as in the General C++ Settings section.

" Fix up indent issues - I can't stand wasting an indent because

" I'm in a namespace. If you don't like this then just comment

" this line out.

setlocal indentexpr=GetCppIndentNoNamespace(v:lnum)

"

" GetCppIndentNoNamespace()

"

" This little function calculates the indent level for C++ and

" treats the namespace differently than usual - we ignore it. The

" indent level is the for a given line is the same as it would

" be were the namespace not event there.

"

" This function is rather crude but it works.

"

function! GetCppIndentNoNamespace(lnum)

let nsLineNum = search('^\s*\\s\+\S\+', 'bnW')

if nsLineNum == 0

return cindent(a:lnum)

else

let incomment = 0

for n in range(nsLineNum + 1, a:lnum - 1)

let cline = getline(n)

if cline =~ '^\s*/\*'

let incomment = 1

elseif cline =~ '^.*\*/'

let incomment = 0

elseif incomment == 0

if cline =~ '^\s*\S\+'

return cindent(a:lnum)

endif

endif

endfor

return cindent(nsLineNum)

endif

endfunction

2 comments on this post.
  1. Mike Jarvis:

    This is great. Thanks!

    The other C++ thing that I think vim gets wrong is indenting the line after template. I’d like the intent to look like:

    template <typename T>
    T foo(T x);

    But vim indents the second line. The only workaround I had found was to add +0 to cinoptions, but that has other undesirable side effects.

    Your function for (not) indenting namespace blocks might give me enough of a starting point to extend it to get the indent right for these lines as well.

    Peace,
    Mike

  2. Leandro:

    This is exactly what I need, but unfortunately it is not working here. :-(

    Analyzing your code, I couldn’t figure out what does ‘^\s*\\s\+\S\+’ match after the beginning of the line (‘^’) and blanks (‘\s*’). Apparently the next 5 chars (‘\\s\+’) evaluates to another regex (‘\s+’) but I don’t see the point. The tail of the string then matches one non blank char (‘\S+’) and the last part escapes a plus sign. If I’m right, the string on the next line would match (ignoring the ‘^’ which indicates the beginning of the line):
    ^ \s+a+

    Like I said before, I don’t see where it takes. Could you give me a light?

    Thanks in advance for your attention.

    Regards,
    Leandro

Leave a comment