5

Apologies if this has been posted already, for I cannot find an answer, even on the vim wiki.

Is there a way I can run multiple commands in vim command-line mode off of a single :g search?

For example,

:%g/foo/ s/bar/\=@a/g | exe "norm /cat\<enter>\"ayiw"

Which (for what I intend it to do) should, on every line matching foo, replace bar with the contents of register a, and then find the next iteration of cat (even if it is many lines ahead), and put the surrounding word into register a.

Instead, this specific syntax completes the subsitution command using the current contents of the initial a register, and then executes the normal mode command on a single line (after the substitution has been completed).

This example is not my specific use-case but shows one instance where this functionality is useful. I realize I could put it all into a single exe, i.e., %g/foo/exe "norm :s/bar/\\=@a/g\<enter>/cat\<enter>\"ayiw", but I would like to do it the first way, as I feel it is more flexible.


I would prefer to do this using vanilla vim, but if a plugin exists for this, that is an okay alternative. Does anybody know if there is syntax to do such a thing?

1
  • 1
    Interesting. Normally, the norm ... should be executed once on each matching line, but it really looks like it's only executed once. The /.../ search seems to cause this. Commented Jul 31, 2017 at 10:37

3 Answers 3

1

Okay a "little bit" dirty, but does this work for you?

:let list = split(execute('g/cat/p'), '\n') | g/foo/ s/bar/\=matchstr(remove(list, 0), '\s\d\+\s\zs.*')/g

It first reads all occurences of cat save them in a list. Then replace the first bar with the first cat... and so on.

The dirty part ist the matchstr command. the g//p also returns a number for the result so the list looks like this:

 1 cat
 2 cat
 3 cat
 ...

that's why we have to remove a bit from the front. I would love to hear if someone knows a clean solution for that (I am also interested in a clean vimscript solution, does not have to be a oneliner).

Sign up to request clarification or add additional context in comments.

Comments

1

You can do this (at least for multiple :s commands applied to a single :g). Example:

" SHORT STORY TITLES to single word of CapitalizedWords within <h3>s
.,$g/^\L\+$/s/[^A-Z0-9 ]\+//ge|s/\u\+/\L&/ge|s/\<\l\+\>/\u&/ge|s/ \+//ge|s/.*/<h3>&<\/h3>/

Comments

0

@user985675 solution of concatenation with [ | ] character works also for [ non-:s ] commands

Example

In

- t- write sum
    8.8
    min
    24
- t- test dev
    7.4
    min
    20

Test

Run '<,'>g/^\s*\zs\d\+\./s/\S\+/- oI- \0/g|j command on selection (entire input)

  • '<,'>g = global command within selection
  • /^\s*\zs\d\+\. = search for lines that match pattern (whitespaces from start of line until numbers followed by dot)
  • /s/\S\+/- oI- \0/g = substitute on matching lines (search for non-whitespace chars, prepend entire match with [ - oI- text ])
  • |j = join lines that match global

Out

- t- write sum
    - oI- 8.8 min
    24
- t- test dev
    - oI- 7.4 min
    20
- t- comm dev
    - oI- 5.2 min
    14
- t- do dev
    - oI- 15.3 min
    42

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.