mirror of
https://github.com/junegunn/vim-easy-align.git
synced 2025-11-18 06:43:40 -05:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bab23a1917 | ||
|
|
fa26fd7b42 | ||
|
|
a4a1e27395 | ||
|
|
98bd9fe6f0 | ||
|
|
f944f5bf29 | ||
|
|
484b4ba5ec | ||
|
|
9d3afa6206 | ||
|
|
4c6a8c174d | ||
|
|
3304f4e95a | ||
|
|
e4f86274e3 | ||
|
|
2d575bcc25 | ||
|
|
8a783c2125 | ||
|
|
5230a2402f | ||
|
|
94a750e03e | ||
|
|
afc95b5ed7 | ||
|
|
1d2c58c06a | ||
|
|
4cdc450126 | ||
|
|
7e1be152dc | ||
|
|
c61a11d150 | ||
|
|
2797baca6c |
91
DEMO.md
Normal file
91
DEMO.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# vim: set buftype=nofile colorcolumn= scrolloff=0 noshowcmd:
|
||||
|
||||
vim-easy-align
|
||||
==============
|
||||
|
||||
Where's Lennon?
|
||||
---------------
|
||||
|
||||
Paul McCartney 1942
|
||||
George Harrison 1943
|
||||
Ringo Starr 1940
|
||||
Pete Best 1941
|
||||
|
||||
|
||||
Formatting table
|
||||
----------------
|
||||
```
|
||||
|
||||
| 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 processing |
|
||||
|batch | Boolean | false | enables batch processing mode |
|
||||
|batch_size | Fixnum | nil | maximum number of items in batch|
|
||||
|logger | Logger | nil | logger instance for debug logs |
|
||||
|
||||
```
|
||||
Operators with = sign
|
||||
---------------------
|
||||
```ruby
|
||||
|
||||
a =
|
||||
a = 1
|
||||
bbbb = 2
|
||||
ccccccc = 3
|
||||
ccccccccccccccc
|
||||
ddd = 4
|
||||
eeee === eee = eee = eee=f
|
||||
fff = ggg += gg &&= gg
|
||||
g != hhhhhhhh == 888
|
||||
i := 5
|
||||
i %= 5
|
||||
i *= 5
|
||||
j =~ 5
|
||||
j >= 5
|
||||
aa => 123
|
||||
aa <<= 123
|
||||
aa >>= 123
|
||||
bbb => 123
|
||||
c => 1233123
|
||||
d => 123
|
||||
dddddd &&= 123
|
||||
dddddd ||= 123
|
||||
dddddd /= 123
|
||||
gg <=> ee
|
||||
|
||||
```
|
||||
Formatting YAML (or JSON)
|
||||
-------------------------
|
||||
```yaml
|
||||
|
||||
mysql:
|
||||
# JDBC driver for MySQL database:
|
||||
driver: com.mysql.jdbc.Driver
|
||||
# JDBC URL for the connection (jdbc:mysql://HOSTNAME/DATABASE)
|
||||
url: jdbc:mysql://localhost/test
|
||||
database: test
|
||||
"user:pass":r00t:pa55
|
||||
|
||||
```
|
||||
Using blockwise-visual mode or negative N-th parameter
|
||||
------------------------------------------------------
|
||||
```ruby
|
||||
|
||||
options = { :caching => nil,
|
||||
:versions => 3,
|
||||
"cache=blocks" => false }.merge(options)
|
||||
|
||||
```
|
||||
Commas
|
||||
------
|
||||
|
||||
aaa, bb,c
|
||||
d,eeeeeee
|
||||
fffff, gggggggggg,
|
||||
h, , ii
|
||||
j,,k
|
||||
|
||||
|
||||
@@ -166,8 +166,8 @@ my_object
|
||||
```
|
||||
|
||||
|
||||
Using blockwise-visual mode or negative field index
|
||||
---------------------------------------------------
|
||||
Using blockwise-visual mode or negative N-th parameter
|
||||
------------------------------------------------------
|
||||
|
||||
You can try either:
|
||||
- select text around `=>` in blockwise-visual mode (`CTRL-V`) and `<Enter>=`
|
||||
|
||||
92
README.md
92
README.md
@@ -37,15 +37,17 @@ and extract in ~/.vim or
|
||||
[plugin](https://github.com/Shougo/neobundle.vim)
|
||||
[manager](https://github.com/MarcWeber/vim-addon-manager).
|
||||
|
||||
### With Vundle
|
||||
|
||||
Add the following line to your .vimrc,
|
||||
|
||||
```vim
|
||||
Bundle 'junegunn/vim-easy-align'
|
||||
```
|
||||
|
||||
then execute `:BundleInstall` command.
|
||||
- [Pathogen](https://github.com/tpope/vim-pathogen)
|
||||
- `git clone https://github.com/junegunn/vim-easy-align.git ~/.vim/bundle/vim-easy-align`
|
||||
- [Vundle](https://github.com/gmarik/vundle)
|
||||
1. Add `Bundle 'junegunn/vim-easy-align'` to .vimrc
|
||||
2. Run `:BundleInstall`
|
||||
- [NeoBundle](https://github.com/Shougo/neobundle.vim)
|
||||
1. Add `NeoBundle 'junegunn/vim-easy-align'` to .vimrc
|
||||
2. Run `:NeoBundleInstall`
|
||||
- [vim-plug](https://github.com/junegunn/vim-plug)
|
||||
1. Add `Plug 'junegunn/vim-easy-align'` to .vimrc
|
||||
2. Run `:PlugInstall`
|
||||
|
||||
Usage
|
||||
-----
|
||||
@@ -56,8 +58,8 @@ variant `:EasyAlign!`) for visual mode.
|
||||
| Mode | Command |
|
||||
| ------------------------- | ------------------------------------------------ |
|
||||
| Interactive mode | `:EasyAlign[!] [OPTIONS]` |
|
||||
| Using predefined rules | `:EasyAlign[!] [FIELD#] DELIMITER_KEY [OPTIONS]` |
|
||||
| Using regular expressions | `:EasyAlign[!] [FIELD#] /REGEXP/ [OPTIONS]` |
|
||||
| Using predefined rules | `:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]` |
|
||||
| Using regular expressions | `:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]` |
|
||||
|
||||
### Concept of _alignment rule_
|
||||
|
||||
@@ -75,7 +77,7 @@ For convenience, it is advised that you define a mapping for triggering it in
|
||||
your `.vimrc`.
|
||||
|
||||
```vim
|
||||
vnoremap <silent> <Enter> :EasyAlign<cr>
|
||||
vnoremap <silent> <Enter> :EasyAlign<Enter>
|
||||
```
|
||||
|
||||
(Of course you can use any key combination as the trigger. e.g. `<Leader>a`)
|
||||
@@ -83,8 +85,8 @@ vnoremap <silent> <Enter> :EasyAlign<cr>
|
||||
With the mapping, you can align selected lines of text with only a few keystrokes.
|
||||
|
||||
1. `<Enter>` key to start interactive EasyAlign command
|
||||
1. Optional Enter keys to select alignment mode (left, right, or center)
|
||||
1. Optional field number (default: 1)
|
||||
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
|
||||
- `2` Around the 2nd occurrences of delimiters
|
||||
- ...
|
||||
@@ -156,6 +158,14 @@ keys listed below. The meaning of each option will be described in
|
||||
| `CTRL-O` | `mode_sequence` | Input string of `/[lrc]+\*{0,2}/` |
|
||||
| `<Left>` | `stick_to_left` | `{ 'stick_to_left': 1, 'left_margin': 0 }` |
|
||||
| `<Right>` | `stick_to_left` | `{ 'stick_to_left': 0, 'left_margin': 1 }` |
|
||||
| `<Down>` | `*_margin` | `{ 'left_margin': 0, 'right_margin': 0 }` |
|
||||
|
||||
After a successful alignment, you can repeat the same operation using the
|
||||
repeatable, non-interactive command recorded in `g:easy_align_last_command`.
|
||||
|
||||
```vim
|
||||
:<C-R>=g:easy_align_last_command<Enter><Enter>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -169,17 +179,17 @@ Go try out vim-easy-align right now, and come back later when you feel like it.
|
||||
|
||||
---
|
||||
|
||||
### Non-interactive mode
|
||||
### Non-interactive mode (command line)
|
||||
|
||||
Instead of going into the interactive mode, you can type in arguments to
|
||||
`:EasyAlign` command.
|
||||
|
||||
```vim
|
||||
" Using predefined alignment rules
|
||||
:EasyAlign[!] [FIELD#] DELIMITER_KEY [OPTIONS]
|
||||
:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]
|
||||
|
||||
" Using arbitrary regular expressions
|
||||
:EasyAlign[!] [FIELD#] /REGEXP/ [OPTIONS]
|
||||
:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]
|
||||
```
|
||||
|
||||
For example, when aligning the following lines around colons and semi-colons,
|
||||
@@ -213,8 +223,26 @@ You can even omit spaces between the arguments, so concisely (or cryptically):
|
||||
|
||||
- `:EasyAlign*/[:;]\+/{'s':1,'l':0}`
|
||||
|
||||
The same thing can be done in the interactive mode as well with the following
|
||||
key combination.
|
||||
Nice. But let's make it even shorter. When you use write regular expression in
|
||||
command line, option values can be written in shorthand notation.
|
||||
|
||||
- `:EasyAlign*/[:;]\+/s1l0`
|
||||
|
||||
The following table summarizes the shorthand notation.
|
||||
|
||||
| Option | Expression |
|
||||
| ---------------- | ---------- |
|
||||
| left_margin | `l[0-9]+` |
|
||||
| right_margin | `r[0-9]+` |
|
||||
| stick_to_left | `s[01]` |
|
||||
| ignore_unmatched | `iu[01]` |
|
||||
| ignore_groups | `ig\[.*\]` |
|
||||
| delimiter_align | `d[lrc]` |
|
||||
| mode_sequence | `m[lrc*]*` |
|
||||
| indentation | `i[ksdn]` |
|
||||
|
||||
For your information, the same thing can be done in the interactive mode as well
|
||||
with the following key combination.
|
||||
|
||||
- `<Enter>`
|
||||
- `*`
|
||||
@@ -247,7 +275,7 @@ 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: `<Enter>-=`
|
||||
since the same can be easily done using the negative N-th parameter: `<Enter>-=`
|
||||
|
||||
Alignment options
|
||||
-----------------
|
||||
@@ -271,19 +299,19 @@ There are 4 ways to set alignment options (from lowest precedence to highest):
|
||||
|
||||
1. Some option values can be set with corresponding global variables
|
||||
2. Option values can be specified in the definition of each alignment rule
|
||||
3. Option values can be given as a dictionary argument to `:EasyAlign` command
|
||||
3. Option values can be given as arguments to `:EasyAlign` command
|
||||
4. Option values can be set in interactive mode using special shortcut keys
|
||||
|
||||
| Option | Shortcut key | Global variable |
|
||||
| ------------------ | ------------------- | ------------------------------- |
|
||||
| `left_margin` | `CTRL-L` | |
|
||||
| `right_margin` | `CTRL-R` | |
|
||||
| `stick_to_left` | `<Left>`, `<Right>` | |
|
||||
| `ignore_groups` | `CTRL-G` | `g:easy_align_ignore_groups` |
|
||||
| `ignore_unmatched` | `CTRL-U` | `g:easy_align_ignore_unmatched` |
|
||||
| `indentation` | `CTRL-I` | `g:easy_align_indentation` |
|
||||
| `delimiter_align` | `CTRL-D` | `g:easy_align_delimiter_align` |
|
||||
| `mode_sequence` | `CTRL-O` | |
|
||||
| Option name | Shortcut key | Abbreviated | Global variable |
|
||||
| ------------------ | ------------------- | ----------- | ------------------------------- |
|
||||
| `left_margin` | `CTRL-L` | `l[0-9]+` | |
|
||||
| `right_margin` | `CTRL-R` | `r[0-9]+` | |
|
||||
| `stick_to_left` | `<Left>`, `<Right>` | `s[01]` | |
|
||||
| `ignore_groups` | `CTRL-G` | `ig\[.*\]` | `g:easy_align_ignore_groups` |
|
||||
| `ignore_unmatched` | `CTRL-U` | `iu[01]` | `g:easy_align_ignore_unmatched` |
|
||||
| `indentation` | `CTRL-I` | `i[ksdn]` | `g:easy_align_indentation` |
|
||||
| `delimiter_align` | `CTRL-D` | `d[lrc]` | `g:easy_align_delimiter_align` |
|
||||
| `mode_sequence` | `CTRL-O` | `m[lrc*]*` | |
|
||||
|
||||
### Ignoring delimiters in comments or strings
|
||||
|
||||
@@ -508,7 +536,7 @@ let g:easy_align_bang_interactive_modes = ['c', 'r']
|
||||
|
||||
### Alignments over multiple occurrences of delimiters
|
||||
|
||||
As stated above, "field number" is used to target specific occurrences of
|
||||
As stated above, "N-th" parameter is used to target specific occurrences of
|
||||
the delimiter when it appears multiple times in each line.
|
||||
|
||||
To recap:
|
||||
|
||||
@@ -49,10 +49,10 @@ let s:known_options = {
|
||||
\ }
|
||||
|
||||
let s:option_values = {
|
||||
\ 'indentation': ['shallow', 'deep', 'none', 'keep'],
|
||||
\ 'delimiter_align': ['left', 'center', 'right'],
|
||||
\ 'ignore_unmatched': [0, 1],
|
||||
\ 'ignore_groups': [[], ['String'], ['Comment'], ['String', 'Comment']]
|
||||
\ 'indentation': ['shallow', 'deep', 'none', 'keep', -1],
|
||||
\ 'delimiter_align': ['left', 'center', 'right', -1],
|
||||
\ 'ignore_unmatched': [0, 1, -1],
|
||||
\ 'ignore_groups': [[], ['String'], ['Comment'], ['String', 'Comment'], -1]
|
||||
\ }
|
||||
|
||||
let s:shorthand = {
|
||||
@@ -95,7 +95,6 @@ function! s:ignored_syntax()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:prev_echon_len = 0
|
||||
function! s:echon_(tokens)
|
||||
" http://vim.wikia.com/wiki/How_to_print_full_screen_width_messages
|
||||
let xy = [&ruler, &showcmd]
|
||||
@@ -104,11 +103,6 @@ function! s:echon_(tokens)
|
||||
|
||||
let winlen = winwidth(winnr()) - 2
|
||||
let len = len(join(map(copy(a:tokens), 'v:val[1]'), ''))
|
||||
if len < s:prev_echon_len
|
||||
echohl None
|
||||
echon "\r". repeat(' ', min([winlen, s:prev_echon_len]))
|
||||
endif
|
||||
let s:prev_echon_len = len
|
||||
let ellipsis = len > winlen ? '..' : ''
|
||||
|
||||
echon "\r"
|
||||
@@ -130,7 +124,7 @@ function! s:echon_(tokens)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:echon(l, n, r, d, o)
|
||||
function! s:echon(l, n, r, d, o, warn)
|
||||
let tokens = [
|
||||
\ ['Function', ':EasyAlign'],
|
||||
\ ['ModeMsg', get(s:mode_labels, a:l, a:l)],
|
||||
@@ -141,10 +135,14 @@ function! s:echon(l, n, r, d, o)
|
||||
call extend(tokens, a:r == 1 ?
|
||||
\ [['Delimiter', '/'], ['String', a:d], ['Delimiter', '/']] :
|
||||
\ [['Identifier', a:d == ' ' ? '\ ' : (a:d == '\' ? '\\' : a:d)]])
|
||||
if a:r == -1 | call add(tokens, ['Comment', ')']) | endif
|
||||
if a:r == -1 | call extend(tokens, [['Normal', '_'], ['Comment', ')']]) | endif
|
||||
call add(tokens, ['Statement', empty(a:o) ? '' : ' '.string(a:o)])
|
||||
if !empty(a:warn)
|
||||
call add(tokens, ['WarningMsg', ' ('.a:warn.')'])
|
||||
endif
|
||||
|
||||
call s:echon_(tokens)
|
||||
return join(map(tokens, 'v:val[1]'), '')
|
||||
endfunction
|
||||
|
||||
function! s:exit(msg)
|
||||
@@ -314,7 +312,10 @@ function! s:split_line(line, nth, modes, cycle, fc, lc, pattern, stick_to_left,
|
||||
let delims = []
|
||||
" Append an empty item to enable right/center alignment of the last token
|
||||
" - if the last token is not ignorable or ignorable but not the only token
|
||||
elseif (mode ==? 'r' || mode ==? 'c') && (!ignorable || len(tokens) > 1) && a:nth >= 0 " includes -0
|
||||
elseif a:ignore_unmatched != 1 &&
|
||||
\ (mode ==? 'r' || mode ==? 'c') &&
|
||||
\ (!ignorable || len(tokens) > 1) &&
|
||||
\ a:nth >= 0 " includes -0
|
||||
call add(tokens, '')
|
||||
call add(delims, '')
|
||||
endif
|
||||
@@ -363,12 +364,12 @@ function! s:do_align(modes, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth
|
||||
" Calculate the maximum number of tokens for a line within the range
|
||||
call s:max(max, { 'tokens': len(tokens) })
|
||||
|
||||
if a:nth > 0 " Positive field number
|
||||
if a:nth > 0 " Positive N-th
|
||||
if len(tokens) < a:nth
|
||||
continue
|
||||
endif
|
||||
let nth = a:nth - 1 " make it 0-based
|
||||
else " -0 or Negative field number
|
||||
else " -0 or Negative N-th
|
||||
if a:nth == 0 && mode !=? 'l'
|
||||
let nth = len(tokens) - 1
|
||||
else
|
||||
@@ -560,16 +561,28 @@ function! s:atoi(str)
|
||||
return (a:str =~ '^[0-9]\+$') ? str2nr(a:str) : a:str
|
||||
endfunction
|
||||
|
||||
function! s:interactive(modes, vis, opts)
|
||||
function! s:shift_opts(opts, key, vals)
|
||||
let val = s:shift(a:vals, 1)
|
||||
if type(val) == 0 && val == -1
|
||||
call remove(a:opts, a:key)
|
||||
else
|
||||
let a:opts[a:key] = val
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:interactive(modes, vis, opts, delims)
|
||||
let mode = s:shift(a:modes, 1)
|
||||
let n = ''
|
||||
let ch = ''
|
||||
let opts = s:compact_options(a:opts)
|
||||
let vals = deepcopy(s:option_values)
|
||||
let regx = 0
|
||||
let warn = ''
|
||||
|
||||
while 1
|
||||
call s:echon(mode, n, -1, '', opts)
|
||||
call s:echon(mode, n, -1, '', opts, warn)
|
||||
let check = 0
|
||||
let warn = ''
|
||||
|
||||
let c = getchar()
|
||||
let ch = nr2char(c)
|
||||
@@ -587,39 +600,55 @@ function! s:interactive(modes, vis, opts)
|
||||
elseif ch == '-'
|
||||
if empty(n) | let n = '-'
|
||||
elseif n == '-' | let n = ''
|
||||
else | break
|
||||
else | let check = 1
|
||||
endif
|
||||
elseif ch == '*'
|
||||
if empty(n) | let n = '*'
|
||||
elseif n == '*' | let n = '**'
|
||||
elseif n == '**' | let n = ''
|
||||
else | break
|
||||
else | let check = 1
|
||||
endif
|
||||
elseif c >= 48 && c <= 57 " Numbers
|
||||
if n[0] == '*' | break
|
||||
elseif (c == 48 && len(n) > 0) || c > 48 && c <= 57 " Numbers
|
||||
if n[0] == '*' | let check = 1
|
||||
else | let n = n . ch
|
||||
end
|
||||
elseif ch == "\<C-D>"
|
||||
let opts['da'] = s:shift(vals['delimiter_align'], 1)
|
||||
call s:shift_opts(opts, 'da', vals['delimiter_align'])
|
||||
elseif ch == "\<C-I>"
|
||||
let opts['idt'] = s:shift(vals['indentation'], 1)
|
||||
call s:shift_opts(opts, 'idt', vals['indentation'])
|
||||
elseif ch == "\<C-L>"
|
||||
let opts['lm'] = s:atoi(s:input("Left margin: ", get(opts, 'lm', ''), a:vis))
|
||||
let lm = s:input("Left margin: ", get(opts, 'lm', ''), a:vis)
|
||||
if empty(lm)
|
||||
let warn = 'Set to default. Input 0 to remove it'
|
||||
silent! call remove(opts, 'lm')
|
||||
else
|
||||
let opts['lm'] = s:atoi(lm)
|
||||
endif
|
||||
elseif ch == "\<C-R>"
|
||||
let opts['rm'] = s:atoi(s:input("Right margin: ", get(opts, 'rm', ''), a:vis))
|
||||
let rm = s:input("Right margin: ", get(opts, 'rm', ''), a:vis)
|
||||
if empty(rm)
|
||||
let warn = 'Set to default. Input 0 to remove it'
|
||||
silent! call remove(opts, 'rm')
|
||||
else
|
||||
let opts['rm'] = s:atoi(rm)
|
||||
endif
|
||||
elseif ch == "\<C-U>"
|
||||
let opts['iu'] = s:shift(vals['ignore_unmatched'], 1)
|
||||
call s:shift_opts(opts, 'iu', vals['ignore_unmatched'])
|
||||
elseif ch == "\<C-G>"
|
||||
let opts['ig'] = s:shift(vals['ignore_groups'], 1)
|
||||
call s:shift_opts(opts, 'ig', vals['ignore_groups'])
|
||||
elseif c == "\<Left>"
|
||||
let opts['stl'] = 1
|
||||
let opts['lm'] = 0
|
||||
elseif c == "\<Right>"
|
||||
let opts['stl'] = 0
|
||||
let opts['lm'] = 1
|
||||
elseif c == "\<Up>" || c == "\<Down>"
|
||||
elseif c == "\<Down>"
|
||||
let opts['lm'] = 0
|
||||
let opts['rm'] = 0
|
||||
elseif c == "\<Up>"
|
||||
silent! call remove(opts, 'stl')
|
||||
silent! call remove(opts, 'lm')
|
||||
silent! call remove(opts, 'rm')
|
||||
elseif ch == "\<C-O>"
|
||||
let modes = tolower(s:input("Mode sequence: ", get(opts, 'm', mode), a:vis))
|
||||
if match(modes, '^[lrc]\+\*\{0,2}$') != -1
|
||||
@@ -633,22 +662,88 @@ function! s:interactive(modes, vis, opts)
|
||||
elseif ch == "\<C-_>" || ch == "\<C-X>"
|
||||
let prompt = 'Regular expression: '
|
||||
let ch = s:input(prompt, '', a:vis)
|
||||
if !empty(ch)
|
||||
if !empty(ch) && s:valid_regexp(ch)
|
||||
let regx = 1
|
||||
let s:prev_echon_len = len(prompt . ch)
|
||||
break
|
||||
else
|
||||
let warn = 'Invalid regular expression: '.ch
|
||||
endif
|
||||
elseif ch =~ '[[:print:]]'
|
||||
let check = 1
|
||||
else
|
||||
break
|
||||
let warn = 'Invalid character'
|
||||
endif
|
||||
|
||||
if check
|
||||
if has_key(a:delims, ch)
|
||||
break
|
||||
else
|
||||
let warn = 'Unknown delimiter key: '.ch
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
return [mode, n, ch, s:normalize_options(opts), regx]
|
||||
endfunction
|
||||
|
||||
function! s:test_regexp(regexp)
|
||||
try | call matchlist('', a:regexp)
|
||||
catch | call s:exit("Invalid regular expression: ". a:regexp)
|
||||
function! s:valid_regexp(regexp)
|
||||
try
|
||||
call matchlist('', a:regexp)
|
||||
catch
|
||||
return 0
|
||||
endtry
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:test_regexp(regexp)
|
||||
if !s:valid_regexp(a:regexp)
|
||||
call s:exit('Invalid regular expression: '. a:regexp)
|
||||
endif
|
||||
return a:regexp
|
||||
endfunction
|
||||
|
||||
function! s:parse_shortcut_opts(expr)
|
||||
let opts = {}
|
||||
let expr = substitute(a:expr, '\s', '', 'g')
|
||||
let regex =
|
||||
\ '^\('
|
||||
\ .'\(l[0-9]\+\)\|\(r[0-9]\+\)\|\(iu[01]\)\|\(s[01]\)\|'
|
||||
\ .'\(d[clr]\)\|\(m[lrc*]\+\)\|\(i[kdsn]\)\|\(ig\[.*\]\)'
|
||||
\ .'\)\+$'
|
||||
|
||||
if empty(expr)
|
||||
return opts
|
||||
elseif expr !~ regex
|
||||
call s:exit("Invalid expression: ". a:expr)
|
||||
else
|
||||
let match = matchlist(expr, regex)
|
||||
if empty(match) | break | endif
|
||||
for m in filter(match[ 2 : -1 ], '!empty(v:val)')
|
||||
let k = tolower(m[0])
|
||||
let kk = tolower(m[0 : 1])
|
||||
let rest = m[1 : -1]
|
||||
if index(['l', 'r', 's'], k) >= 0
|
||||
let opts[k] = str2nr(rest)
|
||||
elseif kk == 'iu'
|
||||
let opts['iu'] = str2nr(m[2 : -1])
|
||||
elseif kk == 'ig'
|
||||
try
|
||||
let arr = eval(m[2 : -1])
|
||||
if type(arr) == 3
|
||||
let opts['ig'] = arr
|
||||
else
|
||||
throw 'Not an array'
|
||||
endif
|
||||
catch
|
||||
call s:exit("Invalid ignore_groups: ". a:expr)
|
||||
endtry
|
||||
elseif k == 'i'
|
||||
let opts['idt'] = rest
|
||||
else
|
||||
let opts[k] = rest
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
return s:normalize_options(opts)
|
||||
endfunction
|
||||
|
||||
function! s:parse_args(args)
|
||||
@@ -691,11 +786,14 @@ function! s:parse_args(args)
|
||||
endif
|
||||
|
||||
" Has /Regexp/?
|
||||
let matches = matchlist(args, '^\(.\{-}\)\s*/\(.*\)/\s*$')
|
||||
let matches = matchlist(args, '^\(.\{-}\)\s*/\(.*\)/\(.\{-}\)$')
|
||||
|
||||
" Found regexp
|
||||
if !empty(matches)
|
||||
return [matches[1], matches[2], opts, 1]
|
||||
if !empty(matches[3])
|
||||
let opts = extend(s:parse_shortcut_opts(matches[3]), opts)
|
||||
endif
|
||||
return [matches[1], s:test_regexp(matches[2]), opts, 1]
|
||||
else
|
||||
let tokens = matchlist(args, '^\([1-9][0-9]*\|-[0-9]*\|\*\*\?\)\?\s*\(.\{-}\)\?$')
|
||||
return [tokens[1], tokens[2], opts, 0]
|
||||
@@ -730,12 +828,17 @@ function! s:align(bang, 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 delimiters = s:easy_align_delimiters_default
|
||||
if exists('g:easy_align_delimiters')
|
||||
let delimiters = extend(copy(delimiters), g:easy_align_delimiters)
|
||||
endif
|
||||
|
||||
if empty(a:expr)
|
||||
let [mode, n, ch, opts, regexp] = s:interactive(copy(modes), vis, opts)
|
||||
let [mode, n, ch, opts, regexp] = s:interactive(copy(modes), vis, opts, delimiters)
|
||||
else
|
||||
let [n, ch, opts, regexp] = s:parse_args(a:expr)
|
||||
if empty(n) && empty(ch)
|
||||
let [mode, n, ch, opts, regexp] = s:interactive(copy(modes), vis, opts)
|
||||
let [mode, n, ch, opts, regexp] = s:interactive(copy(modes), vis, opts, delimiters)
|
||||
elseif empty(ch)
|
||||
" Try swapping n and ch
|
||||
let [n, ch] = ['', n]
|
||||
@@ -747,18 +850,12 @@ function! s:align(bang, first_line, last_line, expr)
|
||||
elseif n == '-' | let nth = -1
|
||||
elseif empty(n) | let nth = 1
|
||||
elseif n == '0' || ( n != '-0' && n != string(str2nr(n)) )
|
||||
call s:exit('Invalid field number: '. n)
|
||||
call s:exit('Invalid N-th parameter: '. n)
|
||||
else
|
||||
let nth = n
|
||||
endif
|
||||
|
||||
let delimiters = s:easy_align_delimiters_default
|
||||
if exists('g:easy_align_delimiters')
|
||||
let delimiters = extend(copy(delimiters), g:easy_align_delimiters)
|
||||
endif
|
||||
|
||||
if regexp
|
||||
call s:test_regexp(ch)
|
||||
let dict = { 'pattern': ch }
|
||||
else
|
||||
" Resolving command-line ambiguity
|
||||
@@ -816,7 +913,7 @@ function! s:align(bang, first_line, last_line, expr)
|
||||
\ get(dict, 'delimiter_align', get(g:, 'easy_align_delimiter_align', 'r'))[0],
|
||||
\ get(dict, 'indentation', get(g:, 'easy_align_indentation', 'k'))[0],
|
||||
\ get(dict, 'stick_to_left', 0),
|
||||
\ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 1)),
|
||||
\ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 2)),
|
||||
\ get(dict, 'ignore_groups', get(dict, 'ignores', s:ignored_syntax())),
|
||||
\ recur)
|
||||
|
||||
@@ -828,6 +925,6 @@ function! s:align(bang, first_line, last_line, expr)
|
||||
\ )
|
||||
call extend(copts, { 'm': aseq_str })
|
||||
endif
|
||||
call s:echon('', n, regexp, ch, copts)
|
||||
let g:easy_align_last_command = s:echon('', n, regexp, ch, copts, '')
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@ EasyAlign *:EasyAlign* *:EasyAlign!*
|
||||
vim-easy-align defines `:EasyAlign` command in the visual mode.
|
||||
(:EasyAlign! is the right-align version.)
|
||||
|
||||
| Mode | Command |
|
||||
| ------------------------- | ---------------------------------------------- |
|
||||
| Interactive mode | :EasyAlign[!] [OPTIONS] |
|
||||
| Using predefined rules | :EasyAlign[!] [FIELD#] DELIMITER_KEY [OPTIONS] |
|
||||
| Using regular expressions | :EasyAlign[!] [FIELD#] /REGEXP/ [OPTIONS] |
|
||||
| Mode | Command |
|
||||
| ------------------------- | -------------------------------------------- |
|
||||
| Interactive mode | :EasyAlign[!] [OPTIONS] |
|
||||
| Using predefined rules | :EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS] |
|
||||
| Using regular expressions | :EasyAlign[!] [N-th] /REGEXP/ [OPTIONS] |
|
||||
|
||||
|
||||
Interactive mode
|
||||
@@ -30,13 +30,13 @@ 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
|
||||
your `.vimrc`.
|
||||
|
||||
vnoremap <silent> <Enter> :EasyAlign<cr>
|
||||
vnoremap <silent> <Enter> :EasyAlign<Enter>
|
||||
|
||||
With this mapping, you can align selected lines of text with a few keystrokes.
|
||||
|
||||
1. <Enter> key to start interactive EasyAlign command
|
||||
2. Optional Enter keys to select alignment mode (left, right, or center)
|
||||
3. Optional field number (default: 1)
|
||||
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
|
||||
2 Around the 2nd occurrences of delimiters
|
||||
* Around all occurrences of delimiters
|
||||
@@ -97,19 +97,27 @@ described in the following sections.
|
||||
| CTRL-O | mode_sequence | Input string of /[lrc]+\*{0,2}/ |
|
||||
| <Left> | stick_to_left | { 'stick_to_left': 1, 'left_margin': 0 } |
|
||||
| <Right> | stick_to_left | { 'stick_to_left': 0, 'left_margin': 1 } |
|
||||
| <Down> | *_margin | { 'left_margin': 0, 'right_margin': 0 } |
|
||||
|
||||
*g:easy_align_last_command*
|
||||
|
||||
After a successful alignment, you can repeat the same operation using the
|
||||
repeatable, non-interactive command recorded in `g:easy_align_last_command`.
|
||||
|
||||
:<C-R>=g:easy_align_last_command<Enter><Enter>
|
||||
|
||||
|
||||
Non-interactive mode
|
||||
Non-interactive mode (command line)
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
Instead of going into the interactive mode, you can type in arguments to
|
||||
`:EasyAlign` command.
|
||||
|
||||
" Using predefined alignment rules
|
||||
:EasyAlign[!] [FIELD#] DELIMITER_KEY [OPTIONS]
|
||||
:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]
|
||||
|
||||
" Using arbitrary regular expressions
|
||||
:EasyAlign[!] [FIELD#] /REGEXP/ [OPTIONS]
|
||||
:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]
|
||||
|
||||
For example, when aligning the following lines around colons and semi-colons,
|
||||
|
||||
@@ -118,16 +126,16 @@ For example, when aligning the following lines around colons and semi-colons,
|
||||
|
||||
try these commands:
|
||||
|
||||
- :EasyAlign /[:;]\+/
|
||||
- :EasyAlign 2/[:;]\+/
|
||||
- :EasyAlign */[:;]\+/
|
||||
- :EasyAlign **/[:;]\+/
|
||||
:EasyAlign /[:;]\+/
|
||||
:EasyAlign 2/[:;]\+/
|
||||
:EasyAlign */[:;]\+/
|
||||
:EasyAlign **/[:;]\+/
|
||||
|
||||
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, 'left_margin': 0 }
|
||||
:EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'left_margin': 0 }
|
||||
|
||||
Then we get:
|
||||
|
||||
@@ -136,20 +144,38 @@ Then we get:
|
||||
|
||||
Option names are fuzzy-matched, so you can write as follows:
|
||||
|
||||
- :EasyAlign * /[:;]\+/ { 'stl': 1, 'l': '' }
|
||||
:EasyAlign * /[:;]\+/ { 'stl': 1, 'l': '' }
|
||||
|
||||
You can even omit spaces between the arguments, so concisely (or cryptically):
|
||||
|
||||
- :EasyAlign*/[:;]\+/{'s':1,'l':''}
|
||||
:EasyAlign*/[:;]\+/{'s':1,'l':''}
|
||||
|
||||
The same thing can be done in the interactive mode as well with the following
|
||||
key combination.
|
||||
Nice. But let's make it even shorter. When you use write regular expression in
|
||||
command line, option values can be written in shorthand notation.
|
||||
|
||||
- <Enter>
|
||||
- *
|
||||
- <Left>
|
||||
- <CTRL-/> (or <CTRL-X> on GVim)
|
||||
- [:;]\+
|
||||
:EasyAlign*/[:;]\+/s1l0
|
||||
|
||||
The following table summarizes the shorthand notation.
|
||||
|
||||
| Option | Expression |
|
||||
| -------------- | ---------- |
|
||||
| left_margin | l[0-9]+ |
|
||||
| right_margin | r[0-9]+ |
|
||||
| stick_to_left | s[01] |
|
||||
| ignore_unmatched | iu[01] |
|
||||
| ignore_groups | ig\[.*\] |
|
||||
| delimiter_align | d[lrc] |
|
||||
| mode_sequence | m[lrc*]+ |
|
||||
| indentation | i[ksdn] |
|
||||
|
||||
For your information, the same thing can be done in the interactive mode as well
|
||||
with the following key combination.
|
||||
|
||||
- <Enter>
|
||||
- *
|
||||
- <Left>
|
||||
- <CTRL-/> (or <CTRL-X> on GVim)
|
||||
- [:;]\+
|
||||
|
||||
|
||||
Partial alignment in blockwise-visual mode
|
||||
@@ -175,26 +201,26 @@ Available options are as follows.
|
||||
| | | (right, left, center) |
|
||||
| indentation | string | 'k' |
|
||||
| | | (keep, shallow, deep, none) |
|
||||
| mode_sequence | string | (Depends on field number and |
|
||||
| mode_sequence | string | (Depends on N-th param and |
|
||||
| | | selected alignment mode) |
|
||||
|
||||
There are 4 ways to set alignment options (from lowest precedence to highest):
|
||||
|
||||
1. Some option values can be set with corresponding global variables
|
||||
2. Option values can be specified in the definition of each alignment rule
|
||||
3. Option values can be given as a dictionary argument to :EasyAlign command
|
||||
3. Option values can be given as arguments to :EasyAlign command
|
||||
4. Option values can be set in interactive mode using special shortcut keys
|
||||
|
||||
| Option | Shortcut key | Global variable |
|
||||
| ---------------- | ------------------- | ------------------------------- |
|
||||
| left_margin | CTRL-L | |
|
||||
| right_margin | CTRL-R | |
|
||||
| stick_to_left | <Left>, <Right> | |
|
||||
| ignore_groups | CTRL-G | `g:easy_align_ignore_groups` |
|
||||
| ignore_unmatched | CTRL-U | `g:easy_align_ignore_unmatched` |
|
||||
| indentation | CTRL-I | `g:easy_align_indentation` |
|
||||
| delimiter_align | CTRL-D | `g:easy_align_delimiter_align` |
|
||||
| mode_sequence | CTRL-O | |
|
||||
| Option | Shortcut key | Abbreviated | Global variable |
|
||||
| ---------------- | --------------- | ----------- | ----------------------------- |
|
||||
| left_margin | CTRL-L | l[0-9]+ | |
|
||||
| right_margin | CTRL-R | r[0-9]+ | |
|
||||
| stick_to_left | <Left>, <Right> | s[01] | |
|
||||
| ignore_groups | CTRL-G | ig\[.*\] | `g:easy_align_ignore_groups` |
|
||||
| ignore_unmatched | CTRL-U | iu[01] | `g:easy_align_ignore_unmatched` |
|
||||
| indentation | CTRL-I | i[ksdn] | `g:easy_align_indentation` |
|
||||
| delimiter_align | CTRL-D | d[lrc] | `g:easy_align_delimiter_align` |
|
||||
| mode_sequence | CTRL-O | m[lrc*]+ | |
|
||||
|
||||
|
||||
Ignoring delimiters in comments or strings *g:easy_align_ignore_groups*
|
||||
@@ -407,7 +433,7 @@ settings as follows.
|
||||
Alignments over multiple occurrences of delimiters
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
As stated above, "field number" is used to target specific occurrences of
|
||||
As stated above, "N-th" parameter is used to target specific occurrences of
|
||||
the delimiter when it appears multiple times in each line.
|
||||
|
||||
To recap:
|
||||
|
||||
@@ -1064,3 +1064,12 @@ aaa, b,
|
||||
111 22 333 444 55555 6666 7 88888
|
||||
1111 2 33 444 555 66 777 8
|
||||
|
||||
a = 1
|
||||
bb = 2
|
||||
ccccc
|
||||
ddd = 3
|
||||
|
||||
a = 1
|
||||
bb = 2
|
||||
ccccc
|
||||
ddd = 3
|
||||
|
||||
@@ -1 +1 @@
|
||||
4Gvipjyvip
|
||||
4Gvipjyvip
|
||||
|
||||
@@ -94,3 +94,15 @@ banana = 'Gros Michel' # comment 2
|
||||
a()p()p()l()e();():()b()a()n()a()n()a():():()c()a()k()e(
|
||||
d()a()t()a();();()e()x()c()h()a()n()g()e():();()f()o()r()m()a()t(
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;;exchange :;format
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;; exchange :; format
|
||||
|
||||
apple;:banana ::cake
|
||||
data ;;exchange:;format
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;; exchange :; format
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
4Gvipjyvip:EasyAlign:
|
||||
4Gvipjyvip:EasyAlign:
|
||||
|
||||
Reference in New Issue
Block a user