rxin
rxin

Reputation: 1786

auto indent in vim string replacement new line?

I'm using the following command to auto replace some code (adding a new code segment after an existing segment)

%s/my_pattern/\0, \r some_other_text_i_want_to_insert/

The problem is that with the \r, some_other_text_i_want_to_insert gets inserted right after the new line:

mycode(
  some_random_text my_pattern
)

would become

mycode(
   some_random_text my_pattern
some_other_text_i_want_to_insert   <--- this line is NOT indented
)

instead of

mycode(
   some_random_text my_pattern
   some_other_text_i_want_to_insert  <--- this line is now indented
)

i.e. the new inserted line is not indented.

Is there any option in vim or trick that I can use to indent the newly inserted line?

Thanks.

Upvotes: 6

Views: 2700

Answers (6)

Justin Helps
Justin Helps

Reputation: 235

I achieved this by using \s* at the beginning of my pattern to capture the preceding whitespace.

I'm using the vim addon for VSCode, which doesn't seem to match standard vim completely, but for me,

:%s/(\s*)(existing line)/$1$2\n$1added line/g

turns this

mycode{
    existing line
}

into this

mycode{
    existing line
    added line
}

The parentheses in the search pattern define groups which are referenced by $1 and $2. In this case $1 is the white space captured by (\s*). I'm not an expert on different implementations of vim or regex, but as far as I can tell, this way of referencing regex groups is specific to VSCode (or at least not general). More explanation of that here. Using \s* to capture a group of whitespace should be general, though, or at least have a close analog in your environment.

Upvotes: 0

ddrscott
ddrscott

Reputation: 539

How about normal =``?

:%s/my_pattern/\0, \r some_other_text_i_want_to_insert/ | normal =``

<equal><backtick><backtick>: re-index position before latest jump

(Sorry about the strange formatting, escaping backtick is really hard to use here)

To keep them as separate command you could do one of these mappings:

" Equalize and move cursor to end of change - more intuitive for me"
nnoremap =. :normal! =````<CR>

" Equalize and keeps cursor at beginning of change"
nnoremap =. :keepjumps normal! =``<CR>

I read the mapping as "equalize last change" since dot already means "repeat last change".

Or skip the mapping altogether since =`` is only 3 keys with 2 of them being repeats. Easy peasy, lemon squeezy!

References

:help =
:help mark-motions

Upvotes: 1

Sameer
Sameer

Reputation: 2505

You can do it in two steps. This is similar to Bill's answer but simpler and slightly more flexible, since you can use part of the original string in the replacement. First substitute and then indent.

:%s/my_pattern/\0, \r some_other_text_i_want_to_insert/

:%g/some_other_text_i_want_to_insert/normal ==

If you use part of the original string with \0,\1, etc. just use the common part of the replacement string for the :global (second) command.

Upvotes: 0

Bill Odom
Bill Odom

Reputation: 4193

Try this:

:let @x="some_other_text_i_want_to_insert\n"
:g/my_pattern/normal "x]p

Here it is, step by step:

First, place the text you want to insert in a register...

:let @x="some_other_text_i_want_to_insert\n"

(Note the newline at the end of the string -- it's important.)

Next, use the :global command to put the text after each matching line...

:g/my_pattern/normal "x]p

The ]p normal-mode command works just like the regular p command (that is, it puts the contents of a register after the current line), but also adjusts the indentation to match.

More info:

:help ]p
:help :global
:help :normal

Upvotes: 4

ZyX
ZyX

Reputation: 53604

%s/my_pattern/\=submatch(0).", \n".matchstr(getline('.'), '^\s*').'some_other_text'/g

Note that you will have to use submatch and concatenation instead of & and \N. This answer is based on the fact that substitute command puts the cursor on the line where it does the substitution.

Upvotes: 3

user229044
user229044

Reputation: 239240

Kind of a round-about way of achieving the same thing: You could record a macro which finds the next occurance of my_pattern and inserts after it a newline and your replacement string. If auto-indent is turned on, the indent level will be maintained reagardless of where the occurance of my_pattern is found.

Something like this key sequence:

q 1                  # begin recording
/my_pattern/e        # find my_pattern, set cursor to end of match
a                    # append
\nsome_other_text... # the text to append
<esc>                # exit insert mode
q                    # stop recording

Repeated by pressing @1

Upvotes: 0

Related Questions