Usability improvements

- Preserve indentation when a line starts with a delimiter
  - Useful for aligning multi-line method chains
- Renamed `margin_{left,right}` to `{left,right}_margin
  - Makes it easier to type in (`l`, `r`)
  - `margin_{left,right}` is still supported
- Margins can be specified as the number of spaces, or as an arbitrary string
This commit is contained in:
Junegunn Choi
2013-08-05 23:41:31 +09:00
parent 20124bc622
commit 2486b9c6df
9 changed files with 223 additions and 49 deletions

View File

@@ -141,6 +141,31 @@ mysql:
```
Formatting multi-line method chaining
-------------------------------------
Try `<Enter>.` or `<Enter>*.` on the following lines.
```ruby
my_object
.method1().chain()
.second_method().call()
.third().call()
.method_4().execute()
```
Notice that the indentation is adjusted to match the shortest one among those of
the lines starting with the delimiter.
```ruby
my_object
.method1() .chain()
.second_method().call()
.third() .call()
.method_4() .execute()
```
Partial alignment in block-visual mode / Negative field index
-------------------------------------------------------------

View File

@@ -127,7 +127,7 @@ Notice that you can't append `\zs` to your regular expression to put delimiters
on the left. It can be done by providing additional options in Vim dictionary
format.
- `:EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'margin_left': '' }`
- `:EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'left_margin': '' }`
Then we get:
@@ -136,21 +136,21 @@ Then we get:
Options keys are fuzzy-matched, so you can write as follows:
- `:EasyAlign * /[:;]\+/ { 'stl': 1, 'ml': '' }`
- `:EasyAlign * /[:;]\+/ { 'stl': 1, 'l': 0 }`
You can even omit spaces between the arguments, so concisely (or cryptically):
- `:EasyAlign*/[:;]\+/{'stl':1,'ml':''}`
- `:EasyAlign*/[:;]\+/{'s':1,'l':0}`
Available options for each alignment are as follows.
| Atrribute | Type | Default |
| ---------------- | ------- | ----------------------- |
| margin_left | string | `' '` |
| margin_right | string | `' '` |
| stick_to_left | boolean | 0 |
| ignore_unmatched | boolean | 1 |
| ignores | array | `['String', 'Comment']` |
| 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.)
@@ -331,14 +331,14 @@ let g:easy_align_delimiters = {
\ '#': { 'pattern': '#\+', 'ignores': ['String'] },
\ ']': {
\ 'pattern': '[\[\]]',
\ 'margin_left': '',
\ 'margin_right': '',
\ 'left_margin': 0,
\ 'right_margin': 0,
\ 'stick_to_left': 0
\ },
\ ')': {
\ 'pattern': '[()]',
\ 'margin_left': '',
\ 'margin_right': '',
\ 'left_margin': 0,
\ 'right_margin': 0,
\ 'stick_to_left': 0
\ }
\ }

View File

@@ -27,23 +27,24 @@ endif
let g:loaded_easy_align = 1
let s:easy_align_delimiters_default = {
\ ' ': { 'pattern': ' ', 'margin_left': '', 'margin_right': '', 'stick_to_left': 0 },
\ ' ': { 'pattern': ' ', 'left_margin': '', 'right_margin': '', 'stick_to_left': 0 },
\ '=': { 'pattern': '===\|<=>\|\(&&\|||\|<<\|>>\)=\|=\~\|=>\|[:+/*!%^=><&|-]\?=[#?]\?',
\ 'margin_left': ' ', 'margin_right': ' ', 'stick_to_left': 0 },
\ ':': { 'pattern': ':', 'margin_left': '', 'margin_right': ' ', 'stick_to_left': 1 },
\ ',': { 'pattern': ',', 'margin_left': '', 'margin_right': ' ', 'stick_to_left': 1 },
\ '|': { 'pattern': '|', 'margin_left': ' ', 'margin_right': ' ', 'stick_to_left': 0 },
\ '.': { 'pattern': '\.', 'margin_left': '', 'margin_right': '', 'stick_to_left': 0 },
\ 'left_margin': ' ', 'right_margin': ' ', 'stick_to_left': 0 },
\ ':': { 'pattern': ':', 'left_margin': '', 'right_margin': ' ', 'stick_to_left': 1 },
\ ',': { 'pattern': ',', 'left_margin': '', 'right_margin': ' ', 'stick_to_left': 1 },
\ '|': { 'pattern': '|', 'left_margin': ' ', 'right_margin': ' ', 'stick_to_left': 0 },
\ '.': { 'pattern': '\.', 'left_margin': '', 'right_margin': '', 'stick_to_left': 0 },
\ '{': { 'pattern': '(\@<!{',
\ 'margin_left': ' ', 'margin_right': ' ', 'stick_to_left': 0 },
\ '}': { 'pattern': '}', 'margin_left': ' ', 'margin_right': '', 'stick_to_left': 0 }
\ 'left_margin': ' ', 'right_margin': ' ', 'stick_to_left': 0 },
\ '}': { 'pattern': '}', 'left_margin': ' ', 'right_margin': '', 'stick_to_left': 0 }
\ }
let s:just = ['', '[R]']
let s:known_options = {
\ 'pattern': 1, 'margin_left': 1, 'margin_right': 1, 'stick_to_left': 0,
\ 'ignores': 3, 'ignore_unmatched': 0
\ 'pattern': [1], '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]
\ }
if exists("*strwidth")
@@ -101,7 +102,7 @@ function! s:fuzzy_lu(key)
return a:key
endif
let regexp = '^' . substitute(a:key, '\(.\)', '\1.*', 'g')
let regexp = '^' . substitute(substitute(a:key, '-', '_', 'g'), '\(.\)', '\1.*', 'g')
let matches = filter(keys(s:known_options), 'v:val =~ regexp')
if empty(matches)
@@ -116,14 +117,18 @@ endfunction
function! s:normalize_options(opts)
let ret = {}
for [k, v] in items(a:opts)
let ret[s:fuzzy_lu(k)] = v
let k = s:fuzzy_lu(k)
" Backward-compatibility
if k == 'margin_left' | let k = 'left_margin' | endif
if k == 'margin_right' | let k = 'right_margin' | endif
let ret[k] = v
endfor
return s:validate_options(ret)
endfunction
function! s:validate_options(opts)
for [k, v] in items(a:opts)
if type(v) != s:known_options[k]
if index(s:known_options[k], type(v)) == -1
call s:exit("Invalid type for option: ". k)
endif
endfor
@@ -135,6 +140,7 @@ function! s:do_align(just, all_tokens, fl, ll, fc, lc, pattern, nth, ml, mr, sti
let max_just_len = 0
let max_delim_len = 0
let max_tokens = 0
let min_indent = -1
let pattern = '\s*\(' .a:pattern. '\)\s' . (a:stick_to_left ? '*' : '\{-}')
" Phase 1
@@ -212,6 +218,10 @@ function! s:do_align(just, all_tokens, fl, ll, fc, lc, pattern, nth, ml, mr, sti
continue
endif
let indent = len(matchstr(tokens[0], '^\s\+'))
if min_indent < 0 || indent < min_indent
let min_indent = indent
endif
let max_just_len = max([s:strwidth(prefix.token), max_just_len])
let max_delim_len = max([s:strwidth(delim), max_delim_len])
let lines[line] = [nth, prefix, token, delim]
@@ -260,8 +270,19 @@ function! s:do_align(just, all_tokens, fl, ll, fc, lc, pattern, nth, ml, mr, sti
let mr = (empty(rest) ||
\ (empty(rest) && stridx(after, a:mr) == 0)) ? '' : a:mr
" Adjust indentation of the lines starting with a delimiter
let lpad = ''
if nth == 0
let ipad = repeat(' ', min_indent - len(strpart(before.token, '^\s\+').ml))
if a:just == 0
let token = ipad . token
else
let lpad = ipad
endif
endif
" Align the token
let aligned = join([token, ml, delim, mr, rpad], '')
let aligned = join([lpad, token, ml, delim, mr, rpad], '')
let tokens[nth] = aligned
" Update the line
@@ -431,13 +452,18 @@ function! easy_align#align(just, expr) range
return
endtry
let ml = get(dict, 'left_margin', ' ')
let mr = get(dict, 'right_margin', ' ')
if type(ml) == 0 | let ml = repeat(' ', ml) | endif
if type(mr) == 0 | let mr = repeat(' ', mr) | endif
call s:do_align(just, {}, a:firstline, a:lastline,
\ visualmode() == '' ? min([col("'<"), col("'>")]) : 1,
\ visualmode() == '' ? max([col("'<"), col("'>")]) : 0,
\ get(dict, 'pattern', ch),
\ nth,
\ get(dict, 'margin_left', ' '),
\ get(dict, 'margin_right', ' '),
\ ml,
\ mr,
\ get(dict, 'stick_to_left', 0),
\ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 1)),
\ get(dict, 'ignores', s:ignored_syntax()),

View File

@@ -95,7 +95,7 @@ try these commands:
Notice that you can't append `\zs` to your regular expression to put delimiters
on the left. It can be done by providing additional options.
- :EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'margin_left': '' }
- :EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'left_margin': '' }
Then we get:
@@ -104,21 +104,21 @@ Then we get:
Options keys are fuzzy-matched, so you can write as follows:
- :EasyAlign * /[:;]\+/ { 'stl': 1, 'ml': '' }
- :EasyAlign * /[:;]\+/ { 'stl': 1, 'l': '' }
You can even omit spaces between the arguments, so concisely (or cryptically):
- :EasyAlign*/[:;]\+/{'stl':1,'ml':''}
- :EasyAlign*/[:;]\+/{'s':1,'l':''}
Available options for each alignment are as follows.
| Atrribute | Type | Default |
| ---------------- | ------- | ----------------------- |
| margin_left | string | `' '` |
| margin_right | string | `' '` |
| stick_to_left | boolean | 0 |
| ignore_unmatched | boolean | 1 |
| ignores | array | `['String', 'Comment']` |
| 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']` |
Partial alignment in blockwise-visual mode
@@ -231,14 +231,14 @@ Extending alignment rules *g:easy_align_delimiters*
\ '#': { 'pattern': '#\+' },
\ ']': {
\ 'pattern': '[\[\]]',
\ 'margin_left': '',
\ 'margin_right': '',
\ 'left_margin': 0,
\ 'right_margin': 0,
\ 'stick_to_left': 0
\ },
\ ')': {
\ 'pattern': '[()]',
\ 'margin_left': '',
\ 'margin_right': '',
\ 'left_margin': 0,
\ 'right_margin': 0,
\ 'stick_to_left': 0
\ }
\ }

View File

@@ -257,3 +257,102 @@ aa >= bb
aaaaa /* bbbbb */ == ccccc /* != eeeee = */ === fffff
```
my_object
.method1 .chain
.second_method.call
.third .call
.method_4 .execute
my_object
.method1 . chain
.second_method. call
.third . call
.method_4 .execute
my_object
. method1.chain
.second_method.call
. third.call
. method_4.execute
my_object
. method1.chain
.second_method.call
. third.call
. method_4.execute
my_object
. method1. chain
.second_method. call
. third. call
. method_4.execute
my_object
.method1 .chain
.second_method.call
.third .call
.method_4 .execute
my_object
.method1.chain
.second_method.call
.third.call
.method_4.execute
my_object .
method1 .chain.
second_method.call.
third .call.
method_4 .execute
| Option | Type | Default | Description |
| -- | -- | -- | -- |
| threads | Fixnum | 1 | number of threads in the thread pool |
| queues | Fixnum | 1 | number of concurrent queues |
| queue_size | Fixnum | 1000 | size of each queue |
| interval | Numeric | 0 | dispatcher interval for batch processing |
| batch | Boolean | false | enables batch processing mode |
| batch_size | Fixnum | nil | number of maximum items to be assigned at once |
| logger | Logger | nil | logger instance for debug logs |
| Option | Type | Default | Description |
| -- | -- | -- | -- |
| threads | Fixnum | 1 | number of threads in the thread pool |
| queues | Fixnum | 1 | number of concurrent queues |
| queue_size | Fixnum | 1000 | size of each queue |
| interval | Numeric | 0 | dispatcher interval for batch processing |
| batch | Boolean | false | enables batch processing mode |
| batch_size | Fixnum | nil | number of maximum items to be assigned at once |
| logger | Logger | nil | logger instance for debug logs |
| Option | Type | Default | Description |
| -- | -- | -- | -- |
| threads | Fixnum | 1 | number of threads in the thread pool |
| queues | Fixnum | 1 | number of concurrent queues |
| queue_size | Fixnum | 1000 | size of each queue |
| interval | Numeric | 0 | dispatcher interval for batch processing |
| batch | Boolean | false | enables batch processing mode |
| batch_size | Fixnum | nil | number of maximum items to be assigned at once |
| logger | Logger | nil | logger instance for debug logs |
|Option |Type |Default |Description |
|-- |-- |-- |-- |
|threads |Fixnum |1 |number of threads in the thread pool |
|queues |Fixnum |1 |number of concurrent queues |
|queue_size |Fixnum |1000 |size of each queue |
|interval |Numeric |0 |dispatcher interval for batch processing |
|batch |Boolean |false |enables batch processing mode |
|batch_size |Fixnum |nil |number of maximum items to be assigned at once |
|logger |Logger |nil |logger instance for debug logs |
| Option <| Type <| Default<| Description <|
| -- <| -- <| -- <| -- <|
| threads <| Fixnum <| 1 <| number of threads in the thread pool <|
| queues <| Fixnum <| 1 <| number of concurrent queues <|
| queue_size<| Fixnum <| 1000 <| size of each queue <|
| interval <| Numeric<| 0 <| dispatcher interval for batch processing <|
| batch <| Boolean<| false <| enables batch processing mode <|
| batch_size<| Fixnum <| nil <| number of maximum items to be assigned at once<|
| logger <| Logger <| nil <| logger instance for debug logs <|

View File

@@ -84,3 +84,26 @@ aa >= bb
aaaaa /* bbbbb */ == ccccc /* != eeeee = */ === fffff
```
my_object
.method1.chain
.second_method.call
.third.call
.method_4.execute
my_object.
method1.chain.
second_method.call.
third.call.
method_4.execute
| Option| Type | Default | Description |
|--|--|--|--|
| threads | Fixnum | 1 | number of threads in the thread pool |
|queues |Fixnum | 1 | number of concurrent queues |
|queue_size | Fixnum | 1000 | size of each queue |
| interval | Numeric | 0 | dispatcher interval for batch processing |
|batch | Boolean | false | enables batch processing mode |
|batch_size | Fixnum | nil | number of maximum items to be assigned at once |
|logger | Logger | nil | logger instance for debug logs |

View File

@@ -1 +1 @@
4Gvipjyvip
4Gvipjyvip

View File

@@ -1 +1 @@
4Gvipjyvip:EasyAlign:
4Gvipjyvip:EasyAlign:

View File

@@ -1,4 +1,5 @@
source include.vim
e!
execute 'source '. expand('%:p:h') . '/include.vim'
while line('.') < line('$')
normal 30j
@@ -6,7 +7,7 @@ while line('.') < line('$')
endwhile
normal gg
let @b=system('cat '. expand('%:r') . '.script')
let @a='@b:vert diffsplit ' . expand('%:r') . '.expected
let @b=system('cat '. expand('%:p:r') . '.script')
let @a='@b:vert diffsplit ' . expand('%:p:r') . '.expected
'
" Syntax highlighting doesn't work