4

I have file where I would like to indent all the lines between curly braces:

html {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
body {
line-height: 1.5;
color: black;
background: white;
}

I could do this with :g/{/ .+1,/}/-1 > Ex command. However, I also tried to do the same with regular expression :g/\v\{\_s?\zs\_.{-}\ze\}/ >. This will match all the lines between curly braces and I expected > command to indent the matched lines. Instead, it indents the html { and body { lines:

        html {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
        body {
line-height: 1.5;
color: black;
background: white;
}

What is the reason for such behavior?

  • 2
    From vim Documentation :h global : for a multi-line pattern, only the start of the match matters; so it only considers just two lines that your matchs start. here the lines include \zs exactly after {'s and indent them. – dNitro Aug 24 '16 at 21:57
  • 2
    What about gg=G? – romainl Aug 24 '16 at 22:17
  • 2
    @dNitro Actually the \zs matches on the line following the '{' since \_s? matches a newline. But :global marks lines at the start of the entire matching process, even if \zs matches on a subsequent line. Unless that's what you meant; I'm not sure :-) – Antony Sep 4 '16 at 20:33
  • @Antony, Tanx, crystal clear ;) – dNitro Sep 4 '16 at 20:40
6
+50

I'm guessing the problem is that :global operates linewise, so the \zs and \ze in your regex don't do anything; They still apply to the line that matched the entire pattern, not the line that the selection starts and ends on. For example, if you have the following text:

foo
bar

and you do

:g/foo\n\zsb/d

This will delete foo rather than deleting bar. Keep in mind, this is mostly a guess, I've never ran into this behavior before, all though it's reproducible. Really though, if you think about it, it makes sense. The definition of the global command is:

:[range]g[lobal]/{pattern}/[cmd]
            Execute the Ex command [cmd] (default ":p") on the
            LINES within [range] where {pattern} matches.

(Emphasis added). foo matches the pattern foo\n\zsbar, so it's irrelevant that you moved the selection forward; the line still matches. On the other hand, there is no possible way for bar to match the pattern foo\n\zsbar.

One thing you could do to make your command simpler is to use the negative global command, e.g. an ex command on every line not matching. That could just be:

:g!/{\|}/>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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