29 Commits
2.4.2 ... 2.6.1

Author SHA1 Message Date
Junegunn Choi
013fb54dd1 Update documentation 2013-10-07 21:13:17 +09:00
Junegunn Choi
2bf1b2164d Allow shorthand option notation when using delimiter key
e.g. :EasyAlign=l2r2dlmlr**
2013-10-07 21:09:37 +09:00
Junegunn Choi
bab23a1917 Update documentation 2013-10-05 15:55:22 +09:00
Junegunn Choi
fa26fd7b42 Remove option value after every cycle 2013-10-05 15:27:50 +09:00
Junegunn Choi
a4a1e27395 Apply ignore_unmatched option on R/C mode if explicitly set
By default, unmatched trailing token from each line is also aligned in
right and center alignment modes unlike in left alignment mode. If
ignore_unmatched option is explicitly set to 1 by user, they will be ignored
even in right/center modes.
2013-10-05 12:23:44 +09:00
Junegunn Choi
98bd9fe6f0 Shorthand notation for ignore_groups/ignore_unmatched
e.g. ig['String']iu0
2013-10-04 02:29:24 +09:00
Junegunn Choi
f944f5bf29 Set g:easy_align_last_command 2013-10-04 02:07:35 +09:00
Junegunn Choi
484b4ba5ec Update doc 2013-10-04 01:50:43 +09:00
Junegunn Choi
9d3afa6206 Merge option values in dictionary and shortcut expression 2013-10-04 01:36:55 +09:00
Junegunn Choi
4c6a8c174d Implement shortcut expression for options 2013-10-03 21:59:51 +09:00
Junegunn Choi
3304f4e95a Make <Down> set both left and right margin to zero
(Undocumented) <Up> will clear *UP* left_margin, right_margin, and stick_to_left
2013-10-03 16:06:23 +09:00
Junegunn Choi
e4f86274e3 Update install instructions 2013-09-22 23:04:20 +09:00
Junegunn Choi
2d575bcc25 Underscore between parens 2013-09-22 22:56:27 +09:00
Junegunn Choi
8a783c2125 Fix a failure in test due to change in interactive mode 2013-09-22 22:21:23 +09:00
Junegunn Choi
5230a2402f Disallow 0 as the first character of N-th 2013-09-22 21:58:31 +09:00
Junegunn Choi
94a750e03e Remove unnecessary prev output wipe 2013-09-22 21:48:14 +09:00
Junegunn Choi
afc95b5ed7 Forgiving interactive mode: Do not terminate on invalid input 2013-09-22 21:17:02 +09:00
Junegunn Choi
1d2c58c06a Field index -> N-th parameter 2013-09-22 03:52:36 +09:00
Junegunn Choi
4cdc450126 Update DEMO.md 2013-09-21 23:53:47 +09:00
Junegunn Choi
7e1be152dc Add DEMO.md 2013-09-21 15:46:40 +09:00
Junegunn Choi
c61a11d150 Update doc
- Field number -> Field index
2013-09-21 13:08:55 +09:00
Junegunn Choi
2797baca6c Disallow non-printable character input 2013-09-21 12:04:56 +09:00
Junegunn Choi
663264ed39 Fix center-alignment
= = eee   = eee = f
= = gg  &&= gg
= = fff

= = eee   = eee = f
= = gg  &&= gg
= = f f
2013-09-21 03:31:34 +09:00
Junegunn Choi
df75520f72 Colored, replayable output 2013-09-21 03:11:20 +09:00
Junegunn Choi
a2d52611ee Fix invalid type conversion 2013-09-20 23:19:32 +09:00
Junegunn Choi
fce0a103ff Use try-finally for reverting the setup 2013-09-19 17:27:26 +09:00
Junegunn Choi
1752bf567b Improve message output
- Error message highlighting
- Wipe previous message if needed
- No line wrap on narrow terminal
2013-09-19 17:10:00 +09:00
Junegunn Choi
003194a47f Update example command sequences 2013-09-18 16:18:03 +09:00
Junegunn Choi
c1c6f32e8c Update example command sequence 2013-09-18 15:50:19 +09:00
9 changed files with 621 additions and 253 deletions

91
DEMO.md Normal file
View 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

View File

@@ -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>=`

188
README.md
View File

@@ -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
- ...
@@ -112,20 +114,21 @@ You can override these default rules or define your own rules with
#### Example command sequences
| With visual map | Description | Equivalent command |
| ------------------- | -------------------------------------------------------- | --------------------- |
| `<Enter><space>` | Alignment around 1st whitespaces | `:'<,'>EasyAlign\ ` |
| `<Enter>2<space>` | Alignment around 2nd whitespaces | `:'<,'>EasyAlign2\ ` |
| `<Enter>-<space>` | Alignment around the last whitespaces | `:'<,'>EasyAlign-\ ` |
| `<Enter>:` | Alignment around 1st colon | `:'<,'>EasyAlign:` |
| `<Enter>=` | Alignment around 1st equals signs (and the likes) | `:'<,'>EasyAlign=` |
| `<Enter>2=` | Alignment around 2nd equals signs (and the likes) | `:'<,'>EasyAlign2=` |
| `<Enter>3=` | Alignment around 3rd equals signs (and the likes) | `:'<,'>EasyAlign3=` |
| `<Enter>*=` | Alignment around all equals signs (and the likes) | `:'<,'>EasyAlign*=` |
| `<Enter>**=` | Left-right alternating alignment around all equals signs | `:'<,'>EasyAlign**=` |
| `<Enter><Enter>=` | Right alignment around 1st equals signs | `:'<,'>EasyAlign!=` |
| `<Enter><Enter>**=` | Right-left alternating alignment around all equals signs | `:'<,'>EasyAlign!**=` |
| ... | ... | |
| With visual map | Description | Equivalent command |
| ------------------- | ------------------------------------------------------- | ---------------------- |
| `<Enter><space>` | Alignment around 1st whitespaces | `:'<,'>EasyAlign\ ` |
| `<Enter>2<space>` | Alignment around 2nd whitespaces | `:'<,'>EasyAlign2\ ` |
| `<Enter>-<space>` | Alignment around the last whitespaces | `:'<,'>EasyAlign-\ ` |
| `<Enter>-2<space>` | Alignment around the 2nd to last whitespaces | `:'<,'>EasyAlign-2\ ` |
| `<Enter>:` | Alignment around 1st colon (`key: value`) | `:'<,'>EasyAlign:` |
| `<Enter><Right>:` | Alignment around 1st colon (`key : value`) | `:'<,'>EasyAlign:s0l1` |
| `<Enter>=` | Alignment around 1st operators with = | `:'<,'>EasyAlign=` |
| `<Enter>2=` | Alignment around 2nd operators with = | `:'<,'>EasyAlign2=` |
| `<Enter>3=` | Alignment around 3rd operators with = | `:'<,'>EasyAlign3=` |
| `<Enter>*=` | Alignment around all operators with = | `:'<,'>EasyAlign*=` |
| `<Enter>**=` | Left-right alternating alignment around all = operators | `:'<,'>EasyAlign**=` |
| `<Enter><Enter>=` | Right alignment around 1st equals signs | `:'<,'>EasyAlign!=` |
| `<Enter><Enter>**=` | Right-left alternating alignment around all = operators | `:'<,'>EasyAlign!**=` |
#### Using regular expressions
@@ -155,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>
```
---
@@ -168,17 +179,17 @@ Go try out vim-easy-align right now, and come back later when you feel like it.
---
### Non-interactive mode
### Using `EasyAlign` in command line
Instead of going into the interactive mode, you can type in arguments to
Instead of going into the interactive mode, you can just 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,
@@ -212,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. 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>`
- `*`
@@ -246,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
-----------------
@@ -270,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
@@ -331,7 +360,7 @@ You can change the default rule by using one of these 4 methods.
2. Define global `g:easy_align_ignore_groups` list
3. Define a custom rule in `g:easy_align_delimiters` with `ignore_groups` option
4. Provide `ignore_groups` option to `:EasyAlign` command.
e.g. `:EasyAlign:{'ig':[]}`
e.g. `:EasyAlign:ig[]`
For example if you set `ignore_groups` option to be an empty list, you get
@@ -350,10 +379,18 @@ Satisfied? :satisfied:
### Ignoring unmatched lines
Lines without any matching delimiter are ignored as well (except in
right-align mode).
`ignore_unmatched` option determines how EasyAlign command processes lines that
do not have N-th delimiter.
For example, when aligning the following code block around the colons,
1. In left-alignment mode, they are ignored
2. In right or center-alignment mode, they are *not* ignored, and the last
tokens from those lines are aligned as well as if there is an invisible
trailing delimiter at the end of each line
3. If `ignore_unmatched` is 1, they are ignored regardless of the alignment mode
4. If `ignore_unmatched` is 0, they are *not* ignored regardless of the mode
Let's take an example.
When we align the following code block around the (1st) colons,
```ruby
{
@@ -377,13 +414,13 @@ this is usually what we want.
}
```
However, this default behavior is also configurable by using one of these 4
methods.
However, we can override this default behavior by setting `ignore_unmatched`
option to zero using one of the following methods.
1. Press `CTRL-U` in interactive mode to toggle `ignore_unmatched` option
2. Set the global `g:easy_align_ignore_unmatched` variable to 0
3. Define a custom alignment rule with `ignore_unmatched` option set to 0
4. Provide `ignore_unmatched` option to `:EasyAlign` command. e.g. `:EasyAlign:{'iu':0}`
4. Provide `ignore_unmatched` option to `:EasyAlign` command. e.g. `:EasyAlign:iu0`
Then we get,
@@ -417,7 +454,7 @@ banana += apple
cake ||= banana
```
However, with `:EasyAlign={'da':l}`, delimiters are left-aligned.
However, with `:EasyAlign=dl`, delimiters are left-aligned.
```ruby
apple = 1
@@ -425,7 +462,7 @@ banana += apple
cake ||= banana
```
And on `:EasyAlign={'da':c}`, center-aligned.
And on `:EasyAlign=dc`, center-aligned.
```ruby
apple = 1
@@ -457,7 +494,7 @@ then again we have `indentation` option. See the following example.
eggplant = 5
# Use the _s_hallowest indentation among the lines
# :EasyAlign={'idt':s}
# :EasyAlign=is
apple = 1
banana = 2
cake = 3
@@ -465,7 +502,7 @@ then again we have `indentation` option. See the following example.
eggplant = 5
# Use the _d_eepest indentation among the lines
# :EasyAlign={'idt':d}
# :EasyAlign=id
apple = 1
banana = 2
cake = 3
@@ -473,7 +510,7 @@ then again we have `indentation` option. See the following example.
eggplant = 5
# Indentation: _n_one
# :EasyAlign={'idt':n}
# :EasyAlign=in
apple = 1
banana = 2
cake = 3
@@ -485,29 +522,9 @@ Notice that `idt` is fuzzy-matched to `indentation`.
In interactive mode, you can change the option value with `CTRL-I` key.
### Left/right/center mode switch in interactive mode
In interactive mode, you can choose the alignment mode you want by pressing
enter keys. The non-bang command, `:EasyAlign` starts in left-alignment mode
and changes to right and center mode as you press enter keys, while the bang
version first starts in right-alignment mode.
- `:EasyAlign`
- Left, Right, Center
- `:EasyAlign!`
- Right, Left, Center
If you do not prefer this default mode transition, you can define your own
settings as follows.
```vim
let g:easy_align_interactive_modes = ['l', 'r']
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:
@@ -543,24 +560,27 @@ in interactive mode with the special key `CTRL-O`)
" Right, left, center alignment over the 1st to 3rd occurrences of delimiters
:EasyAlign = { 'm': 'rlc' }
" Using shorthand notation
:EasyAlign = mrlc
" Right, left, center alignment over the 2nd to 4th occurrences of delimiters
:EasyAlign 2={ 'm': 'rlc' }
:EasyAlign 2=mrlc
" (*) Repeating alignments (default: l, r, or c)
" Right, left, center, center, center, center, ...
:EasyAlign *={ 'm': 'rlc' }
:EasyAlign *=mrlc
" (**) Alternating alignments (default: lr or rl)
" Right, left, center, right, left, center, ...
:EasyAlign **={ 'm': 'rlc' }
:EasyAlign **=mrlc
" Right, left, center, center, center, ... repeating alignment
" over the 3rd to the last occurrences of delimiters
:EasyAlign 3={ 'm': 'rlc*' }
:EasyAlign 3=mrlc*
" Right, left, center, right, left, center, ... alternating alignment
" over the 3rd to the last occurrences of delimiters
:EasyAlign 3={ 'm': 'rlc**' }
:EasyAlign 3=mrlc**
```
### Extending alignment rules

View File

@@ -49,10 +49,17 @@ 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 = {
\ 'margin_left': 'lm', 'margin_right': 'rm', 'stick_to_left': 'stl',
\ 'left_margin': 'lm', 'right_margin': 'rm', 'indentation': 'idt',
\ 'ignore_groups': 'ig', 'ignore_unmatched': 'iu', 'delimiter_align': 'da',
\ 'mode_sequence': 'm', 'ignores': 'ig'
\ }
if exists("*strwidth")
@@ -88,14 +95,58 @@ function! s:ignored_syntax()
endif
endfunction
function! s:echon(l, n, d, o)
echon "\r"
echon "\rEasyAlign". s:mode_labels[a:l] ." (" .a:n.a:d. ")"
\ . (empty(a:o) ? '' : ' '.string(a:o))
function! s:echon_(tokens)
" http://vim.wikia.com/wiki/How_to_print_full_screen_width_messages
let xy = [&ruler, &showcmd]
try
set noruler noshowcmd
let winlen = winwidth(winnr()) - 2
let len = len(join(map(copy(a:tokens), 'v:val[1]'), ''))
let ellipsis = len > winlen ? '..' : ''
echon "\r"
let yet = 0
for [hl, msg] in a:tokens
if empty(msg) | continue | endif
execute "echohl ". hl
let yet += len(msg)
if yet > winlen - len(ellipsis)
echon msg[ 0 : (winlen - len(ellipsis) - yet - 1) ] . ellipsis
break
else
echon msg
endif
endfor
finally
echohl None
let [&ruler, &showcmd] = xy
endtry
endfunction
function! s:echon(l, n, r, d, o, warn)
let tokens = [
\ ['Function', ':EasyAlign'],
\ ['ModeMsg', get(s:mode_labels, a:l, a:l)],
\ ['None', ' ']]
if a:r == -1 | call add(tokens, ['Comment', '(']) | endif
call add(tokens, [a:n =~ '*' ? 'Repeat' : 'Number', a:n])
call extend(tokens, a:r == 1 ?
\ [['Delimiter', '/'], ['String', a:d], ['Delimiter', '/']] :
\ [['Identifier', a:d == ' ' ? '\ ' : (a:d == '\' ? '\\' : a:d)]])
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)
echon "\r". a:msg
call s:echon_([['ErrorMsg', a:msg]])
throw 'exit'
endfunction
@@ -108,7 +159,7 @@ function! s:rtrim(str)
endfunction
function! s:trim(str)
return substitute(a:str, '^\s*\(\S*\)\s*$', '\1', '')
return substitute(a:str, '^\s*\(.\{-}\)\s*$', '\1', '')
endfunction
function! s:fuzzy_lu(key)
@@ -166,6 +217,14 @@ function! s:normalize_options(opts)
return s:validate_options(ret)
endfunction
function! s:compact_options(opts)
let ret = {}
for k in keys(a:opts)
let ret[s:shorthand[k]] = a:opts[k]
endfor
return ret
endfunction
function! s:validate_options(opts)
for k in keys(a:opts)
let v = a:opts[k]
@@ -253,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
@@ -302,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
@@ -492,23 +554,35 @@ function! s:input(str, default, vis)
call inputsave()
let got = input(a:str, a:default)
call inputrestore()
try
return eval(got)
catch
return got
endtry
return got
endfunction
function! s:interactive(modes, vis)
function! s:atoi(str)
return (a:str =~ '^[0-9]\+$') ? str2nr(a:str) : a:str
endfunction
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 = {}
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, '', opts)
call s:echon(mode, n, -1, '', opts, warn)
let check = 0
let warn = ''
let c = getchar()
let ch = nr2char(c)
@@ -526,39 +600,55 @@ function! s:interactive(modes, vis)
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: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: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
@@ -570,16 +660,93 @@ function! s:interactive(modes, vis)
silent! call remove(opts, 'm')
endif
elseif ch == "\<C-_>" || ch == "\<C-X>"
let ch = s:input('Regular expression: ', '', a:vis)
if !empty(ch)
let prompt = 'Regular expression: '
let ch = s:input(prompt, '', a:vis)
if !empty(ch) && s:valid_regexp(ch)
let regx = 1
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, opts, s:normalize_options(opts), regx]
return [mode, n, ch, s:normalize_options(opts), regx]
endfunction
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
let s:shorthand_regex =
\ '\s*\('
\ .'\(lm\?[0-9]\+\)\|\(rm\?[0-9]\+\)\|\(iu[01]\)\|\(s\%(tl\)\?[01]\)\|'
\ .'\(da\?[clr]\)\|\(ms\?[lrc*]\+\)\|\(i\%(dt\)\?[kdsn]\)\|\(ig\[.*\]\)'
\ .'\)\+\s*$'
function! s:parse_shorthand_opts(expr)
let opts = {}
let expr = substitute(a:expr, '\s', '', 'g')
let regex = '^'. s:shorthand_regex
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)')
for key in ['lm', 'rm', 'l', 'r', 'stl', 's', 'iu', 'da', 'd', 'ms', 'm', 'ig', 'i']
if stridx(tolower(m), key) == 0
let rest = strpart(m, len(key))
if key == 'i' | let key = 'idt' | endif
if key == 'idt' || index(['d', 'm'], key[0]) >= 0
let opts[key] = rest
elseif key == 'ig'
try
let arr = eval(rest)
if type(arr) == 3
let opts[key] = arr
else
throw 'Not an array'
endif
catch
call s:exit("Invalid ignore_groups: ". a:expr)
endtry
else
let opts[key] = str2nr(rest)
endif
break
endif
endfor
endfor
endif
return s:normalize_options(opts)
endfunction
function! s:parse_args(args)
@@ -621,77 +788,88 @@ function! s:parse_args(args)
let opts = s:normalize_options(opts)
endif
" Shorthand option notation
let sopts = matchstr(args, s:shorthand_regex)
if !empty(sopts)
let args = strpart(args, 0, len(args) - len(sopts))
let opts = extend(s:parse_shorthand_opts(sopts), opts)
endif
" Has /Regexp/?
let matches = matchlist(args, '^\(.\{-}\)\s*/\(.*\)/\s*$')
" Found regexp
if !empty(matches)
let regexp = matches[2]
" Test regexp
try | call matchlist('', regexp)
catch | call s:exit("Invalid regular expression: ". regexp)
endtry
return [matches[1], regexp, opts, 1]
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]
endif
endfunction
function! s:modes(bang)
return get(g:,
\ (a:bang ? 'easy_align_bang_interactive_modes' : 'easy_align_interactive_modes'),
\ (a:bang ? ['r', 'l', 'c'] : ['l', 'r', 'c']))
endfunction
function! s:alternating_modes(mode)
return a:mode ==? 'r' ? ['r', 'l'] : ['l', 'r']
endfunction
function! easy_align#align(bang, expr) range
let modes = get(g:,
\ (a:bang ? 'easy_align_bang_interactive_modes' : 'easy_align_interactive_modes'),
\ (a:bang ? ['r', 'l', 'c'] : ['l', 'r', 'c']))
try
call s:align(a:bang, a:firstline, a:lastline, a:expr)
catch 'exit'
endtry
endfunction
function! s:align(bang, first_line, last_line, expr)
let modes = s:modes(a:bang)
let mode = modes[0]
let recur = 0
let n = ''
let ch = ''
let opts = {}
let ioptsr = {}
let iopts = {}
let regexp = 0
" Heuristically determine if the user was in visual mode
let vis = a:firstline == line("'<") && a:lastline == line("'>")
let vis = a:first_line == line("'<") && a:last_line == line("'>")
try
if empty(a:expr)
let [mode, n, ch, ioptsr, iopts, regexp] = s:interactive(copy(modes), vis)
else
let [n, ch, opts, regexp] = s:parse_args(a:expr)
if empty(n) && empty(ch)
let [mode, n, ch, ioptsr, iopts, regexp] = s:interactive(copy(modes), vis)
elseif empty(ch)
" Try swapping n and ch
let [n, ch] = ['', 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 empty(a:expr)
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, delimiters)
elseif empty(ch)
" Try swapping n and ch
let [n, ch] = ['', n]
endif
catch 'exit'
return
endtry
endif
if n == '*' | let [nth, recur] = [1, 1]
elseif n == '**' | let [nth, recur] = [1, 2]
elseif n == '-' | let nth = -1
elseif empty(n) | let nth = 1
elseif n == '0' || ( n != '-0' && n != string(str2nr(n)) )
echon "\rInvalid field number: ". n
return
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
let dict = { 'pattern': ch }
else
" Resolving command-line ambiguity
if !empty(a:expr)
" '\ ' => ' '
if ch =~ '^\\\s\+$'
" '\' => ' '
if ch =~ '^\\\s*$'
let ch = ' '
" '\\' => '\'
elseif ch =~ '^\\\\\s*$'
@@ -699,17 +877,12 @@ function! easy_align#align(bang, expr) range
endif
endif
if !has_key(delimiters, ch)
echon "\rUnknown delimiter key: ". ch
return
call s:exit('Unknown delimiter key: '. ch)
endif
let dict = delimiters[ch]
let dict = copy(delimiters[ch])
endif
for opt in [opts, iopts]
if !empty(opt)
let dict = extend(copy(dict), opt)
endif
endfor
call extend(dict, opts)
let ml = get(dict, 'left_margin', ' ')
let mr = get(dict, 'right_margin', ' ')
@@ -719,12 +892,11 @@ function! easy_align#align(bang, expr) range
let bvisual = vis && char2nr(visualmode()) == 22 " ^V
if recur && bvisual
echon "\rRecursive alignment is currently not supported in blockwise-visual mode"
return
call s:exit('Recursive alignment is not supported in blockwise-visual mode')
endif
let aseq = get(dict, 'mode_sequence',
\ recur == 2 ? (mode ==? 'r' ? ['r', 'l'] : ['l', 'r']) : [mode])
\ recur == 2 ? s:alternating_modes(mode) : [mode])
let mode_expansion = matchstr(aseq, '\*\+$')
if mode_expansion == '*'
let aseq = aseq[0 : -2]
@@ -734,11 +906,11 @@ function! easy_align#align(bang, expr) range
let recur = 2
endif
let aseq_list = type(aseq) == 1 ? split(tolower(aseq), '\s*') : map(copy(aseq), 'tolower(v:val)')
let aseq_str = join(aseq_list, '')
try
call s:do_align(
call s:do_align(
\ aseq_list,
\ {}, {}, a:firstline, a:lastline,
\ {}, {}, a:first_line, a:last_line,
\ bvisual ? min([col("'<"), col("'>")]) : 1,
\ bvisual ? max([col("'<"), col("'>")]) : 0,
\ get(dict, 'pattern', ch),
@@ -748,11 +920,18 @@ function! easy_align#align(bang, expr) range
\ 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)
call s:echon(mode, n, regexp ? '/'.ch.'/' : ch, ioptsr)
catch 'exit'
endtry
let copts = s:compact_options(opts)
let nbmode = s:modes(0)[0]
if !has_key(copts, 'm') && (
\ (recur == 2 && join(s:alternating_modes(nbmode), '') != aseq_str) ||
\ (recur != 2 && (aseq_str[0] != nbmode || len(aseq_str) > 1))
\ )
call extend(copts, { 'm': aseq_str })
endif
let g:easy_align_last_command = s:echon('', n, regexp, ch, copts, '')
endfunction

View File

@@ -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,49 @@ 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
Left/right/center mode switch in interactive mode
-------------------------------------------------------------------------
*g:easy_align_interactive_modes*
*g:easy_align_bang_interactive_modes*
In interactive mode, you can choose the alignment mode you want by pressing
enter keys. The non-bang command, `:EasyAlign` starts in left-alignment mode
and changes to right and center mode as you press enter keys, while the bang
version first starts in right-alignment mode.
- `:EasyAlign`
- Left, Right, Center
- `:EasyAlign!`
- Right, Left, Center
If you do not prefer this default mode transition, you can define your own
settings as follows.
let g:easy_align_interactive_modes = ['l', 'r']
let g:easy_align_bang_interactive_modes = ['c', 'r']
Using EasyAlign in 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 +148,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 +166,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. 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 +223,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*
@@ -239,7 +287,7 @@ You can change the default rule by using one of these 4 methods.
2. Define global `g:easy_align_ignore_groups` list
3. Define a custom rule in `g:easy_align_delimiters` with 'ignore_groups' option
4. Provide 'ignore_groups' option to `:EasyAlign` command.
e.g. :EasyAlign:{'is':[]}
e.g. :EasyAlign:ig[]
For example if you set 'ignore_groups' option to be an empty list, you get
@@ -256,10 +304,18 @@ For example if you set 'ignore_groups' option to be an empty list, you get
Ignoring unmatched lines *g:easy_align_ignore_unmatched*
-------------------------------------------------------------------------
Lines without any matching delimiter are ignored as well (except in
right-align mode).
'ignore_unmatched' option determines how EasyAlign command processes lines that
do not have N-th delimiter.
For example, when aligning the following code block around the colons,
1. In left-alignment mode, they are ignored
2. In right or center-alignment mode, they are not ignored, and the last
tokens from those lines are aligned as well as if there is an invisible
trailing delimiter at the end of each line
3. If 'ignore_unmatched' is 1, they are ignored regardless of the alignment mode
4. If 'ignore_unmatched' is 0, they are not ignored regardless of the mode
Let's take an example.
When we align the following code block around the (1st) colons,
{
apple: proc {
@@ -279,14 +335,14 @@ this is usually what we want.
grapefruits: 3
}
However, this default behavior is also configurable by using one of these 4
methods.
However, we can override this default behavior by setting 'ignore_unmatched'
option to zero using one of the following methods.
1. Press CTRL-U in interactive mode to toggle 'ignore_unmatched' option
2. Set the global `g:easy_align_ignore_unmatched` variable to 0
3. Define a custom alignment rule with 'ignore_unmatched' option set to 0
4. Provide 'ignore_unmatched' option to `:EasyAlign` command.
e.g. :EasyAlign:{'iu':0}
e.g. :EasyAlign:iu0
Then we get,
@@ -316,13 +372,13 @@ By default, delimiters are right-aligned as follows.
banana += apple
cake ||= banana
However, with ':EasyAlign={'da':l}', delimiters are left-aligned.
However, with ':EasyAlign=dl', delimiters are left-aligned.
apple = 1
banana += apple
cake ||= banana
And on ':EasyAlign={'da':c}', center-aligned.
And on ':EasyAlign=dc', center-aligned.
apple = 1
banana += apple
@@ -353,7 +409,7 @@ But then again we have 'indentation' option. See the following example.
eggplant = 5
# Use the _s_hallowest indentation among the lines
# :EasyAlign={'idt':s}
# :EasyAlign=is
apple = 1
banana = 2
cake = 3
@@ -361,7 +417,7 @@ But then again we have 'indentation' option. See the following example.
eggplant = 5
# Use the _d_eepest indentation among the lines
# :EasyAlign={'idt':d}
# :EasyAlign=id
apple = 1
banana = 2
cake = 3
@@ -369,7 +425,7 @@ But then again we have 'indentation' option. See the following example.
eggplant = 5
# Indentation: _n_one
# :EasyAlign={'idt':n}
# :EasyAlign=in
apple = 1
banana = 2
cake = 3
@@ -382,32 +438,10 @@ Notice that 'idt' is fuzzy-matched to 'indentation'.
In interactive mode, you can change the option value with `CTRL-I` key.
Left/right/center mode switch in interactive mode
-------------------------------------------------------------------------
*g:easy_align_interactive_modes*
*g:easy_align_bang_interactive_modes*
In interactive mode, you can choose the alignment mode you want by pressing
enter keys. The non-bang command, `:EasyAlign` starts in left-alignment mode
and changes to right and center mode as you press enter keys, while the bang
version first starts in right-alignment mode.
- `:EasyAlign`
- Left, Right, Center
- `:EasyAlign!`
- Right, Left, Center
If you do not prefer this default mode transition, you can define your own
settings as follows.
let g:easy_align_interactive_modes = ['l', 'r']
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:
@@ -440,24 +474,27 @@ in interactive mode with the special key CTRL-O)
" Right, left, center alignment over the 1st to 3rd occurrences of delimiters
:EasyAlign = { 'm': 'rlc' }
" Using shorthand notation
:EasyAlign = mrlc
" Right, left, center alignment over the 2nd to 4th occurrences of delimiters
:EasyAlign 2={ 'm': 'rlc' }
:EasyAlign 2=mrlc
" (*) Repeating alignments (default: l, r, or c)
" Right, left, center, center, center, center, ...
:EasyAlign *={ 'm': 'rlc' }
:EasyAlign *=mrlc
" (**) Alternating alignments (default: lr or rl)
" Right, left, center, right, left, center, ...
:EasyAlign **={ 'm': 'rlc' }
:EasyAlign **=mrlc
" Right, left, center, center, center, ... repeating alignment
" over the 3rd to the last occurrences of delimiters
:EasyAlign 3={ 'm': 'rlc*' }
:EasyAlign 3=mrlc*
" Right, left, center, right, left, center, ... alternating alignment
" over the 3rd to the last occurrences of delimiters
:EasyAlign 3={ 'm': 'rlc**' }
:EasyAlign 3=mrlc**
Extending alignment rules *g:easy_align_delimiters*

View File

@@ -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

View File

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

View File

@@ -94,3 +94,35 @@ 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
a+= 1
bb==# 2
ccc= 3
dddd=> 4
apple;: banana:: cake
data;; exchange:; format
```ruby
apple = 1 # comment not aligned
apricot = 'DAD' + 'F#AD'
banana = 'Gros Michel' # comment 2
```
```ruby
apple = 1 # comment not aligned
apricot = 'DAD' + 'F#AD'
banana = 'Gros Michel' # comment 2
```

View File

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