2

I have a file like this:

int var;

int f() {
    // Use of var
}

int g() {
    // Use of var
}

int h() {
    // Use of var
}

// ...

I want to move my global var into each function to get this file:

int f() {
    int var;
    // Use of var
}

int g() {
    int var;
    // Use of var
}

int h() {
    int var;
    // Use of var
}

// ...

I started by yanking the declaration of var and then created a macro to paste the contents of the register every 4 lines. This method has 2 problems. First, if my functions f, g, h, ... have different numbers of lines, I can't use it. Also, I have to type @@ to repeat my macro again and again.

Is there a way to tell vim to paste the contents of my register after each line that matches a pattern: /^int .*() {$/ in my example?

1 Answer 1

4

Using a :global command

You can use a :global command to run a command on every line that matches a pattern. Try the following:

:g/^int .*() {$/put

You can equally easily run a macro once on each line that matches the pattern:

:g/^int .*() {$/normal! @q

Using a macro

An alternative solution is to alter your macro so that:

  1. Instead of just moving down four lines, it uses more precise motions to move to the correct place,

  2. It stops when it gets to the end of the file, so that instead of having to type @@ the exact number of times, you can instead just use a really large count, e.g. 99@q

Here's one way you could do this:

Starting with the cursor at the top of the file (and having already yanked the variable definition with a linewise command such as yy), type the following:

qq][%p==][q

Breaking that down:

  1. qq Start recording a macro into the "q register,
  2. ][ Jump to the } brace at the end of the function,
  3. % Jump back to the opening { brace,
  4. p Put/paste your line,
  5. == Ensure indentation is correct,
  6. ][ Jump to the end of the function again, so that we're in the correct place the next time the macro is called,
  7. q End the recording.

An alternative to the ][ and % motions is simply to include your search in the macro, but note that if you then want to playback the macro with a very large count (rather than using a precise count or manually typing @@ until you get to the last match in the buffer), you will need to turn off 'wrapscan' to stop the macro wrapping around to the start of the buffer when it reaches the end:

:set nowrapscan
2
  • 2
    Why not :g/^int .*() {$/put ? No need to invoke normal
    – D. Ben Knoble
    Commented Oct 17, 2019 at 14:11
  • @D.BenKnoble For some reason I rejected that solution when composing the answer, but I have no idea why. Updated. Thanks!
    – Rich
    Commented Oct 17, 2019 at 14:19

Your Answer

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

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