Indent a block of code on the basis of a single character

微笑、不失礼 提交于 2020-01-02 08:56:18

问题


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 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.


回答1:


Using GNU tools

 :%!column -t -s= -o=      

  % ............. current file
  ! ............. use external command
 -t ............. use tabs
 -s ............. input separator
 -o ............. output separator

Instead of whole file it can be a range of lines 1,5 or you can select a paragraph with vip

I ended up creating a function called AlignText that uses column command to solve this issue:

" Align text by a chosen char
" https://stackoverflow.com/questions/57093175/
" https://vi.stackexchange.com/a/2412/7339
if !exists('*AlignText')
    function! AlignText(param) range
        execute a:firstline . ',' . a:lastline . '!column -t -s' . a:param . ' -o' . a:param
    endfunction
endif
command! -range=% -nargs=1 Align <line1>,<line2>call AlignText(<q-args>)
" :Align =
" :8,$ Align =

If you wnat to test this function before put it into your vimrc, copy the code to your clipboard and then try this:

:@+

Now you can use something like this:

:15,22Align /
:Align ,

I by any change you want to use the function call instead of the command one, don't forget to pass the range and put the argument between quotes.

A slitly different version that accepts nor arguments and uses just "column -t"

" https://stackoverflow.com/questions/57093175/
" https://vi.stackexchange.com/a/2412/7339
function! AlignText(...) range
    if a:0 < 1
        execute a:firstline . ',' . a:lastline . '!column -t'
    else
        execute a:firstline . ',' . a:lastline . '!column -t -s' . a:1 . ' -o' . a:1
    endif
endfunction
command! -range=% -nargs=? Align <line1>,<line2>call AlignText(<f-args>)



回答2:


there are plugins can do this kind of alignment. E.g.

Align or easy-align. I have been using Align for a long time, for your requirement, I just select those lines and do <leader>t=

https://github.com/vim-scripts/Align

https://github.com/junegunn/vim-easy-align

You can of course code by yourself, you find out the max length before the =, then you know how many spaces you should insert between partBefore and =. (the diff) on each line.




回答3:


(NOTE: Originally answered at the Vi and Vim Stack Exchange.)

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.



来源:https://stackoverflow.com/questions/57093175/indent-a-block-of-code-on-the-basis-of-a-single-character

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!