Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You can use the <code>:s</code> command with the <code>\=</code> aka sub-replace-expression.</p> <pre><code>:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.escape(submatch(2),'~&amp;\').'\2','')# </code></pre> <p><strong>Overview</strong></p> <p>Capture the text (including white-space) between the <code>&gt;&gt;&gt;</code> and <code>&lt;&lt;&lt;</code> marks. Divide up the white-space on both sides of the text in half and substitute in the non-white-space text in between. This white-space balancing act is done via the regex engine's backtracking because math is hard. Lets go shopping!</p> <p>Notes:</p> <ul> <li>using <code>\v</code> or <code>very magic</code> mode to reduce escaping as this command is long enough already</li> <li>use <code>#</code> as an alternative separator instead of the usual <code>/</code> for <code>:s/pat/sub/</code> in hopes to make it slightly more readable</li> </ul> <p><strong>Matching Pattern</strong></p> <pre><code>:s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#... </code></pre> <ul> <li><code>:s</code> with no range supplied only do the substitution on the current line.</li> <li><code>^\s*\S+</code> match the starting white-space followed by non-white-space. <code>&gt;&gt;&gt;</code> in this case.</li> <li><code>(\s+)(.{-})(\s+)</code> match white-space followed by the "text" followed by white-space</li> <li>3 capture groups: 1) leading white-space, 2) the "text", and 3) trailing white-space. These will be later referenced by <code>submatch(1)</code>, <code>submatch(2)</code>, and <code>submatch(3)</code> respectively</li> <li><code>.{-}</code> is vim-speak for non-greedy matching or <code>.*?</code> in perl-speak</li> <li>without the non-greedy matching the second capture group would include too much white-space at its end</li> <li><code>\S+\s*$</code> match the non-white-space (i.e. <code>&lt;&lt;&lt;</code>) and any trailing white-space</li> <li>Use <code>\zs</code> and <code>ze</code> to designate the start and end of the match to be replaced</li> </ul> <p><strong>Replacement</strong></p> <pre><code>\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.escape(submatch(2),'~&amp;\').'\2','') </code></pre> <ul> <li><code>\=</code> tells vim that replacement will be a vim expression. Also allows the use of <code>submatch()</code> functions</li> <li><code>substitute({str}, {pat}, {sub}, {flags})</code> Our expression will be a nested substitution</li> <li><code>substitute(submatch(1).submatch(3), ...)</code> do a substitute over the concatenation of leading and trailing white-spacing captured in <code>submatch(1)</code> and <code>submatch(3)</code></li> <li>The <code>{pat}</code> is <code>^(\s*)(\1\s=)$</code>. Match some white-space followed by white-space of the same length as the first or 1 character longer. Capture both halves.</li> <li><code>escape(submatch(2),'~&amp;\')</code> escape <code>submatch(2)</code> for any special characters. e.g. <code>~</code>,<code>&amp;</code>,<code>\1</code>, ...</li> <li>The <code>{sub}</code> is <code>'\1'.escape(submatch(2),'~&amp;\').'\2'</code>. Replace with the the escaped <code>submatch(2)</code> (i.e. the "text" we want to center) in between the halves of white-space, <code>\1</code> and <code>\2</code> from the <code>{pat}</code></li> <li>No <code>{flag}</code>'s are needed so <code>''</code></li> </ul> <p><strong>Usage</strong></p> <p>If you use this often I would suggest creating a command and putting it in <code>~/.vimrc</code>. </p> <pre><code>command! -range -bar -nargs=0 CenterBetween &lt;line1&gt;,&lt;line2&gt;s#\v^\s*\S+\zs(\s+)(.{-})(\s+)\ze\S+\s*$#\=substitute(submatch(1).submatch(3),'\v^(\s*)(\1\s=)$','\1'.submatch(2).'\2','')#` </code></pre> <p>Otherwise use this once and then repeat the last substitution via <code>&amp;</code> on each needed line.</p> <p><strong>For more help see</strong></p> <pre><code>:h :s/ :h :s/\= :h sub-replace-\= :h submatch( :h substitute( :h escape( :h /\v :h /\S :h /\{- :h /\zs :h &amp; </code></pre> <p><strong>EDIT by Kent</strong></p> <p>Don't be jealous, your answer has it too. ^_^</p> <p>I didn't change the command, just cp/paste to my vim. only add <code>|noh</code> at the end to disable highlighting.</p> <p>If execute this command, it looks like:</p> <p><img src="https://i.stack.imgur.com/q4lkP.gif" alt="enter image description here"></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload