diff --git a/README.md b/README.md index a03d06e..3e17432 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,14 @@ or [Pathogen](https://github.com/tpope/vim-pathogen). ### With Vundle +Add the following line to your .vimrc, + ```vim Bundle 'junegunn/vim-easy-align' ``` +then execute `:BundleInstall` command. + Usage ----- @@ -55,7 +59,7 @@ your `.vimrc`. vnoremap :EasyAlign ``` -With the mapping, you can align selected lines of text with a few keystrokes. +With the mapping, you can align selected lines of text with only a few keystrokes. 1. `` key to start interactive EasyAlign command 1. Optional Enter keys to toggle right-justification mode @@ -143,17 +147,7 @@ You can even omit spaces between the arguments, so concisely (or cryptically): - `:EasyAlign*/[:;]\+/{'s':1,'l':0}` -Available options are as follows. - -| Atrribute | Type | Default | -| ---------------- | ---------------- | ----------------------- | -| left_margin | number or string | 0 | -| right_margin | number or string | 0 | -| stick_to_left | boolean | 0 | -| ignore_unmatched | boolean | 1 | -| ignores | array | `['String', 'Comment']` | - -(The last two options will be described shortly in the following sections.) +Available options will be shown later in the document. ### Partial alignment in blockwise-visual mode @@ -182,14 +176,35 @@ my_hash = { :a => 1, However, in this case, we don't really need blockwise visual mode since the same can be easily done using the negative field number: `-=` -Global options --------------- +Alignment options +----------------- -| Option | Type | Default | Description | -| ----------------------------- | ---------- | ----------------------- | -------------------------------------------------- | -| g:easy_align_ignores | list | `['String', 'Comment']` | Ignore delimiters in these syntax highlight groups | -| g:easy_align_ignore_unmatched | boolean | `1` | Ignore lines without matching delimiter | -| g:easy_align_delimiters | dictionary | `{}` | Extend or override alignment rules | +Options values can be 1) specified as global variables, 2) set on each alignment +rule in `g:easy_align_delimiters`, 3) or given to every `:EasyAlign` command. + +Command-line options have the highest precedence, and global variables have the +lowest precedence. + +### List of options + +| Option | Type | Default | Description | +| ------------------ | ----------------- | ----------------------- | ------------------------------------------------------- | +| `left_margin` | number | 0 | Number of spaces to attach before delimiter | +| `left_margin` | string | `''` | String to attach before delimiter | +| `right_margin` | number | 0 | Number of spaces to attach after delimiter | +| `right_margin` | string | `''` | String to attach after delimiter | +| `stick_to_left` | boolean | 0 | Whether to position delimiter on the left-side | +| `ignore_unmatched` | boolean | 1 | Whether to ignore lines without matching delimiter | +| `ignores` | array | `['String', 'Comment']` | Delimiters in these syntax highlight groups are ignored | +| `delimiter_align` | string | `r` | Determines how to align delimiters of different lengths | + +Some of the options can be specified using corresponding global variables. + +| Option | Global variable | +| ------------------ | ------------------------------- | +| `ignore_unmatched` | `g:easy_align_ignore_unmatched` | +| `ignores` | `g:easy_align_ignores` | +| `delimiter_align` | `g:easy_align_delimiter_align` | ### Ignoring delimiters in comments or strings @@ -232,21 +247,13 @@ becomes as follows on `:` (or `:EasyAlign:`) Naturally, this feature only works when syntax highlighting is enabled. -You can change the default rule by either defining global `g:easy_align_ignores` -array, +You can change the default rule by using one of these 3 methods. -```vim -" Ignore nothing! -let g:easy_align_ignores = [] -``` +1. Define global `g:easy_align_ignores` list +2. Define a custom alignment rule in `g:easy_align_delimiters` with `ignores` option +3. Provide `ignores` option to `:EasyAlign` command. e.g. `:EasyAlign:{'is':[]}` -or providing `ignores` option directly to `:EasyAlign` command - -```vim -:EasyAlign:{'is':[]} -``` - -Then you get, +For example if you set `ignores` option to be an empty list, you get ```ruby { @@ -290,20 +297,12 @@ this is usually what we want. } ``` -However, this default behavior is also configurable. +However, this default behavior is also configurable by using one of these 3 +methods. -One way is to set the global `g:easy_align_ignore_unmatched` variable to 0. - -```vim -let g:easy_align_ignore_unmatched = 0 -``` - -Or in non-interactive mode, you can provide `ignore_unmatched` option to -`:EasyAlign` command as follows. - -```vim -:EasyAlign:{'iu':0} -``` +1. Set the global `g:easy_align_ignore_unmatched` variable to 0 +2. Define a custom alignment rule with `ignore_unmatched` option set to 0 +3. Provide `ignore_unmatched` option to `:EasyAlign` command. e.g. `:EasyAlign:{'iu':0}` Then we get, @@ -317,6 +316,42 @@ Then we get, } ``` +### Aligning delimiters of different lengths + +Global `g:easy_align_delimiter_align` option and rule-wise/command-wise +`delimiter_align` option determines how matched delimiters of different lengths +are aligned. + +```ruby +apple = 1 +banana += apple +cake ||= banana +``` + +By default, delimiters are right-aligned as follows. + +```ruby +apple = 1 +banana += apple +cake ||= banana +``` + +However, with `:EasyAlign={'da':l}`, delimiters are left-aligned. + +```ruby +apple = 1 +banana += apple +cake ||= banana +``` + +And on `:EasyAlign={'da':c}`, center-aligned. + +```ruby +apple = 1 +banana += apple +cake ||= banana +``` + ### Extending alignment rules Although the default rules should cover the most of the use cases, @@ -328,7 +363,7 @@ you can extend the rules by setting a dictionary named `g:easy_align_delimiters` let g:easy_align_delimiters = { \ '>': { 'pattern': '>>\|=>\|>' }, \ '/': { 'pattern': '//\+\|/\*\|\*/', 'ignores': ['String'] }, -\ '#': { 'pattern': '#\+', 'ignores': ['String'] }, +\ '#': { 'pattern': '#\+', 'ignores': ['String'], 'delimiter_align': 'l' }, \ ']': { \ 'pattern': '[\[\]]', \ 'left_margin': 0, diff --git a/autoload/easy_align.vim b/autoload/easy_align.vim index 561599d..2b77fc8 100644 --- a/autoload/easy_align.vim +++ b/autoload/easy_align.vim @@ -44,7 +44,7 @@ let s:just = ['', '[R]'] let s:known_options = { \ 'margin_left': [0, 1], 'margin_right': [0, 1], 'stick_to_left': [0], \ 'left_margin': [0, 1], 'right_margin': [0, 1], -\ 'ignores': [3], 'ignore_unmatched': [0] +\ 'ignores': [3], 'ignore_unmatched': [0], 'delimiter_align': [1] \ } if exists("*strwidth") @@ -200,7 +200,7 @@ function! s:split_line(line, fc, lc, pattern, stick_to_left, ignore_unmatched, i return [tokens, delims] endfunction -function! s:do_align(just, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth, ml, mr, stick_to_left, ignore_unmatched, ignores, recursive) +function! s:do_align(just, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth, ml, mr, da, stick_to_left, ignore_unmatched, ignores, recursive) let lines = {} let max_just_len = 0 let max_delim_len = 0 @@ -288,11 +288,16 @@ function! s:do_align(just, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth, let tokens[nth] = token " Pad the delimiter - let dpad = repeat(' ', max_delim_len - s:strwidth(delim)) - if a:stick_to_left - let rpad = rpad . dpad + let dpadl = max_delim_len - s:strwidth(delim) + if a:da == 'l' + let [dl, dr] = ['', repeat(' ', dpadl)] + elseif a:da == 'c' + let dl = repeat(' ', dpadl / 2) + let dr = repeat(' ', dpadl - dpadl / 2) + elseif a:da == 'r' + let [dl, dr] = [repeat(' ', dpadl), ''] else - let delim = dpad . delim + call s:exit('Invalid delimiter_align: ' . a:da) endif " Before and after the range (for blockwise visual mode) @@ -318,7 +323,7 @@ function! s:do_align(just, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth, endif " Align the token - let aligned = join([lpad, token, ml, delim, mr, rpad], '') + let aligned = join([lpad, token, ml, dl, delim, dr, mr, rpad], '') let tokens[nth] = aligned " Update the line @@ -329,7 +334,7 @@ function! s:do_align(just, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth, if a:recursive && a:nth < max_tokens let just = a:recursive == 2 ? !a:just : a:just call s:do_align(just, a:all_tokens, a:all_delims, a:fl, a:ll, a:fc, a:lc, a:pattern, - \ a:nth + 1, a:ml, a:mr, a:stick_to_left, a:ignore_unmatched, + \ a:nth + 1, a:ml, a:mr, a:da, a:stick_to_left, a:ignore_unmatched, \ a:ignores, a:recursive) endif endfunction @@ -389,6 +394,7 @@ function! s:parse_args(args) let cand = strpart(args, midx) try + let [l, r, c] = ['l', 'r', 'c'] let o = eval(cand) if type(o) == 4 let option = o @@ -504,6 +510,7 @@ function! easy_align#align(just, expr) range \ nth, \ ml, \ mr, + \ get(dict, 'delimiter_align', get(g:, 'easy_align_delimiter_align', 'r')), \ get(dict, 'stick_to_left', 0), \ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 1)), \ get(dict, 'ignores', s:ignored_syntax()), diff --git a/doc/easy_align.txt b/doc/easy_align.txt index b4152ad..fee72ac 100644 --- a/doc/easy_align.txt +++ b/doc/easy_align.txt @@ -1,3 +1,5 @@ +*easy_align.txt* A simple, easy-to-use Vim alignment plugin + vim-easy-align *vim-easy-align* *easy-align* ========================================================================= @@ -117,6 +119,7 @@ Available options are as follows. | left_margin | number or string | 0 | | right_margin | number or string | 0 | | stick_to_left | boolean | 0 | +| delimiter_align | string | 'r' | | ignore_unmatched | boolean | 1 | | ignores | array | `['String', 'Comment']` | @@ -235,6 +238,36 @@ Then we get, } + +Aligning delimiters of different lengths *g:easy_align_delimiter_align* +------------------------------------------------------------------------- + +Global `g:easy_align_delimiter_align` option and rule-wise/command-wise +`delimiter_align` option determines how matched delimiters of different +lengths are aligned. + + apple = 1 + banana += apple + cake ||= banana + +By default, delimiters are right-aligned as follows. + + apple = 1 + banana += apple + cake ||= banana + +However, with `:EasyAlign={'da':l}`, delimiters are left-aligned. + + apple = 1 + banana += apple + cake ||= banana + +And on `:EasyAlign={'da':c}`, center-aligned. + + apple = 1 + banana += apple + cake ||= banana + Extending alignment rules *g:easy_align_delimiters* ------------------------------------------------------------------------- diff --git a/test/basic.expected b/test/basic.expected index cedc697..461b25a 100644 --- a/test/basic.expected +++ b/test/basic.expected @@ -379,3 +379,123 @@ George Harrison 1943 Ringo Starr 1940 Pete Best 1941 +... - . ----- +.. -- .. ---- +. --- ... --- + ---- .... -- +. --- ..... - +.. -- ...... +... - ..... - + +... - . ----- +.. -- .. ---- +. --- ... --- + ---- .... -- +. --- ..... - +.. -- ...... +... - ..... - + +... - . ----- +.. -- .. ---- +. --- ... --- + ---- .... -- +. --- ..... - +.. -- ...... +... - ..... - + +... - . ----- +.. -- .. ---- +. --- ... --- + ---- .... -- +. --- ..... - +.. -- ...... +... - ..... - + +... - .----- +.. -- ..---- +. --- ...--- + ---- ....-- +. --- .....- +.. -- ...... +... - .....- + +... - . ----- +.. -- .. ---- +. --- ... --- + ---- .... -- +. --- ..... - +.. -- ...... +... - ..... - + +... - .----- +.. -- ..---- +. --- ...--- + ---- ....-- +. --- .....- +.. -- ...... +... - .....- + +... - .----- +.. -- ..---- +. --- ...--- + ---- ....-- +. --- .....- +.. -- ...... +... - .....- + +...-.----- +..--..---- +.---...--- +----....-- +.---.....- +..--...... +...-.....- + +... - . ----- +.. -- .. ---- +. --- ... --- + ---- .... -- +. --- ..... - +.. -- ...... +... - ..... - + +... - .----- +.. -- ..---- +. --- ...--- + ---- ....-- +. --- .....- +.. -- ...... +... - .....- + +... - . ----- +.. -- .. ---- +. --- ... --- + ---- .... -- +. --- ..... - +.. -- ...... +... - ..... - + +... - . ----- +.. -- .. ---- +. --- ... --- + ---- .... -- +. --- ..... - +.. -- ...... +... - ..... - + +...-. ----- +..--.. ---- +.---... --- +----.... -- +.---..... - +..--...... +...-..... - + +... - .----- +.. -- ..---- +. --- ...--- + ---- ....-- +. --- .....- +.. -- ...... +... - .....- + diff --git a/test/basic.md b/test/basic.md index 94da93c..4a48d08 100644 --- a/test/basic.md +++ b/test/basic.md @@ -122,3 +122,11 @@ George Harrison 1943 Ringo Starr 1940 Pete Best 1941 +...-.----- +..--..---- +.---...--- +----....-- +.---.....- +..--...... +...-.....- + diff --git a/test/basic.script b/test/basic.script index 59cfda3..fbb3425 100644 --- a/test/basic.script +++ b/test/basic.script @@ -1 +1 @@ -4Gvipjyvip Pvip 2 Pvip * Pvip Pvip 2 Pvip * Pvip ** Pvip - Pvip -2 Pvip -1 Pvip ** 60zzvipjyvip *|Pvip *|Pvip **|80zzvip **|gv 3|vip *|90zzvip *,100zzvipjyvip =Pvip *=Pvip **=Pvip =vip 2=198Gvipjyvip =Pvip -=Pf:jj3E =209Gvip - 214zzvipjyvip #P:let g:easy_align_delimiters = { '#': {'pattern': '#\+', 'ignores': ['String'] } } vip #227zzvip :239zzvip *=vipjyP:let g:easy_align_ignores = [] vip *=:unlet g:easy_align_delimiters :unlet g:easy_align_ignores 4Gvipy4GP7Gojkkvip:EasyAlign /1/{'ml':'{{', 'mr-r':'}}'} vipjyPvip:EasyAlign */../ 263zzvipjygv .Pvip *.Pvip * .Pvip .vip 2.Pvip **.Pvip **.Pvip -.G303zzvip .310zzvipjygv *|Pvip *|Pvip |gv -|gv **|gv *|gv **|jji jjjhi vip ** |339Gpvip:EasyAlign*|{'ml': 5, 'mrr': 0 } 349Gpvip:EasyAlign*/|/{'ml':'<', 'mrr': 4} 362G:let g:easy_align_delimiters = { 'd': { 'pattern': '\s\+\(\S\+\s*[;=]\)\@=', 'left_margin': 0, 'right_margin': 0 } } vip dgv =236GvipjyPvip :377Gvip gv 2 +4Gvipjyvip Pvip 2 Pvip * Pvip Pvip 2 Pvip * Pvip ** Pvip - Pvip -2 Pvip -1 Pvip ** 60zzvipjyvip *|Pvip *|Pvip **|80zzvip **|gv 3|vip *|90zzvip *,100zzvipjyvip =Pvip *=Pvip **=Pvip =vip 2=198Gvipjyvip =Pvip -=Pf:jj3E =209Gvip - 214zzvipjyvip #P:let g:easy_align_delimiters = { '#': {'pattern': '#\+', 'ignores': ['String'] } } vip #227zzvip :239zzvip *=vipjyP:let g:easy_align_ignores = [] vip *=:unlet g:easy_align_delimiters :unlet g:easy_align_ignores 4Gvipy4GP7Gojkkvip:EasyAlign /1/{'ml':'{{', 'mr-r':'}}'} vipjyPvip:EasyAlign */../ 263zzvipjygv .Pvip *.Pvip * .Pvip .vip 2.Pvip **.Pvip **.Pvip -.G303zzvip .310zzvipjygv *|Pvip *|Pvip |gv -|gv **|gv *|gv **|jji jjjhi vip ** |339Gpvip:EasyAlign*|{'ml': 5, 'mrr': 0 } 349Gpvip:EasyAlign*/|/{'ml':'<', 'mrr': 4} 362G:let g:easy_align_delimiters = { 'd': { 'pattern': '\s\+\(\S\+\s*[;=]\)\@=', 'left_margin': 0, 'right_margin': 0 } } vip dgv =236GvipjyPvip :377Gvip gv 2 382Gvipjyvip:EasyAlign/-\+/ Pvip:EasyAlign2/-\+/ Pvip:EasyAlign*/-\+/ Pvip:EasyAlign*/-\+/{'da': l} Pvip:EasyAlign/-\+/{'da': c} Pvip:EasyAlign*/-\+/{'delimiter_align':'c'} Pvip:EasyAlign*/-\+/{'da': 'x'} 381Gpvip:EasyAlign/-\+/{'da':r} :let g:easy_align_delimiter_align = 'l' Pvip:EasyAlign/-\+/ Pvip:EasyAlign*/-\+/ :unlet g:easy_align_delimiter_align :let g:easy_align_delimiters['_'] = { 'pattern': '-\+', 'delimiter_align': 'c' } Pvip _Pvip *-vip *_Pvip:EasyAlign*_{'da':l} Pvip:EasyAlign*_ Pvip:EasyAlign*_{'da': 'r'}