Vim Tips Wiki
(→‎Comments: missing "w"?)
(→‎Comments: fix up additional example as suggested)
Line 74: Line 74:
 
qf
 
qf
 
0y$
 
0y$
<c-w>
+
<c-w>w
/<c-r>"<cr>
+
/\V<c-r>"<cr>
<c-w>
+
<c-w>w
 
j@f
 
j@f
 
q
 
q
Line 84: Line 84:
   
 
If we include this example, though, we should consider a rename of the tip...it has nothing to do with "quick editing of structured text".
 
If we include this example, though, we should consider a rename of the tip...it has nothing to do with "quick editing of structured text".
 
:Yes, that's cute. Shouldn't "<c-w>" be "<c-w>w" (twice)?
 
:Of course you would really need to escape special characters in <tt>/<c-r>"<cr></tt> if you wanted something that worked for all possible text. I would suggest just assuming that you're looking for alnum. --[[User:JohnBeckett|JohnBeckett]] 08:14, 16 December 2008 (UTC)
 

Revision as of 14:57, 16 December 2008

Proposed tip Please edit this page to improve it, or add your comments below (do not use the discussion page).

Please use new tips to discuss whether this page should be a permanent tip, or whether it should be merged to an existing tip.
created November 7, 2008 · complexity basic · author Hongleong · version 7.0

Often, when dealing with a data file in text format (e.g. csv), we need to massage the data to modify, filter or rearrange it. Using a clever trick to recursively use Vim's complex repeats (i.e. "macro recording"), such tasks can be done easily without having to be a REGEXpert.

Let's say we have a text file with the following contents:

dr-------- 20906
drwx------ 20913
drwxr-x--- 20704
drwxr-xr-x 21104
lrwxrwxrwx 20606
-------r-- 21004
-rw-r----- 20716
-rwxrwx--- 21102

For some reason, we want to move the 5-digit number at the end of the line to after the last "r" character on the same line, and we want to repeat it for the whole file. Notice that all these numbers begin with "2" and there can be multiple "r" per line.

Here's the end-result that we want:

dr20906--------
dr20913wx------
drwxr20704-x---
drwxr-xr21104-x
lrwxrwxr20606wx
-------r21004--
-rw-r20716-----
-rwxr21102wx---

Yes, this can probably be done via :substitute with back references, but that can be intimidating for some. An easier, more flexible and often quicker method to accomplish the same task is to use "complex repeats", which really aren't too complex.

Here's how:

  1. Place the cursor on the first character of the first line of the file.
  2. Hit the following keys to record the repeat-sequence:
    • qqq : Start and immediately end recording for register q -- this essentially empties register q
    • qq : Start recording actions into register q
    • f2 : Find the "2" character to the right on this line (cursor will jump there)
    • D : Delete and yank the 5-digit number into memory (rest of line)
    • Fr : Find the "r" character to the left on this line (cursor will jump to the last "r")
    • p : Paste the number that was yanked earlier after the "r" character
    • Enter : Move the cursor to the next line
    • @q : Execute the contents of register q (itself!), which is for now, empty, so nothing will happen. The trick here is that when we run it again with "@q" after you have ended the recording, it will call itself after processing each line! This recursive loop will process all the subsequent lines in that file, until it hits the end-of-file. This is the essence that makes complex repeats so flexible and powerful.
    • q : End the recording
  3. Hit @q to apply the same manipulation to the rest of the file from the 2nd line onwards. Enjoy the art of flying cursor and automatic text manipulation on your screen.

With this knowledge, you can now quickly perform complex editing of any structured text with relative ease.

This works much the same way as typing 9999@q to execute the 'q' register as many times as the count you pass, except that you do not need to think about the size of your file before doing so to make sure enough 9's are added. One could be really clever and do :if cond | exe 'normal @q' | endif to provide a base case to end the recursion if desired, but that's probably not necessary in most cases.

See also

Comments

This concept is so cool! But, I think the tip suffers from the fact that the task at hand might be done more efficiently using another method (like regex).

How about an example of something that this is the better method for? For example, I can't think of a much better way to do this:

I wanted to verify that all file names in a list appear somewhere in another file. So, I formatted the file list to one file name per line, starting at character zero in the line, split the window with the file I want to verify the list items are in, and did the following from the list window:

qfq
qf
0y$
<c-w>w
/\V<c-r>"<cr>
<c-w>w
j@f
q

The result is that register f contains a macro that will search for every line of the list of file names, until it reaches the end of the list of file names or until it encounters an error such as "pattern not found: {filename}".

If we include this example, though, we should consider a rename of the tip...it has nothing to do with "quick editing of structured text".