14 Commits
2.8.0 ... 2.9.0

Author SHA1 Message Date
Junegunn Choi
9271fc3f8f Make visual-operator repeatable (#24) 2013-12-05 23:16:33 +09:00
Junegunn Choi
d3eec7fa8b Remove an unnecessary function call 2013-12-05 20:50:46 +09:00
Junegunn Choi
62387b78e0 Fix normal-mode repeat affected by visual-mode operator 2013-12-05 13:36:01 +09:00
Junegunn Choi
f400e4d8d1 Wording 2013-12-03 02:27:30 +09:00
Junegunn Choi
9716fb3917 One-minute guide 2013-12-03 02:25:40 +09:00
Junegunn Choi
353ae9b071 One-minute guide 2013-12-03 02:21:05 +09:00
Junegunn Choi
ba4ba6e3c4 Fix vim-repeat integration 2013-12-02 00:33:33 +09:00
Junegunn Choi
da284f908e <Plug>(EasyAlign) / <Plug>(LiveEasyAlign) for vim-repeat integration 2013-12-01 22:58:13 +09:00
Junegunn Choi
8d4d5b7941 Update documentation 2013-11-30 13:07:26 +09:00
Junegunn Choi
165bda1d95 Add <Plug>(EasyAlignOperator) 2013-11-30 13:04:32 +09:00
Junegunn Choi
ddc1e00b81 Update README
- Add <silent> to opfunc mapping
2013-11-30 11:55:54 +09:00
Junegunn Choi
462a800064 Generic operator function with interactive mode 2013-11-30 11:41:11 +09:00
Junegunn Choi
3921d0bab3 Fix #20 - Alignment with tabs inserting spaces 2013-11-20 07:27:39 +09:00
Junegunn Choi
ea1ea51ef1 Fix link to slow GIF 2013-11-15 02:27:14 +09:00
6 changed files with 384 additions and 46 deletions

View File

@@ -8,7 +8,7 @@ Demo
![Screencast](https://raw.github.com/junegunn/i/master/vim-easy-align.gif)
(Too fast? Slower GIF is [here](https://raw.github.com/junegunn/i/master/vim-easy-align.gif))
(Too fast? Slower GIF is [here](https://raw.github.com/junegunn/i/master/vim-easy-align-slow.gif))
Features
--------
@@ -49,11 +49,45 @@ and extract in ~/.vim or
1. Add `Plug 'junegunn/vim-easy-align'` to .vimrc
2. Run `:PlugInstall`
TL;DR - One-minute guide
------------------------
Add the following mappings to your .vimrc.
```vim
" Start interactive EasyAlign in visual mode
vmap <Enter> <Plug>(EasyAlign)
" Start interactive EasyAlign with a Vim movement
nmap <leader>a <Plug>(EasyAlign)
```
And with the following lines of text,
```
apple = red
grass=green
sky=blue
```
try these commands:
- `vip<Enter>=`
- `v`isual-select `i`nner `p`aragraph
- Start EasyAlign command (`<Enter>`)
- Align around `=`
- `<leader>aip=`
- Start EasyAlign command (`<Leader>a`) for `i`nner `p`aragraph
- Align around `=`
Notice that the commands are repeatable with `.` key if you have installed
[repeat.vim](https://github.com/tpope/vim-repeat).
Usage
-----
_vim-easy-align_ defines `:EasyAlign` command (and the right-align
variant `:EasyAlign!`) for visual mode.
variant `:EasyAlign!`).
| Mode | Command |
| ------------------------- | ------------------------------------------------ |
@@ -74,18 +108,23 @@ several options, you can just type in a single character.
### Interactive mode
The command will go into the interactive mode when no argument is given.
For convenience, it is advised that you define a mapping for triggering it in
For convenience, it is advised that you define mappings for triggering it in
your `.vimrc`.
```vim
vnoremap <silent> <Enter> :EasyAlign<Enter>
" For visual mode (e.g. vip<Enter>)
vmap <Enter> <Plug>(EasyAlign)
" For normal mode, with Vim movement (e.g. <Leader>aip)
nmap <Leader>a <Plug>(EasyAlign)
```
(Of course you can use any key combination as the trigger. e.g. `<Leader>a`)
(Of course you can use any key combination as the trigger.)
With the mapping, you can align selected lines of text with only a few keystrokes.
1. `<Enter>` key to start interactive EasyAlign command
1. `<Enter>` key (or `<Leader>a` followed by a Vim movement) to start
interactive EasyAlign command
1. Optional: Enter keys to select alignment mode (left, right, or center)
1. Optional: N-th delimiter (default: 1)
- `1` Around the 1st occurrences of delimiters
@@ -170,6 +209,20 @@ repeatable, non-interactive command recorded in `g:easy_align_last_command`.
:<C-R>=g:easy_align_last_command<Enter><Enter>
```
### EasyAlign as Vim operator
With normal-mode map to `<Plug>(EasyAlign)`, EasyAlign command becomes a Vim
operator that can be used with any Vim movement.
```vim
nmap <leader>a <Plug>(EasyAlign)
```
Now without going into visual mode, you can align the lines in the paragraph
with `<Leader>aip=`, `<Leader>aip*|`, or `<Leader>aip:`. And if you have
installed [repeat.vim](https://github.com/tpope/vim-repeat) by Tim Pope, the
exact alignment can be repeated with `.` key.
### Live interactive mode
If you're performing a complex alignment where multiple options should be
@@ -177,11 +230,12 @@ carefully adjusted, try "live interactive mode" where you can preview the result
of the alignment on-the-fly as you type in.
Live interactive mode can be started with `:LiveEasyAlign` command which takes
the same parameters as `:EasyAlign`. I suggest you define a mapping such as
follows in addition to the one for `:EasyAlign` command.
the same parameters as `:EasyAlign`. I suggest you define mappings such as
follows in addition to the ones for `:EasyAlign` command.
```vim
vnoremap <silent> <Leader><Enter> :LiveEasyAlign<Enter>
vmap <leader><Enter> <Plug>(LiveEasyAlign)
nmap <leader>A <Plug>(LiveEasyAlign)
```
In live interactive mode, you have to type in the same delimiter (or `CTRL-X` on
@@ -289,25 +343,6 @@ 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 N-th parameter: `<Enter>-=`
### EasyAlign as Vim operator
You can define an operator function which executes EasyAlign command, so that it
can be used with a Vim movement.
```vim
function! s:easy_align_1st_eq(type, ...)
'[,']EasyAlign=
endfunction
nnoremap <Leader>= :set opfunc=<SID>easy_align_1st_eq<Enter>g@
function! s:easy_align_1st_colon(type, ...)
'[,']EasyAlign:
endfunction
nnoremap <Leader>: :set opfunc=<SID>easy_align_1st_colon<Enter>g@
```
Now without going into visual mode, you can align the lines in the paragraph
by `<Leader>=ip` or `<Leader>:ip`.
Alignment options
-----------------

View File

@@ -546,7 +546,7 @@ function! s:do_align(todo, modes, all_tokens, all_delims, fl, ll, fc, lc, nth, r
" Adjust indentation of the lines starting with a delimiter
let lpad = ''
if nth == 0
let ipad = repeat(' ', min_indent - len(token.ml))
let ipad = repeat(' ', min_indent - s:strwidth(token.ml))
if mode ==? 'l'
let token = ipad . token
else
@@ -1041,10 +1041,16 @@ function s:summarize(opts, recur, mode_sequence)
return copts
endfunction
function! s:align(bang, live, first_line, last_line, expr)
function! s:align(bang, live, visualmode, first_line, last_line, expr)
" Heuristically determine if the user was in visual mode
let vis = a:first_line == line("'<") && a:last_line == line("'>")
let bvis = vis && char2nr(visualmode()) == 22 " ^V
if empty(a:visualmode)
let vis = a:first_line == line("'<") && a:last_line == line("'>")
let bvis = vis && visualmode() == "\<C-V>"
" Visual-mode explicitly given
else
let vis = 1
let bvis = a:visualmode == "\<C-V>"
end
let range = [a:first_line, a:last_line]
let modes = s:interactive_modes(a:bang)
let mode = modes[0]
@@ -1080,9 +1086,9 @@ function! s:align(bang, live, first_line, last_line, expr)
endtry
endfunction
function! easy_align#align(bang, live, expr) range
function! easy_align#align(bang, live, visualmode, expr) range
try
call s:align(a:bang, a:live, a:firstline, a:lastline, a:expr)
call s:align(a:bang, a:live, a:visualmode, a:firstline, a:lastline, a:expr)
catch 'exit'
endtry
endfunction

View File

@@ -27,14 +27,19 @@ Interactive mode
-------------------------------------------------------------------------
The command will go into the interactive mode when no argument is given.
For convenience, it is advised that you define a mapping for triggering it in
For convenience, it is advised that you define mappings for triggering it in
your `.vimrc`.
vnoremap <silent> <Enter> :EasyAlign<Enter>
" For visual mode (e.g. vip<Enter>)
vmap <Enter> <Plug>(EasyAlign)
" For normal mode, with Vim movement (e.g. <Leader>aip)
nmap <Leader>a <Plug>(EasyAlign)
With this mapping, you can align selected lines of text with a few keystrokes.
1. <Enter> key to start interactive EasyAlign command
1. <Enter> key (or <Leader>a followed by a Vim movement) to start interactive
EasyAlign command
2. Optional: Enter keys to select alignment mode (left, right, or center)
3. Optional: N-th delimiter (default: 1)
1 Around the 1st occurrences of delimiters
@@ -108,6 +113,20 @@ repeatable, non-interactive command recorded in `g:easy_align_last_command`.
:<C-R>=g:easy_align_last_command<Enter><Enter>
EasyAlign as Vim operator *<Plug>(EasyAlign)*
-------------------------------------------------------------------------
With normal-mode map to `<Plug>(EasyAlign)`, EasyAlign command becomes
a Vim operator that can be used with any Vim movement.
nmap <leader>a <Plug>(EasyAlign)
Now without going into visual mode, you can align the lines in the
paragraph with "<Leader>aip=", "<Leader>aip*|", or "<Leader>aip:".
And if you have installed vim-repeat by Tim Pope, the exact alignment
can be repeated with "." key.
Live interactive mode *:LiveEasyAlign* *:LiveEasyAlign!*
-------------------------------------------------------------------------
@@ -115,11 +134,12 @@ If you're performing a complex alignment where multiple options should be
carefully adjusted, try "live interactive mode" which aligns the text
on-the-fly as you type in.
Live interactive mode can be started with `:LiveEasyAlign` command which
takes the same parameters as `:EasyAlign`. I suggest you define the
following mapping in addition to the one for `:EasyAlign` command.
Live interactive mode can be started with `:LiveEasyAlign` command which takes
the same parameters as `:EasyAlign`. I suggest you define mappings such as
follows in addition to the ones for `:EasyAlign` command.
vnoremap <silent> <Leader><Enter> :LiveEasyAlign<Enter>
vmap <Leader><Enter> <Plug>(LiveEasyAlign)
nmap <leader>A <Plug>(LiveEasyAlign)
In live interactive mode, you have to type in the same delimiter (or
`CTRL-X` on regular expression) again to finalize the alignment. This

View File

@@ -26,5 +26,100 @@ if exists("g:loaded_easy_align_plugin")
endif
let g:loaded_easy_align_plugin = 1
command! -nargs=* -range -bang EasyAlign <line1>,<line2>call easy_align#align('<bang>' == '!', 0, <q-args>)
command! -nargs=* -range -bang LiveEasyAlign <line1>,<line2>call easy_align#align('<bang>' == '!', 1, <q-args>)
command! -nargs=* -range -bang EasyAlign <line1>,<line2>call easy_align#align('<bang>' == '!', 0, '', <q-args>)
command! -nargs=* -range -bang LiveEasyAlign <line1>,<line2>call easy_align#align('<bang>' == '!', 1, '', <q-args>)
let s:last_command = 'EasyAlign'
function! s:remember_visual(mode)
let s:last_visual = [a:mode, abs(line("'>") - line("'<")), abs(col("'>") - col("'<"))]
endfunction
function! s:repeat_visual()
let [mode, ldiff, cdiff] = s:last_visual
let cmd = 'normal! '.mode
if ldiff > 0
let cmd .= ldiff . 'j'
endif
let ve_save = &virtualedit
try
if mode == "\<C-V>"
if cdiff > 0
let cmd .= cdiff . 'l'
endif
set virtualedit+=block
endif
execute cmd.":\<C-r>=g:easy_align_last_command\<Enter>\<Enter>"
silent! call repeat#set("\<Plug>(EasyAlignRepeat)")
finally
if ve_save != &virtualedit
let &virtualedit = ve_save
endif
endtry
endfunction
function! s:generic_easy_align_op(type, vmode, live)
let sel_save = &selection
let &selection = "inclusive"
if a:vmode
let vmode = a:type
call s:remember_visual(vmode)
else
let tail = "\<C-c>"
if a:type == 'line'
silent execute "normal! '[V']".tail
elseif a:type == 'block'
silent execute "normal! `[\<C-V>`]".tail
else
silent execute "normal! `[v`]".tail
endif
let vmode = ''
unlet! s:last_visual
endif
try
if get(g:, 'easy_align_need_repeat', 0)
execute "'<,'>". g:easy_align_last_command
else
'<,'>call easy_align#align('<bang>' == '!', a:live, vmode, '')
end
silent! call repeat#set("\<Plug>(EasyAlignRepeat)")
finally
let &selection = sel_save
endtry
endfunction
function! s:easy_align_op(type, ...)
call s:generic_easy_align_op(a:type, a:0, 0)
endfunction
function! s:live_easy_align_op(type, ...)
call s:generic_easy_align_op(a:type, a:0, 1)
endfunction
function! s:easy_align_repeat()
if exists('s:last_visual')
call s:repeat_visual()
else
try
let g:easy_align_need_repeat = 1
normal! .
finally
unlet! g:easy_align_need_repeat
endtry
endif
endfunction
nnoremap <silent> <Plug>(EasyAlign) :set opfunc=<SID>easy_align_op<Enter>g@
vnoremap <silent> <Plug>(EasyAlign) :<C-U>call <SID>easy_align_op(visualmode(), 1)<Enter>
nnoremap <silent> <Plug>(LiveEasyAlign) :set opfunc=<SID>live_easy_align_op<Enter>g@
vnoremap <silent> <Plug>(LiveEasyAlign) :<C-U>call <SID>live_easy_align_op(visualmode(), 1)<Enter>
" vim-repeat support
nnoremap <silent> <Plug>(EasyAlignRepeat) :call <SID>easy_align_repeat()<Enter>
" Backward-compatibility (deprecated)
nnoremap <silent> <Plug>(EasyAlignOperator) :set opfunc=<SID>easy_align_op<Enter>g@

View File

@@ -1,3 +1,6 @@
Execute:
Save &tabstop
Given (Table):
|a|b|c|d|
| -|-|>-|-|
@@ -40,3 +43,80 @@ Execute:
Expect:
a <|>b <|>c <|
aa<|>bb<|>cc<|
Given (Tab-indented code (#20)):
class MyUnitTest(unittest.TestCase):
def test_base(self):
n2f = {}
n2v = {}
f2v = {}
n2gv = {}
n2vt = {}
Execute:
set tabstop=1
%EasyAlign=
Expect:
class MyUnitTest(unittest.TestCase):
def test_base(self):
n2f = {}
n2v = {}
f2v = {}
n2gv = {}
n2vt = {}
Execute:
set tabstop=2
%EasyAlign=
Expect:
class MyUnitTest(unittest.TestCase):
def test_base(self):
n2f = {}
n2v = {}
f2v = {}
n2gv = {}
n2vt = {}
Execute:
set tabstop=4
%EasyAlign=
Expect:
class MyUnitTest(unittest.TestCase):
def test_base(self):
n2f = {}
n2v = {}
f2v = {}
n2gv = {}
n2vt = {}
Execute:
set tabstop=8
%EasyAlign=
Expect:
class MyUnitTest(unittest.TestCase):
def test_base(self):
n2f = {}
n2v = {}
f2v = {}
n2gv = {}
n2vt = {}
Execute:
set tabstop=12
%EasyAlign=
Expect:
class MyUnitTest(unittest.TestCase):
def test_base(self):
n2f = {}
n2v = {}
f2v = {}
n2gv = {}
n2vt = {}
Execute:
Restore

View File

@@ -2,7 +2,7 @@ Execute (Clean up test environment):
Save g:easy_align_ignore_groups, g:easy_align_ignore_unmatched
Save g:easy_align_indentation, g:easy_align_delimiter_align
Save g:easy_align_interactive_modes, g:easy_align_bang_interactive_modes
Save g:easy_align_delimiters
Save g:easy_align_delimiters, &tabstop
Save mapleader
" TODO: revert after test
@@ -15,11 +15,18 @@ Execute (Clean up test environment):
let g:easy_align_delimiters = {}
let mapleader = ' '
vnoremap <silent> <Enter> :EasyAlign<Enter>
vnoremap <silent> r<Enter> :EasyAlign!<Enter>
vnoremap <silent> <Leader><Enter> :LiveEasyAlign<Enter>
vnoremap <silent> <Leader>r<Enter> :LiveEasyAlign!<Enter>
" " Legacy
" vnoremap <silent> <Enter> :EasyAlign<Enter>
" vnoremap <silent> <Leader><Enter> :LiveEasyAlign<Enter>
" nmap <leader>A <Plug>(EasyAlignOperator)
vmap <Enter> <Plug>(EasyAlign)
vmap <leader><Enter> <Plug>(LiveEasyAlign)
nmap <leader>A <Plug>(EasyAlign)
###########################################################
Given (space-separated columns):
@@ -39,6 +46,15 @@ Expect:
111 22 333 444 55555 6666 7 88888
1111 2 33 444 555 66 777 8
Do (left-align using operator map):
\<Space>Aip*\<Space>
Expect:
1 22222 33 444 555 6666 7 888
11 222 3333 4 55 6666 77 888
111 22 333 444 55555 6666 7 88888
1111 2 33 444 555 66 777 8
Do (right-align):
vip
\<Enter>\<Enter>
@@ -1500,6 +1516,92 @@ Expect:
'type': 'global',
'url': 'http://localhost:8090/display/TEST'}
###########################################################
Given (Two paragraphs (requires vim-repeat)):
a = 1
bb = 2
ccc = 3
dddd = 4
d = 1
cc = 2
bbb = 3
aaaa = 4
_____ = 5
Do (Align and repeat):
\<Space>Aip\<Enter>=
6G
.
Expect:
a = 1
bb = 2
ccc = 3
dddd = 4
d = 1
cc = 2
bbb = 3
aaaa = 4
_____ = 5
Do (Visual-mode operator is also repeatable):
vip\<Enter>\<Enter>=
6G
.
Expect:
a = 1
bb = 2
ccc = 3
dddd = 4
d = 1
cc = 2
bbb = 3
aaaa = 4
_____ = 5
Given:
:: a : 1
:: bb : 2
:: ccc : 3
:: dd : 4
:: e : 5
:: :: a:1
:: :: b :2
:: :: ccc : 3
:: :: dd : 4
:: :: e : 5
:: :: f : 6
Do (Blockwise-visual-operator is also repeatable):
fa
\<C-V>
f1
4j
\<Enter>:
7G
fa
.
Expect:
:: a: 1
:: bb: 2
:: ccc: 3
:: dd: 4
:: e: 5
:: :: a: 1
:: :: b: 2
:: :: ccc: 3
:: :: dd: 4
:: :: e: 5
:: :: f : 6
###########################################################
Execute:
Restore