Search code examples
vim

How can I get the whitespace at the beginning of a line and use it in a search and replace?


Background

I want to convert an if statement from Fortran to C++. I like to have braces on a new line.

So I want to make

    ! this may be nested so indentation is unknown
    if ( condition ) then
        block
    end if

to

    if ( condition )
    {
        block
    }

Changing end if to } is easy since the indentation is already how I want it. I just used :%s/end if/}/gc.

However, changing then is more challenging. I need to create a new line and set its the leading whitespace to the same as the previous line. The closest I have to a solution is :%s/then/\=printf("\n%s{",indent(line('.')))/gc However I want to use the value returned from indent(line('.') to set the number of indents.

Problem

Can I use a number I receive from a function to set the number of tabs at the beginning of line in a search and replace?


Solution

  • You want to substitute then with:

    • a newline,
    • followed by n spaces, as many as used for indenting the current line,
    • followed by an opening brace.

    As is, your command does the following:

    • a newline,
    • followed by the number of spaces used for the indentation of the current line,
    • followed by an opening brace.

    :help repeat() to the rescue:

    :%s/then/\=printf("\n%s{",repeat(' ',indent(line('.'))))/gc
    

    But there is still room for improvement…

    • you only want to substitute trailing thens so the g flag is useless:

      :%s/then/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
      
    • the search pattern may match other thens so it should be restricted a little:

      :%s/then\s*$/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
      
    • also, the pattern should include any whitespace before the then to avoid leaving annoying trailing whitespace behind:

      :%s/\s*then\s*$/\=printf("\n%s{",repeat(' ',indent(line('.'))))/c
      
    • line('.') is unnecessary:

      :%s/\s*then\s*$/\=printf("\n%s{",repeat(' ',indent('.')))/c
      
    • and we could use the new-ish "method" syntax to limit parenthesis nesting:

      :%s/\s*then\s*$/\=repeat(' ',indent('.'))->printf("\n%s{")/c