firedev
firedev

Reputation: 21088

Vim: How to gather all matching and surrounding lines from file?

Since suggestion for a separate VimOverflow was rejected, would have to continue posting here.

I had to move translations from one file to another one only msgid matches some specific RegExp.

Translations are repeated in blocks, plus they can span multiple lines:

# English.po

#: ...
msgid "..."
msgstr "..."

#: templates/common/commonTranslation.phtml:10 | These parts can be
#: any/number/of/lines/can/precede/the/data:0  | of any length.
msgid "buttonhelp.edit"                       <- Matching string
msgstr "Edit your details"                     | 
"the long line continues"                      | Translation
"and can be even longer"                       |

#: ...
msgid "..."
msgstr "..."

Here is what I did in Sublime:

  1. Did a regexp for msgid pattern that I need.
  2. Sublime places multiple cursors around the file.
  3. Up, Up, Shift-Down-Down-Down-Down – all translation blocks with the surrounding blank lines are selected.
  4. Cmd-C, Paste in the new file. Done.

How could I do that in Vim?

Just to reiterate, I need multiple selections that I can extract to a separate file based on the msgid value. Here is what a single selection block looks like including the trailing and leading blank lines:

     
#: templates/common/commonTranslation.phtml:10
msgid "buttonhelp.edit" # <- value for regexp
msgstr "Edit your details"
 

Update Sorry at first I didn't realise that my self, but translations can span an unspecified amount of lines, that's where Sublime fell short, since I have selected blocks of a fixed size. But translations are always separated by a blank line, except the end of file, but we can disregard that. This is the shortest amount of data possible:

     
#~ msgid "hotline.title"  | POEdit stores obsolete
#~ msgstr "HOTLINE"       | strings as well
 

Solved Thanks to commenters it finally dawned on me and here is what I did in the end:

:let @a=''
:g/\v"\w+\.\w+"/norm! "Ayap
:tabe
:put A

It clears up the a register first, finds all lines with dots between words inside quotes ("\w+\.\w+") and yanks the surrounding paragraphs into the a register the content of which I am pasting into a new tab.

Upvotes: 1

Views: 596

Answers (2)

Ingo Karkat
Ingo Karkat

Reputation: 172510

You can locate (and execute a yank command) on all matching lines via :global.

In case you always need the lines above and below the msgid line, you can specify those as a range .-1,.+1 (.+2 to include the empty separator line, too).

To accumulate all matches in a register, first clear it, and use the uppercase for (for appending):

:let @a = '' | global/^msgid "\.\.\."/.-1,.+1yank A

To put that into another buffer, you can use

:new | put! a

Upvotes: 1

Kent
Kent

Reputation: 195029

to "yank" all those blocks in register a , you could try this in vim:

:g/msgid "buttonhelp\./norm! 2kV2)"Ay

in above :g cmd, the msgid "buttonhelp\. is the regex to match your msgid.

before exec the :g cmd, please do a qaq to clear the a register.

Upvotes: 1

Related Questions