15

Suppose I have this code:

width: 215px;
height: 22px;
margin-top: 3px;
background-color: white;
border: 1px solid #999999;

I want to align it this way:

width:            215px;
height:           22px;
margin-top:       3px;
background-color: white;
border:           1px solid #999999;

using Align.vim I can do :Align \s to use whitespace as separator, but that has 2 problems

  1. the initial indent is doubled
  2. all whitespaces are considered separators, so the last line is messed up

I've read through the many options Align.vim offers, but I haven't found a way to do this.

Matteo Riva
  • 24,728
  • 12
  • 72
  • 104
  • 1
    For small yet relatively universal alignment tricks that work without plugins, see [the answer](http://stackoverflow.com/a/7538363/254635) to the question "[Inserting indentation for columns in Vim](http://stackoverflow.com/q/7529029/254635)". – ib. Dec 03 '11 at 03:18

4 Answers4

30

You can do this with a Vim macro, no plugins needed. Put the cursor anywhere on the first line, and type in normal mode, not insert mode:

qa0f:w100i <Esc>19|dwjq4@a

Note the single space after the 100i, and the <Esc> means "press escape"--don't type "<Esc>" literally.

Translation:

qa         -- record macro in hotkey a
0          -- go to beginning of line
f:         -- go to first : symbol
w          -- go to next non-space character after the symbol
100i <Esc> -- insert 100 spaces
19|        -- go to 19th column (value 19 figured out manually)
dw         -- delete spaces until : symbol
j          -- go to next line
q          -- stop recording macro
4@a        -- run the macro 4 times (for the remaining 4 lines)

And yes, I used a similar macro to format the above code block :)

Cf. my answer to a similar Vim alignment question.

To apply this to a number of lines in visual mode, do, select and type:

:norm!@a
Community
  • 1
  • 1
TalkLittle
  • 8,866
  • 6
  • 54
  • 51
  • 5
    great that you followed up with the explanation - without it I wouldn't dare type this magical incantation, for fear of my soul and disk contents, but with it I'll even learn a few new interesting (albeit perversely) vim commands! – akavel Nov 16 '12 at 13:36
  • 2
    @TalkLittle excellent use of a plugin-free solution that does not require any additional addons. Excellent use of a commented vim command to help new users. All good practice in supporting and explaining the power of native vim. – dreftymac Mar 30 '16 at 17:24
11

If you use Tabular, then you can just do :Tabularize /:\zs/.

Looking at Align's description on vim.org, a similar invocation should work for it. You could try :Align :\zs. I don't use Align, so I'm not positive.

jamessan
  • 41,569
  • 8
  • 85
  • 85
  • Yeah, that works with Align. You may want to use `:AlignCtrl l:` (or similar) to have any further colons disregarded. – Michał Marczyk Jan 25 '10 at 03:32
  • 3
    Could someone explain what `\zs` means? – kizzx2 Jul 07 '11 at 08:39
  • Using `\zs` will match everything before `\zs` but put it back in the results. That is, it will leave whatever you have before `\zs` intact (just as if you would have put a group `(...)` around it and used `\1` first in the replacement. See `:h /\zs` – Adam Lindberg Nov 22 '11 at 14:39
3

Utilize @TalkLittle's algorithm, this can be done with this code, which is a little bit easier for the eyes to me:)

  • add enough spcaes after the first colon

    :%s/^[^:]:\zs/lots of spaces/

  • but if pressing spaces all the time hurts your thumb, use this instead

    :%s/^[^:]:\zs/\=repeat(' ',100)/

  • then delete all spaces after column 19

    :%s/\%19v\s*//

    NOTE: % will do this on all lines, specify a range if you don't want this.

  • if you don't feel like to count to 19, use this:

    %s/:\zs.*// | %s/.*/\=len(submatch(0))/ | sort! n | let n=getline(1) | undo | echo 'the column nmuber of the right most ":" is' n

Community
  • 1
  • 1
ipirlo
  • 130
  • 6
1

You still can do it with your preferred plugin Align.vim with command:

Align! lp0P0: \s

Align! means that first argument is AlignCtrl format where you order the first match to be left (l) aligned without spaces padding (p0P0) and you also want to skip (:) all subsequent matches. This example could be expanded for more sophisticated alignments.

mrajner
  • 392
  • 4
  • 9
  • I have a similar question, but don't want the padding in the OP's question. I have tried altering your answer as :Align! 1: and :Align! 1: \s and :Align 1: etc., but have not found how to use something similar to your response to get Align to only align about the first :. How would I do that? – Shawn Jul 14 '20 at 23:51