17

The question's title might sound a little vague, so I'll explain the situation here more clearly. I have these lines of code in a file which I want to align with respect to the character =.

const service = require('./service');
const baseService = require('./baseService');
const config = require('../config');
const Promise = require('bluebird');
const errors = require('../errors');

I want the above lines to somehow look like this

const service     = require('./service');
const baseService = require('./baseService');
const config      = require('../config');
const Promise     = require('bluebird');
const errors      = require('../errors');

I hope you understand what I'm trying to ask. I want all the = characters to lie in the same column and shift the after-coming code accordingly. What can I do to achieve this task?

A plugin capable of doing this would be nice, but it'd be great if I could do this without the aid of any plugin. That way I'd also learn something.

3

3 Answers 3

15

If you're in a pinch and want to get the expressions aligned, without having to install and learn any plug-ins, here is a quick way to do it.

  1. Select the lines on a visual selection. For example, if this is your whole buffer, you could use ggVG, but if these lines are in the middle of a file, just select appropriately. Perhaps V4j?
  2. Insert enough whitespace before the =, which you can do with :normal f=9i . (Note the "space" at the end.) This will add 9 spaces before each = in the lines of the visual selection. If 9 is not enough, add more (like 99 or 999, as much as you want.) Note that when you type : with the visual selection, Vim will automatically insert the range, so the actual command is :'<,'>normal f=9i , but you don't need to type those characters.
  3. Move to the column where you want the =s to be flushed to. In this case, line 2 has the longest variable name, so move to two spaces after the end of that name, which is where the =s should be at the end. If this is the whole buffer, you could use 2G2e2l to get there.
  4. Staying on that same column, move to the first line of the block. In this case, you're moving from line 2 to line 1, so k is enough.
  5. Start visual-block selection, pressing Ctrl-V.
  6. Move to the last line of the block. If this is the whole buffer, you could use G, if this is the middle of a file, you could use 4j to go four lines down, etc.
  7. (Optional) Use $ to select until the end of the line, on every line of the visual block selection. UPDATE: This step is actually not necessary here, since < will work correctly even if you don't select lines to the end. Using $ is important when using e.g. A to append to the end of all lines though.
  8. Now you can use the < command to shift the lines left, but until they hit the left of the visual block. Each < will shift them by one 'shiftwidth' only, so you're likely to need more than one. So, to be sure, use 9< (or 99<, or 999<, if you added tons of spaces in step 2.)

Voilà!

This is a pretty cool technique and it can be helpful when you need more flexibility than plug-ins can afford you. It's a good one to learn and keep on your Vim toolbox.

9
  • 2
    Thanks. Nice trick.
    – dedowsdi
    Commented Jul 19, 2019 at 5:57
  • 2
    Is $ necessary?
    – dedowsdi
    Commented Jul 19, 2019 at 6:00
  • 1
    So, to be sure, use 9< BTW. If you've shifted too little then the visual selection could be restored with gv. Also, some people use vnoremap < <gv, so it's possible to press < one after another.
    – Matt
    Commented Jul 19, 2019 at 7:30
  • 2
    @Matt, you don't have to vnoremap as < command is dot repeatable. So press < once and continue with . s
    – Maxim Kim
    Commented Jul 19, 2019 at 9:30
  • 1
    @dedowsdi Ah indeed $ is not needed! I was under the impression it was, as I recall blocks being shifted and spaces shuffling, but I just tested and it's not the case. I just updated my answer to point out that's not necessary here. Thanks for checking that out!
    – filbranden
    Commented Jul 19, 2019 at 12:39
6

The answer provided by filbranden shows the sequence in general. Though, it is quite complicated. The most interesting part there is command normal. So, I would simplify and generalize the whole sequence of actions to the following.

  1. Find a column where the characters to be aligned (= in this case) should be placed at on each line. The column in the example is 19.
  2. Select visually the lines to be modified.
  3. Use command :normal f=30i ^[19|dw (including the space in the middle) to apply the alignment for all the selected lines at once.

The command is applied to each line of the visual selection as follows:

  • f= - go to the first character =;
  • 30 ^[ - insert 30 spaces (the number may be increased if needed), ^[ - code of Escape (to insert it to the command line press Ctrl-v and then Esc);
  • 19| - go to the column found at step #1 of the instruction above;
  • dw delete all the spaces till the following word which is = in our case.

The command may be re-applied easily to other part of code/text. Though, it would be better if it could find the column automatically (I have not found a solution for this yet).

3
  • ^[ didn't work with vim/neovim
    – outoftime
    Commented Jan 12, 2023 at 18:08
  • 1
    @outoftime What did not work exactly? Did you insert the Escape code in the way that I mentioned in the answer (using Ctrl-v)?
    – Maxim V.
    Commented Jan 13, 2023 at 9:20
  • Yes, exactly, that was my problem. I have typed those characters instead of adding bare escape sequence by pressing <C-v><Esc> keys on the keyboard.
    – outoftime
    Commented Jan 13, 2023 at 17:43
4

Install vim-easy-align, assume you bind <Plug>(EasyAlign) to ga, execute gaip=, done.

This plugin comes with a lot of predefined rule to handle common align scenarios.

Another way to do this is to use :h ! : !ipcolumn -t

4
  • you mean column not ipcolumn right? (however that does not work on windows) Commented Jul 18, 2019 at 14:45
  • @ChristianBrabandt It's :h ! in normal mode, not :h :!. And yes, it doesn't work on windows.
    – dedowsdi
    Commented Jul 18, 2019 at 23:42
  • @dedowsdi I didn't get the second solution. What is ipcolumn and is this vim's native command? Commented Jul 19, 2019 at 7:03
  • 1
    @KartikChauhan :h ! is a valid normal mode operator, it Filter {motion} text lines through the external program {filter}. In this case, {motion} is ip, {filter} is column -t.
    – dedowsdi
    Commented Jul 19, 2019 at 7:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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