2

Is it possible to configure vim and cindent to not alter indentation in c++ comments when reindenting the file (gg=G) ?

I have some formated lists in comments aligned with 4 spaces but vim interpret this as bad indent and realign everything.

For example:

/**
    my list:
         * item 1
         * item 2
 */

becomes:

/**
    my list:
    * item 1
    * item 2
*/

I want a way to tell vim: "Don't touch to comments content but indent everything else."

It is important because our project use doxygen with a markdown like parser to generate documentation and indentation is used by list levels.

1 Answer 1

1

I don't believe it's possible to achieve this with 'cinoptions'.

The correct solution is probably to write a new indentexpr that applies C-indenting (accessible via the cindent() function) only to lines that aren't within comments.

However, here's a couple of quick and dirty solutions:

Using a Macro

First, turn off 'wrapscan', so searches end when no more matches are found.

:set nows

Move the cursor to any position where it's not within a comment, and then record a recursive macro:

qqqqq=/\/\*\*\|\%$/-<CR>n/\*\//+<CR>@qq

Then you can jump to the start of the file and run the macro.

gg@q

(N.B. If the very first line of your file is a comment, you'll need to skip past this before running the macro, e.g. by doing this instead: gg/\*\/<CR>+@q)

Broken down:

  1. qqqqq: Clear out the q register and start recording a macro.
  2. =/\/\*\*\|\%$/-<CR>: Indent up to the beginning of the first comment or to the end of the file.
  3. n/\*\/+<CR>: Jump to the end of the comment.
  4. @q: Playback the q macro. Currently this is empty (we cleared it in the first step) so nothing happens, but when we run this macro for the first time, this will cause the macro to repeat as many times as necessary.
  5. q: Complete the recording.

The first regular expression used is broken down thus:

  • /: start of expression
  • \/\*\*: the start of comment (literal /**)
  • \|: or
  • \%$: the end of the file
  • /: end of expression
  • -: offset up one line (so the line itself is not indented).

Using a Function

function! IndentIgnoringComments()
  let in_comment = 0
  for i in range(1, line('$'))
    if !in_comment
      " Check if this line starts a comment
      if getline(i) =~# '^\s*/\*\*'
        let in_comment = 1
      else
        " Indent line 'i'
        execute i . "normal =="
      endif
    else
      " Check if this line ends the comment
      if getline(i) =~# '\*\/\s*$'
        let in_comment = 0
      endif
    endif
  endfor
endfunction

You can run this with :call IndentIgnoringComments() or you could set up a command or a mapping. e.g.:

nnoremap <leader>= :call IndentIgnoringComments()<CR>
1
  • Function is a nice solution for me, I will certainly add it to a command or a map as you suggested.
    – fievel
    Oct 18, 2017 at 10:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.