Using a macro or a :s
command is probably the easiest way to get this task done...
But if you'd like to explore an alternative, then the gn
command is a good fit. This commands selects the next search match in a visual selection. You can use it as a text object, so you can have your ys
command act on the gn
block, which you can then simply repeat with a .
, without the need for a motion to get to the next match.
The problem with using the gn
command here is that we need a fairly complex regular expression, since it needs to only match the text before the modification, but not match it after it. If the search pattern still matches the text after the modification, the gn
command will apply the modification again to the current block, rather than skip to the next one.
So let's come up with a search that will match sequences of non-whitespace characters, as long as they don't start with a single quote.
This search pattern should work:
/\v(^|\s@<=)[^' \t]\S+
If you have 'hlsearch'
set, you'll see Vim highlighting each of the individual words, one
, two
, three
, four
. If you surround any of them with '
, it will stop being highlighted, which means it will no longer match.
This regex is fairly complex. I'm using "verymagic" mode to avoid having to backquote many metacharacters. Then I'm matching a start of line ^
or a space, but I'm using a zero-width match-behind /\@<=
to match it without including it into the pattern. This is to ensure we only match beginning of words. Then I'm using [^' \t]
to match a character other than the single quote, a space or a tab. So this is the start of a word (sequence of non-whitespace characters) that doesn't start with a single quote.
Having performed this search, we're ready to use the gn
magic. Set your cursor somewhere in the first word you want to change, in this case one
, and then use:
ysgn'
This will surround the one
in single quotes: 'one'
. If you have 'hlsearch'
enabled, you'll see that 'one'
is no longer highlighted, since it's not a match anymore.
At this point, you can repeat the ysgn'
command with a single .
. Since the word under the cursor is not a match, Vim will jump forward to the next match and act on it, so you'll get 'one' 'two'
. Repeat it one more time with .
and you'll get 'three'
, and finally one last .
for 'four'
. Done!
So this is probably overkill for this specific case, but when you're doing operations that modify the term enough that it's easy to match it before the change and not match it after the change, this technique is super useful. One great example is switching identifiers from snake_case
to CamelCase
or vice-versa.
:s/\w\+/'&'/g
solve your problem? If not, please give a more representative example. – Quasímodo Sep 24 '20 at 18:04f g one two three four
and you want itf g "one" "two" "th...
– theonlygusti Sep 24 '20 at 20:41:s/\w\{2,}/"&"/g
will only replace on words with at least two characters, so it won't matchf
org
. – filbranden♦ Sep 25 '20 at 3:10f g f g f g
and you wantf g f "g" "f" "g"
. Yes you can continue making the substitution more complex, but I'd just love to learn about a way to repeat commands. Looks like it doesn't exist. (I guess you can3@:
) – theonlygusti Sep 25 '20 at 8:31