adds support for right and center justification

This commit is contained in:
Junegunn Choi
2013-05-04 00:58:58 +09:00
parent 7dc67e5392
commit 0020db37ae
4 changed files with 206 additions and 75 deletions

View File

@@ -1,15 +1,17 @@
vim-easy-align vim-easy-align
============== ==============
Yet another Vim alignment plugin without too much ambition. A simple, easy-to-use Vim alignment plugin.
This plugin clearly has less features than the other pre-existing ones with the similar goals, Demo
but it is simpler, easier to use, and just good enough for the most of the cases. ----
[Screencast](https://vimeo.com/63506219)
Usage Usage
----- -----
Vim-easy-align defines `:EasyAlign` command in the visual mode. _vim-easy-align_ defines interactive `:EasyAlign` command in the visual mode.
For convenience, it is advised that you define a mapping for triggering it in your `.vimrc`. For convenience, it is advised that you define a mapping for triggering it in your `.vimrc`.
```vim ```vim
@@ -18,7 +20,8 @@ vnoremap <silent> <Enter> :EasyAlign<cr>
With the mapping, you can align selected lines with a few keystrokes. With the mapping, you can align selected lines with a few keystrokes.
1. `<Enter>` key to start EasyAlign command 1. `<Enter>` key to start interactive EasyAlign command
1. Optional Enter keys to switch justficiation mode (default: left)
1. Optional field number (default: 1) 1. Optional field number (default: 1)
- `1` Alignment around 1st delimiter - `1` Alignment around 1st delimiter
- `2` Alignment around 2nd delimiter - `2` Alignment around 2nd delimiter
@@ -40,11 +43,12 @@ Alignment rules for the following delimiters have been crafted to meet the most
### Example command sequences ### Example command sequences
| With visual map | Description | Equivalent command | | With visual map | Description | Equivalent command |
| ----------------- | ------------------------------------------------- | -------------------- | | ----------------- | ------------------------------------------------- | ----------------------- |
| `<Enter>=` | Alignment around 1st equals sign (and the likes) | `:'<,'>EasyAlign=` | | `<Enter>=` | Alignment around 1st equals signs (and the likes) | `:'<,'>EasyAlign=` |
| `<Enter>2=` | Alignment around 2nd equals sign (and the likes) | `:'<,'>EasyAlign2=` | | `<Enter>2=` | Alignment around 2nd equals signs (and the likes) | `:'<,'>EasyAlign2=` |
| `<Enter>3=` | Alignment around 3rd equals sign (and the likes) | `:'<,'>EasyAlign3=` | | `<Enter>3=` | Alignment around 3rd equals signs (and the likes) | `:'<,'>EasyAlign3=` |
| `<Enter>*=` | Alignment around all equals signs (and the likes) | `:'<,'>EasyAlign*=` | | `<Enter>*=` | Alignment around all equals signs (and the likes) | `:'<,'>EasyAlign*=` |
| `<Enter><Enter>=` | Right-justified alignment around 1st equals signs | `:'<,'>EasyAlignRight=` |
| `<Enter><space>` | Alignment around 1st space | `:'<,'>EasyAlign\ ` | | `<Enter><space>` | Alignment around 1st space | `:'<,'>EasyAlign\ ` |
| `<Enter>2<space>` | Alignment around 2nd space | `:'<,'>EasyAlign2\ ` | | `<Enter>2<space>` | Alignment around 2nd space | `:'<,'>EasyAlign2\ ` |
| `<Enter>:` | Alignment around 1st colon | `:'<,'>EasyAlign:` | | `<Enter>:` | Alignment around 1st colon | `:'<,'>EasyAlign:` |
@@ -90,10 +94,57 @@ let g:easy_align_delimiters = {
\ } \ }
``` ```
Demo Handling unmatched lines
---- ------------------------
[Screencast](https://vimeo.com/63506219) EasyAlign by default ignores lines without the matching delimiters.
This is to ignore interleaved comments commonly found in code.
For example, when aligning the following code block,
```
{
# Quantity of apples
apple: 1,
# Quantity of bananas
bananas: 2,
# Quantity of grapefruits
grapefruits: 3
}
```
we don't want to the comment lines to affect the alignment,
so this is usually what we want.
```
{
# Quantity of apples
apple: 1,
# Quantity of bananas
bananas: 2,
# Quantity of grapefruits
grapefruits: 3
}
```
However, this default behavior is configurable.
```vim
let g:easy_align_ignore_unmatched = 0
```
Then we get,
```
{
# Quantity of apples
apple: 1,
# Quantity of bananas
bananas: 2,
# Quantity of grapefruits
grapefruits: 3
}
```
Author Author
------ ------

View File

@@ -2,7 +2,8 @@ if exists("g:easy_align_loaded")
finish finish
endif endif
let g:easy_align_loaded = 1 let g:easy_align_loaded = 1
let g:easy_align_delimiters_merged = {
let s:easy_align_delimiters_default = {
\ ' ': { 'pattern': ' ', 'margin_left': '', 'margin_right': '', 'stick_to_left': 0 }, \ ' ': { 'pattern': ' ', 'margin_left': '', 'margin_right': '', 'stick_to_left': 0 },
\ '=': { 'pattern': '<=>\|\(&&\|||\|<<\|>>\)=\|=\~\|=>\|[:+/*!%^=><&|-]\?=', \ '=': { 'pattern': '<=>\|\(&&\|||\|<<\|>>\)=\|=\~\|=>\|[:+/*!%^=><&|-]\?=',
\ 'margin_left': ' ', 'margin_right': ' ', 'stick_to_left': 0 }, \ 'margin_left': ' ', 'margin_right': ' ', 'stick_to_left': 0 },
@@ -12,16 +13,13 @@ let g:easy_align_delimiters_merged = {
\ '.': { 'pattern': '\.', 'margin_left': '', 'margin_right': '', 'stick_to_left': 0 } \ '.': { 'pattern': '\.', 'margin_left': '', 'margin_right': '', 'stick_to_left': 0 }
\ } \ }
if !exists("g:easy_align_delimiters") let s:just = ['L', 'R', 'C']
let g:easy_align_delimiters = {}
endif
call extend(g:easy_align_delimiters_merged, g:easy_align_delimiters) function! s:do_align(just, fl, ll, fc, lc, pattern, nth, ml, mr, stick_to_left, recursive)
function! s:do_align(fl, ll, fc, lc, pattern, nth, ml, mr, stick_to_left, recursive)
let lines = {} let lines = {}
let just_len = 0 let max_token_len = 0
let max_delim_len = 0 let max_delim_len = 0
let max_prefix_len = 0
let max_tokens = 0 let max_tokens = 0
let pattern = '\s*\(' .a:pattern. '\)\s*' let pattern = '\s*\(' .a:pattern. '\)\s*'
for line in range(a:fl, a:ll) for line in range(a:fl, a:ll)
@@ -41,27 +39,47 @@ function! s:do_align(fl, ll, fc, lc, pattern, nth, ml, mr, stick_to_left, recurs
endif endif
let last = tokens[nth - 1] let last = tokens[nth - 1]
let prefix = (nth > 1 ? join(tokens[0 : nth - 2], '') : '') . substitute(last, pattern.'$', '', '') let prefix = (nth > 1 ? join(tokens[0 : nth - 2], '') : '')
let token = substitute(last, pattern.'$', '', '')
let suffix = join(tokens[nth : -1], '') let suffix = join(tokens[nth : -1], '')
if match(last, pattern.'$') == -1 if match(last, pattern.'$') == -1
if !exists("g:easy_align_ignore_unmatched") || g:easy_align_ignore_unmatched
continue continue
else
let delim = ''
endif
else
let delim = matchlist(last, pattern)[1]
endif endif
let delim = matchlist(tokens[nth - 1], pattern)[1] let max_token_len = max([len(token), max_token_len])
let just_len = max([len(prefix), just_len]) let max_prefix_len = max([len(prefix), max_prefix_len])
let max_delim_len = max([len(delim), max_delim_len]) let max_delim_len = max([len(delim), max_delim_len])
let lines[line] = [prefix, suffix, delim] let lines[line] = [prefix, token, delim, suffix]
endfor endfor
for [line, tokens] in items(lines) for [line, tokens] in items(lines)
let [prefix, suffix, delim] = tokens let [prefix, token, delim, suffix] = tokens
let pad = repeat(' ', just_len - len(prefix)) let pad = repeat(' ', max_token_len - len(token) + max_prefix_len - len(prefix))
if a:just == 0
if a:stick_to_left if a:stick_to_left
let suffix = pad . suffix let suffix = pad . suffix
else else
let prefix = prefix . pad let token = token . pad
endif
elseif a:just == 1
let token = pad . token
else
let p1 = strpart(pad, 0, len(pad) / 2)
let p2 = strpart(pad, len(pad) / 2)
if a:stick_to_left
let token = p1 . token
let suffix = p2 . suffix
else
let token = p1. token .p2
endif
endif endif
let delim = repeat(' ', max_delim_len - len(delim)). delim let delim = repeat(' ', max_delim_len - len(delim)). delim
@@ -69,45 +87,51 @@ function! s:do_align(fl, ll, fc, lc, pattern, nth, ml, mr, stick_to_left, recurs
let before = strpart(cline, 0, a:fc - 1) let before = strpart(cline, 0, a:fc - 1)
let after = a:lc ? strpart(cline, a:lc) : '' let after = a:lc ? strpart(cline, a:lc) : ''
let ml = empty(prefix) ? '' : a:ml let ml = empty(prefix . token) ? '' : a:ml
let mr = (empty(suffix . after) || (empty(suffix) && stridx(after, a:mr) == 0)) ? '' : a:mr let mr = (empty(suffix . after) || (empty(suffix) && stridx(after, a:mr) == 0)) ? '' : a:mr
let aligned = join([prefix, ml, delim, mr, suffix], '') let aligned = join([prefix, token, ml, delim, mr, suffix], '')
let aligned = empty(after) ? substitute(aligned, '\s*$', '', '') : aligned let aligned = empty(after) ? substitute(aligned, '\s*$', '', '') : aligned
call setline(line, before.aligned.after) call setline(line, before.aligned.after)
endfor endfor
if a:recursive && a:nth < max_tokens if a:recursive && a:nth < max_tokens
call s:do_align(a:fl, a:ll, a:fc, a:lc, a:pattern, a:nth + 1, a:ml, a:mr, a:stick_to_left, a:recursive) call s:do_align(a:just, a:fl, a:ll, a:fc, a:lc, a:pattern, a:nth + 1, a:ml, a:mr, a:stick_to_left, a:recursive)
endif endif
endfunction endfunction
function! easy_align#align(...) range function! s:echon(l, n, d)
echon "\rEasyAlign[". s:just[a:l] ."] (" .a:n.a:d. ")"
endfunction
function! easy_align#align(just, ...) range
let just = a:just
let recursive = 0 let recursive = 0
let n = '' let n = ''
let ch = '' let ch = ''
if a:0 == 0 if a:0 == 0
echon "\reasy-align ()"
while 1 while 1
call s:echon(just, n, '')
let c = getchar() let c = getchar()
let ch = nr2char(c) let ch = nr2char(c)
if c == 3 || c == 27 if c == 3 || c == 27
return return
elseif c == 13
let just = (just + 1) % len(s:just)
elseif c >= 48 && c <= 57 elseif c >= 48 && c <= 57
if n == '*' if n == '*'
echon "\rField number(*) already specified" break
return else
endif
let n = n . nr2char(c) let n = n . nr2char(c)
echon "\reasy-align (". n .")" endif
elseif ch == '*' elseif ch == '*'
if !empty(n) if !empty(n)
echon "\rField number(". n .") already specified" break
return else
endif
let n = '*' let n = '*'
echon "\reasy-align (*)" endif
else else
break break
endif endif
@@ -137,9 +161,12 @@ function! easy_align#align(...) range
return return
endif endif
if has_key(g:easy_align_delimiters_merged, ch) let delimiters = extend(copy(s:easy_align_delimiters_default),
let dict = g:easy_align_delimiters_merged[ch] \ exists("g:easy_align_delimiters") ? g:easy_align_delimiters : {})
call s:do_align(a:firstline, a:lastline,
if has_key(delimiters, ch)
let dict = delimiters[ch]
call s:do_align(just, a:firstline, a:lastline,
\ visualmode() == '' ? min([col("'<"), col("'>")]) : 1, \ visualmode() == '' ? min([col("'<"), col("'>")]) : 1,
\ visualmode() == '' ? max([col("'<"), col("'>")]) : 0, \ visualmode() == '' ? max([col("'<"), col("'>")]) : 0,
\ get(dict, 'pattern', ch), \ get(dict, 'pattern', ch),
@@ -147,7 +174,7 @@ function! easy_align#align(...) range
\ get(dict, 'margin_left', ' '), \ get(dict, 'margin_left', ' '),
\ get(dict, 'margin_right', ' '), \ get(dict, 'margin_right', ' '),
\ get(dict, 'stick_to_left', 0), recursive) \ get(dict, 'stick_to_left', 0), recursive)
echon "\reasy-align (". (recursive ? '*' : n) . ch .")" call s:echon(just, (recursive ? '*' : n), ch)
else else
echon "\rUnknown delimiter: ". ch echon "\rUnknown delimiter: ". ch
endif endif

View File

@@ -1,21 +1,16 @@
vim-easy-align *vim-easy-align* *easy-align* vim-easy-align *vim-easy-align* *easy-align*
========================================================================= =========================================================================
Author: Junegunn Choi <https://github.com/junegunn> A simple, easy-to-use Vim alignment plugin.
Yet another Vim alignment plugin without too much ambition. Author: Junegunn Choi
Source: https://github.com/junegunn/vim-easy-align
This plugin clearly has less features than the other pre-existing ones
with the similar goals, but it is simpler, easier to use,
and just good enough for the most of the cases.
https://github.com/junegunn/vim-easy-align
EasyAlign *EasyAlign* EasyAlign *EasyAlign*
------------------------------------------------------------------------- -------------------------------------------------------------------------
Vim-easy-align defines `:EasyAlign` command in the visual mode. vim-easy-align defines interactive `:EasyAlign` command in the visual mode.
For convenience, it is advised that you define a mapping for triggering it For convenience, it is advised that you define a mapping for triggering it
in your `.vimrc`. in your `.vimrc`.
@@ -24,13 +19,14 @@ in your `.vimrc`.
With this mapping, you can align selected lines with a few keystrokes. With this mapping, you can align selected lines with a few keystrokes.
1. <Enter> key to start EasyAlign command 1. <Enter> key to start interactive EasyAlign command
2. Optional field number (default: 1) 2. Optional Enter keys to switch justficiation mode (default: left)
3. Optional field number (default: 1)
1 Alignment around 1st delimiter 1 Alignment around 1st delimiter
2 Alignment around 2nd delimiter 2 Alignment around 2nd delimiter
... ...
* Alignment around all delimiters (recursive) * Alignment around all delimiters (recursive)
3. Delimiter 4. Delimiter
<space> General alignment around whitespaces <space> General alignment around whitespaces
= Operators containing equals sign (=, ==, !=, +=, &&=, ...) = Operators containing equals sign (=, ==, !=, +=, &&=, ...)
: Suitable for formatting JSON or YAML : Suitable for formatting JSON or YAML
@@ -38,17 +34,28 @@ With this mapping, you can align selected lines with a few keystrokes.
, Multi-line method arguments. CSV. , Multi-line method arguments. CSV.
| Table markdown | Table markdown
During the key sequence, <Enter> key will switch justification mode.
(left -> right -> center)
Examples: Examples:
<Enter>= Alignment around 1st equals sign (and the likes) <Enter>= Alignment around 1st equals signs (and the likes)
<Enter>2= Alignment around 2nd equals sign (and the likes) <Enter>2= Alignment around 2nd equals signs (and the likes)
<Enter>3= Alignment around 3rd equals sign (and the likes) <Enter>3= Alignment around 3rd equals signs (and the likes)
<Enter>*= Alignment around all equals signs (and the likes) <Enter>*= Alignment around all equals signs (and the likes)
<Enter><Enter>= Right-justified alignment around 1st equals signs
<Enter><space> Alignment around 1st whitespace <Enter><space> Alignment around 1st whitespace
<Enter>2<space> Alignment around 2nd whitespace <Enter>2<space> Alignment around 2nd whitespace
<Enter>: Alignment around 1st colon <Enter>: Alignment around 1st colon
EasyAlignRight, EasyAlignCenter *EasyAlignRight* *EasyAlignCenter*
-------------------------------------------------------------------------
*EasyAlignRight* and *EasyAlignCenter* are the right and center justified
versions of EasyAlign command.
Partial alignment in blockwise-visual mode Partial alignment in blockwise-visual mode
------------------------------------------------------------------------- -------------------------------------------------------------------------
@@ -56,7 +63,8 @@ In blockwise-visual mode (`CTRL-V`), EasyAlign command aligns only
the selected parts, instead of the whole lines in the range. the selected parts, instead of the whole lines in the range.
Defining custom alignment rules
Defining custom alignment rules *g:easy_align_delimiters*
------------------------------------------------------------------------- -------------------------------------------------------------------------
let g:easy_align_delimiters = { let g:easy_align_delimiters = {
@@ -69,3 +77,46 @@ Defining custom alignment rules
\ } \ }
\ } \ }
Handling unmatched lines *g:easy_align_ignore_unmatched*
-------------------------------------------------------------------------
EasyAlign by default ignores lines without the matching delimiters.
This is to ignore interleaved comments commonly found in code.
For example, when aligning the following code,
{
# Quantity of apples
apple: 1,
# Quantity of bananas
bananas: 2,
# Quantity of grapefruits
grapefruits: 3
}
this is usually what we want.
{
# Quantity of apples
apple: 1,
# Quantity of bananas
bananas: 2,
# Quantity of grapefruits
grapefruits: 3
}
However, this default behavior is configurable.
let g:easy_align_ignore_unmatched = 0
Then we get,
{
# Quantity of apples
apple: 1,
# Quantity of bananas
bananas: 2,
# Quantity of grapefruits
grapefruits: 3
}

View File

@@ -3,4 +3,6 @@ if exists("g:easy_align_plugin_loaded")
endif endif
let g:easy_align_plugin_loaded = 1 let g:easy_align_plugin_loaded = 1
command! -nargs=* -range EasyAlign <line1>,<line2>call easy_align#align(<f-args>) command! -nargs=* -range EasyAlign <line1>,<line2>call easy_align#align(0, <f-args>)
command! -nargs=* -range EasyAlignRight <line1>,<line2>call easy_align#align(1, <f-args>)
command! -nargs=* -range EasyAlignCenter <line1>,<line2>call easy_align#align(2, <f-args>)