mirror of
https://github.com/junegunn/vim-easy-align.git
synced 2025-11-17 14:23:42 -05:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc9555cd65 | ||
|
|
a98c1ccc99 | ||
|
|
0aa6289d8c | ||
|
|
cc8966c0a5 | ||
|
|
da281d78d3 | ||
|
|
8e8629c0cd | ||
|
|
a9f593fdf8 | ||
|
|
d87ea32cfe | ||
|
|
11a6b03e7e | ||
|
|
ba54df53ca | ||
|
|
d041e17bba | ||
|
|
2ab86911cb | ||
|
|
4929841a7a | ||
|
|
12792cd60f | ||
|
|
f7213f30f3 | ||
|
|
f44c325aa2 | ||
|
|
dc4786841e | ||
|
|
46abd8fb92 | ||
|
|
af39e544ca | ||
|
|
49c7133328 | ||
|
|
4298395085 | ||
|
|
e7fca89dde | ||
|
|
4b706efeb3 | ||
|
|
9bb987599a | ||
|
|
b8e93f96b8 | ||
|
|
6d85e93476 | ||
|
|
9271fc3f8f | ||
|
|
d3eec7fa8b | ||
|
|
62387b78e0 | ||
|
|
f400e4d8d1 | ||
|
|
9716fb3917 | ||
|
|
353ae9b071 | ||
|
|
ba4ba6e3c4 | ||
|
|
da284f908e | ||
|
|
8d4d5b7941 | ||
|
|
165bda1d95 | ||
|
|
ddc1e00b81 | ||
|
|
462a800064 | ||
|
|
3921d0bab3 | ||
|
|
ea1ea51ef1 | ||
|
|
2daae46a43 | ||
|
|
2b119f9bb6 | ||
|
|
15bcbc9499 | ||
|
|
54e6b5d866 | ||
|
|
1f28ce346e | ||
|
|
2832a76cea | ||
|
|
1a232ac19b | ||
|
|
a76cfdb8ae | ||
|
|
c3a7842b0d | ||
|
|
3cc564bd68 | ||
|
|
6e2264672a | ||
|
|
bec3e94383 | ||
|
|
7f0fccba0b | ||
|
|
aa62ca4603 | ||
|
|
831cecdaf2 | ||
|
|
37fa908d04 | ||
|
|
256e5b83ab | ||
|
|
cb7306341c | ||
|
|
7b82a1e496 | ||
|
|
ad2df21039 | ||
|
|
4c2808d13c | ||
|
|
124654ec46 | ||
|
|
ab4b72addf | ||
|
|
cdc648f5a4 | ||
|
|
438b5312ee | ||
|
|
e24f8479a5 | ||
|
|
9d626dd765 | ||
|
|
7490aa61d7 | ||
|
|
aa42666f10 | ||
|
|
9951cad2d0 | ||
|
|
cb5041ba67 | ||
|
|
7019edb08c | ||
|
|
247f69bf3f | ||
|
|
133588b181 | ||
|
|
fb8cf1d54a | ||
|
|
013fb54dd1 | ||
|
|
2bf1b2164d |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,3 +1,4 @@
|
||||
.travis.yml export-ignore
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
doc/tags export-ignore
|
||||
|
||||
13
.travis.yml
Normal file
13
.travis.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
language: vim
|
||||
|
||||
before_script: |
|
||||
git clone https://github.com/junegunn/vader.vim.git
|
||||
|
||||
script: |
|
||||
vim -Nu <(cat << VIMRC
|
||||
filetype off
|
||||
set rtp+=vader.vim
|
||||
set rtp+=.
|
||||
set rtp+=after
|
||||
filetype plugin indent on
|
||||
VIMRC) -c 'Vader! test/*' > /dev/null
|
||||
11
EXAMPLES.md
11
EXAMPLES.md
@@ -3,10 +3,14 @@ vim-easy-align examples
|
||||
|
||||
Open this document in your Vim and try it yourself.
|
||||
|
||||
This document assumes that you have defined the following mapping.
|
||||
This document assumes that you have defined the following mappings.
|
||||
|
||||
```vim
|
||||
vnoremap <silent> <Enter> :EasyAlign<cr>
|
||||
" Start interactive EasyAlign in visual mode (e.g. vip<Enter>)
|
||||
vmap <Enter> <Plug>(EasyAlign)
|
||||
|
||||
" Start interactive EasyAlign for a motion/text object (e.g. <Leader>aip)
|
||||
nmap <Leader>a <Plug>(EasyAlign)
|
||||
```
|
||||
|
||||
To enable syntax highlighting in the code blocks, define and call the following
|
||||
@@ -214,6 +218,9 @@ This only works when syntax highlighting is enabled.
|
||||
Aligning in-line comments
|
||||
-------------------------
|
||||
|
||||
*Note: Since the current version provides '#'-rule as one of the default rules,
|
||||
you can ignore this section.*
|
||||
|
||||
```ruby
|
||||
apple = 1 # comment not aligned
|
||||
banana = 'Gros Michel' # comment 2
|
||||
|
||||
426
README.md
426
README.md
@@ -6,9 +6,9 @@ A simple, easy-to-use Vim alignment plugin.
|
||||
Demo
|
||||
----
|
||||
|
||||

|
||||

|
||||
|
||||
(Too fast? Slower GIF is [here](https://raw.github.com/junegunn/vim-easy-align/gif/vim-easy-align-slow.gif))
|
||||
(Too fast? Slower GIF is [here](https://raw.github.com/junegunn/i/master/vim-easy-align-slow.gif))
|
||||
|
||||
Features
|
||||
--------
|
||||
@@ -37,54 +37,108 @@ and extract in ~/.vim or
|
||||
[plugin](https://github.com/Shougo/neobundle.vim)
|
||||
[manager](https://github.com/MarcWeber/vim-addon-manager).
|
||||
|
||||
- [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`
|
||||
1. Add `Plugin 'junegunn/vim-easy-align'` to .vimrc
|
||||
2. Run `:PluginInstall`
|
||||
- [vim-plug](https://github.com/junegunn/vim-plug)
|
||||
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 (e.g. vip<Enter>)
|
||||
vmap <Enter> <Plug>(EasyAlign)
|
||||
|
||||
" Start interactive EasyAlign for a motion/text object (e.g. <Leader>aip)
|
||||
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). Install
|
||||
[visualrepeat](https://github.com/vim-scripts/visualrepeat) as well if you want
|
||||
to repeat in visual mode.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
_vim-easy-align_ defines `:EasyAlign` command (and the right-align
|
||||
variant `:EasyAlign!`) for visual mode.
|
||||
|
||||
| Mode | Command |
|
||||
| ------------------------- | ------------------------------------------------ |
|
||||
| Interactive mode | `:EasyAlign[!] [OPTIONS]` |
|
||||
| Using predefined rules | `:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]` |
|
||||
| Using regular expressions | `:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]` |
|
||||
|
||||
### Concept of _alignment rule_
|
||||
|
||||
Though easy-align can align lines of text around any delimiter, it provides
|
||||
shortcuts for the most common use cases with the concept of "_alignment rule_".
|
||||
|
||||
An *alignment rule* is a predefined set of options for common alignment tasks,
|
||||
which is identified by a single character, *DELIMITER KEY*, such as `<space>`,
|
||||
`=`, `:`, `.`, `|`, and `,`.
|
||||
which is identified by a single character, *DELIMITER KEY*, such as `<Space>`,
|
||||
`=`, `:`, `.`, `|`, `&`, `#`, and `,`.
|
||||
|
||||
Think of it as a shortcut. Instead of writing regular expression and setting
|
||||
several options, you can just type in a single character.
|
||||
|
||||
### Execution models
|
||||
|
||||
There are two ways to use easy-align.
|
||||
|
||||
#### 1. Using `<Plug>` mappings
|
||||
|
||||
The recommended method is to use `<Plug>` mappings as described earlier.
|
||||
|
||||
| Mapping | Mode | Description |
|
||||
| ----------------------- | ------ | ---------------------------------------------------- |
|
||||
| `<Plug>(EasyAlign)` | normal | Start interactive mode for a motion/text object |
|
||||
| `<Plug>(EasyAlign)` | visual | Start interactive mode for the selection |
|
||||
| `<Plug>(LiveEasyAlign)` | normal | Start live-interactive mode for a motion/text object |
|
||||
| `<Plug>(LiveEasyAlign)` | visual | Start live-interactive mode for the selection |
|
||||
|
||||
#### 2. Using `:EasyAlign` command
|
||||
|
||||
If you prefer command-line or do not want to start interactive mode, you can use
|
||||
`:EasyAlign` command instead.
|
||||
|
||||
| Mode | Command |
|
||||
| ------------------------------------------ | ------------------------------------------------ |
|
||||
| Interactive mode | `:EasyAlign[!] [OPTIONS]` |
|
||||
| Live interactive mode | `:LiveEasyAlign[!] [...]` |
|
||||
| Non-interactive mode (predefined rules) | `:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]` |
|
||||
| Non-interactive mode (regular expressions) | `:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]` |
|
||||
|
||||
### 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
|
||||
your `.vimrc`.
|
||||
The following sections will assume that you have `<Plug>(EasyAlign)` mappings in
|
||||
your .vimrc as below:
|
||||
|
||||
```vim
|
||||
vnoremap <silent> <Enter> :EasyAlign<Enter>
|
||||
" Start interactive EasyAlign in visual mode (e.g. vip<Enter>)
|
||||
vmap <Enter> <Plug>(EasyAlign)
|
||||
|
||||
" Start interactive EasyAlign for a motion/text object (e.g. <Leader>aip)
|
||||
nmap <Leader>a <Plug>(EasyAlign)
|
||||
```
|
||||
|
||||
(Of course you can use any key combination as the trigger. e.g. `<Leader>a`)
|
||||
With these mappings, you can align text with only a few keystrokes.
|
||||
|
||||
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 in visual mode, or `<Leader>a` followed by a motion or a text
|
||||
object to start interactive mode
|
||||
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
|
||||
@@ -95,40 +149,41 @@ With the mapping, you can align selected lines of text with only a few keystroke
|
||||
- `-` Around the last occurrences of delimiters (`-1`)
|
||||
- `-2` Around the second to last occurrences of delimiters
|
||||
- ...
|
||||
1. Delimiter key (a single keystroke; `<space>`, `=`, `:`, `.`, `|`, `,`)
|
||||
1. Delimiter key (a single keystroke; `<Space>`, `=`, `:`, `.`, `|`, `&`, `#`, `,`)
|
||||
|
||||
Alignment rules for the following delimiters have been defined to meet the most needs.
|
||||
#### Predefined alignment rules
|
||||
|
||||
| Delimiter key | Description/Use cases |
|
||||
| ------------- | -------------------------------------------------------------------- |
|
||||
| `<space>` | General alignment around whitespaces |
|
||||
| `<Space>` | General alignment around whitespaces |
|
||||
| `=` | Operators containing equals sign (`=`, `==,` `!=`, `+=`, `&&=`, ...) |
|
||||
| `:` | Suitable for formatting JSON or YAML |
|
||||
| `.` | Multi-line method chaining |
|
||||
| `,` | Multi-line method arguments |
|
||||
| | | Table markdown |
|
||||
| `&` | LaTeX tables (matches `&` and `\\`) |
|
||||
| `#` | Ruby/Python comments |
|
||||
| `<Bar>` | Table markdown |
|
||||
|
||||
You can override these default rules or define your own rules with
|
||||
`g:easy_align_delimiters`, which will be described in
|
||||
[the later section](https://github.com/junegunn/vim-easy-align#extending-alignment-rules).
|
||||
|
||||
#### Example command sequences
|
||||
#### Examples
|
||||
|
||||
| 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:{'s':0,'l':1}` |
|
||||
| `<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!**=` |
|
||||
| With visual map | Description | Equivalent command |
|
||||
| ------------------- | ---------------------------------- | ---------------------- |
|
||||
| `<Enter><Space>` | Around 1st whitespaces | `:'<,'>EasyAlign\ ` |
|
||||
| `<Enter>2<Space>` | Around 2nd whitespaces | `:'<,'>EasyAlign2\ ` |
|
||||
| `<Enter>-<Space>` | Around the last whitespaces | `:'<,'>EasyAlign-\ ` |
|
||||
| `<Enter>-2<Space>` | Around the 2nd to last whitespaces | `:'<,'>EasyAlign-2\ ` |
|
||||
| `<Enter>:` | Around 1st colon (`key: value`) | `:'<,'>EasyAlign:` |
|
||||
| `<Enter><Right>:` | Around 1st colon (`key : value`) | `:'<,'>EasyAlign:s0l1` |
|
||||
| `<Enter>=` | Around 1st operators with = | `:'<,'>EasyAlign=` |
|
||||
| `<Enter>3=` | Around 3rd operators with = | `:'<,'>EasyAlign3=` |
|
||||
| `<Enter>*=` | Around all operators with = | `:'<,'>EasyAlign*=` |
|
||||
| `<Enter>**=` | Left-right alternating around = | `:'<,'>EasyAlign**=` |
|
||||
| `<Enter><Enter>=` | Right alignment around 1st = | `:'<,'>EasyAlign!=` |
|
||||
| `<Enter><Enter>**=` | Right-left alternating around = | `:'<,'>EasyAlign!**=` |
|
||||
|
||||
#### Using regular expressions
|
||||
|
||||
@@ -138,7 +193,7 @@ For example, if you want to align text around all occurrences of numbers:
|
||||
|
||||
- `<Enter>`
|
||||
- `*`
|
||||
- `<CTRL-/>` (or `<CTRL-X>` on GVim)
|
||||
- `<CTRL-X>`
|
||||
- `[0-9]\+`
|
||||
|
||||
#### Alignment options in interactive mode
|
||||
@@ -148,69 +203,63 @@ keys listed below. The meaning of each option will be described in
|
||||
[the following sections](https://github.com/junegunn/vim-easy-align#alignment-options).
|
||||
|
||||
| Key | Option | Values |
|
||||
| -------- | ------------------ | -------------------------------------------------- |
|
||||
| --------- | ------------------ | -------------------------------------------------- |
|
||||
| `CTRL-F` | `filter` | Input string (`[gv]/.*/?`) |
|
||||
| `CTRL-I` | `indentation` | shallow, deep, none, keep |
|
||||
| `CTRL-L` | `left_margin` | Input number or string |
|
||||
| `CTRL-R` | `right_margin` | Input number or string |
|
||||
| `CTRL-D` | `delimiter_align` | left, center, right |
|
||||
| `CTRL-U` | `ignore_unmatched` | 0, 1 |
|
||||
| `CTRL-G` | `ignore_groups` | [], ['String'], ['Comment'], ['String', 'Comment'] |
|
||||
| `CTRL-O` | `mode_sequence` | Input string of `/[lrc]+\*{0,2}/` |
|
||||
| `CTRL-O` | `mode_sequence` | Input string (`/[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`.
|
||||
### Live interactive mode
|
||||
|
||||
```vim
|
||||
:<C-R>=g:easy_align_last_command<Enter><Enter>
|
||||
```
|
||||
If you're performing a complex alignment where multiple options should be
|
||||
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 either `<Plug>(LiveEasyAlign)` or
|
||||
`:LiveEasyAlign` command.
|
||||
|
||||
### *Intermission*
|
||||
In live interactive mode, you have to type in the same delimiter (or `CTRL-X` on
|
||||
regular expression) again to finalize the alignment. This allows you to preview
|
||||
the result of the alignment and freely change the delimiter using backspace key
|
||||
without leaving the interactive mode.
|
||||
|
||||
You can stop reading here. Trust me. All the fancy features described in the
|
||||
following sections are really powerful but you won't be needing them in most
|
||||
of the cases.
|
||||
### Non-interactive mode
|
||||
|
||||
Go try out vim-easy-align right now, and come back later when you feel like it.
|
||||
|
||||
---
|
||||
|
||||
### Non-interactive mode (command line)
|
||||
|
||||
Instead of going into the interactive mode, you can type in arguments to
|
||||
Instead of starting interactive mode, you can use declarative, non-interactive
|
||||
`:EasyAlign` command.
|
||||
|
||||
```vim
|
||||
" Using predefined alignment rules
|
||||
:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]
|
||||
" :EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]
|
||||
:EasyAlign :
|
||||
:EasyAlign =
|
||||
:EasyAlign *=
|
||||
:EasyAlign 3\
|
||||
|
||||
" Using arbitrary regular expressions
|
||||
:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]
|
||||
" :EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]
|
||||
:EasyAlign /[:;]\+/
|
||||
:EasyAlign 2/[:;]\+/
|
||||
:EasyAlign */[:;]\+/
|
||||
:EasyAlign **/[:;]\+/
|
||||
```
|
||||
|
||||
For example, when aligning the following lines around colons and semi-colons,
|
||||
|
||||
apple;:banana::cake
|
||||
data;;exchange:;format
|
||||
|
||||
try these commands:
|
||||
|
||||
- `: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.
|
||||
A command can end with alignment options, [each of which will be discussed in
|
||||
detail later](https://github.com/junegunn/vim-easy-align#alignment-options),
|
||||
in Vim dictionary format.
|
||||
|
||||
- `:EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'left_margin': 0 }`
|
||||
|
||||
Then we get:
|
||||
`stick_to_left` of 1 means that the matched delimiter should be positioned right
|
||||
next to the preceding token, and `left_margin` of 0 removes the margin on the
|
||||
left. So we get:
|
||||
|
||||
apple;: banana:: cake
|
||||
data;; exchange:; format
|
||||
@@ -223,31 +272,32 @@ You can even omit spaces between the arguments, so concisely (or cryptically):
|
||||
|
||||
- `:EasyAlign*/[:;]\+/{'s':1,'l':0}`
|
||||
|
||||
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.
|
||||
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]` |
|
||||
| Option | Expression |
|
||||
| ------------------ | ---------- |
|
||||
| `filter` | `[gv]/.*/` |
|
||||
| `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.
|
||||
For your information, the same operation can be done in interactive mode as
|
||||
follows:
|
||||
|
||||
- `<Enter>`
|
||||
- `*`
|
||||
- `<Left>`
|
||||
- `<CTRL-/>` (or `<CTRL-X>` on GVim)
|
||||
- `<CTRL-X>`
|
||||
- `[:;]\+`
|
||||
|
||||
### Partial alignment in blockwise-visual mode
|
||||
@@ -277,6 +327,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 N-th parameter: `<Enter>-=`
|
||||
|
||||
|
||||
Alignment options
|
||||
-----------------
|
||||
|
||||
@@ -284,6 +335,7 @@ Alignment options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| ------------------ | ------- | --------------------- | ------------------------------------------------------- |
|
||||
| `filter` | string | | Line filtering expression: `g/../` or `v/../` |
|
||||
| `left_margin` | number | 1 | Number of spaces to attach before delimiter |
|
||||
| `left_margin` | string | `' '` | String to attach before delimiter |
|
||||
| `right_margin` | number | 1 | Number of spaces to attach after delimiter |
|
||||
@@ -304,6 +356,7 @@ There are 4 ways to set alignment options (from lowest precedence to highest):
|
||||
|
||||
| Option name | Shortcut key | Abbreviated | Global variable |
|
||||
| ------------------ | ------------------- | ----------- | ------------------------------- |
|
||||
| `filter` | `CTRL-F` | `[gv]/.*/` | |
|
||||
| `left_margin` | `CTRL-L` | `l[0-9]+` | |
|
||||
| `right_margin` | `CTRL-R` | `r[0-9]+` | |
|
||||
| `stick_to_left` | `<Left>`, `<Right>` | `s[01]` | |
|
||||
@@ -313,6 +366,30 @@ There are 4 ways to set alignment options (from lowest precedence to highest):
|
||||
| `delimiter_align` | `CTRL-D` | `d[lrc]` | `g:easy_align_delimiter_align` |
|
||||
| `mode_sequence` | `CTRL-O` | `m[lrc*]*` | |
|
||||
|
||||
### Filtering lines
|
||||
|
||||
With `filter` option, you can align lines that only match or do not match a
|
||||
given pattern. There are several ways to set the pattern.
|
||||
|
||||
1. Press `CTRL-F` in interactive mode and type in `g/pat/` or `v/pat/`
|
||||
2. In command-line, it can be written in dictionary format: `{'filter': 'g/pat/'}`
|
||||
3. Or in shorthand notation: `g/pat/` or `v/pat/`
|
||||
|
||||
(You don't need to escape '/'s in the regular expression)
|
||||
|
||||
#### Examples
|
||||
|
||||
```vim
|
||||
" Start interactive mode with filter option set to g/hello/
|
||||
EasyAlign g/hello/
|
||||
|
||||
" Start live interactive mode with filter option set to v/goodbye/
|
||||
LiveEasyAlign v/goodbye/
|
||||
|
||||
" Align the lines with 'hi' around the first colons
|
||||
EasyAlign:g/hi/
|
||||
```
|
||||
|
||||
### Ignoring delimiters in comments or strings
|
||||
|
||||
EasyAlign can be configured to ignore delimiters in certain syntax highlight
|
||||
@@ -360,7 +437,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
|
||||
|
||||
@@ -375,14 +452,24 @@ For example if you set `ignore_groups` option to be an empty list, you get
|
||||
}
|
||||
```
|
||||
|
||||
Satisfied? :satisfied:
|
||||
If a pattern in `ignore_groups` is prepended by a `!`, it will have the opposite
|
||||
meaning. For instance, if `ignore_groups` is given as `['!Comment']`, delimiters
|
||||
that are *not* highlighted as Comment will be ignored during the alignment.
|
||||
|
||||
### 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
|
||||
{
|
||||
@@ -406,13 +493,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,
|
||||
|
||||
@@ -446,7 +533,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
|
||||
@@ -454,7 +541,7 @@ banana += apple
|
||||
cake ||= banana
|
||||
```
|
||||
|
||||
And on `:EasyAlign={'da':c}`, center-aligned.
|
||||
And on `:EasyAlign=dc`, center-aligned.
|
||||
|
||||
```ruby
|
||||
apple = 1
|
||||
@@ -486,7 +573,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
|
||||
@@ -494,7 +581,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
|
||||
@@ -502,7 +589,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
|
||||
@@ -510,30 +597,8 @@ daisy = 4
|
||||
eggplant = 5
|
||||
```
|
||||
|
||||
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, "N-th" parameter is used to target specific occurrences of
|
||||
@@ -572,24 +637,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
|
||||
@@ -597,13 +665,18 @@ in interactive mode with the special key `CTRL-O`)
|
||||
Although the default rules should cover the most of the use cases,
|
||||
you can extend the rules by setting a dictionary named `g:easy_align_delimiters`.
|
||||
|
||||
#### Example
|
||||
You may refer to the definitions of the default alignment rules
|
||||
[here](https://github.com/junegunn/vim-easy-align/blob/2.9.0/autoload/easy_align.vim#L29).
|
||||
|
||||
#### Examples
|
||||
|
||||
```vim
|
||||
let g:easy_align_delimiters = {
|
||||
\ '>': { 'pattern': '>>\|=>\|>' },
|
||||
\ '/': { 'pattern': '//\+\|/\*\|\*/', 'ignore_groups': ['String'] },
|
||||
\ '#': { 'pattern': '#\+', 'ignore_groups': ['String'], 'delimiter_align': 'l' },
|
||||
\ '/': {
|
||||
\ 'pattern': '//\+\|/\*\|\*/',
|
||||
\ 'delimiter_align': 'l',
|
||||
\ 'ignore_groups': ['!Comment'] },
|
||||
\ ']': {
|
||||
\ 'pattern': '[[\]]',
|
||||
\ 'left_margin': 0,
|
||||
@@ -617,13 +690,49 @@ let g:easy_align_delimiters = {
|
||||
\ 'stick_to_left': 0
|
||||
\ },
|
||||
\ 'd': {
|
||||
\ 'pattern': ' \(\S\+\s*[;=]\)\@=',
|
||||
\ 'left_margin': 0,
|
||||
\ 'pattern': ' \(\S\+\s*[;=]\)\@=',
|
||||
\ 'left_margin': 0,
|
||||
\ 'right_margin': 0
|
||||
\ }
|
||||
\ }
|
||||
```
|
||||
|
||||
Other options
|
||||
-------------
|
||||
|
||||
### Disabling &foldmethod during alignment
|
||||
|
||||
[It is reported](https://github.com/junegunn/vim-easy-align/issues/14) that
|
||||
`&foldmethod` value of `expr` or `syntax` can significantly slow down the
|
||||
alignment when editing a large, complex file with many folds. To alleviate this
|
||||
issue, EasyAlign provides an option to temporarily set `&foldmethod` to `manual`
|
||||
during the alignment task. In order to enable this feature, set
|
||||
`g:easy_align_bypass_fold` switch to 1.
|
||||
|
||||
```vim
|
||||
let g:easy_align_bypass_fold = 1
|
||||
```
|
||||
|
||||
### 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']
|
||||
```
|
||||
|
||||
Advanced examples and use cases
|
||||
-------------------------------
|
||||
|
||||
@@ -634,7 +743,7 @@ for more examples.
|
||||
Related work
|
||||
------------
|
||||
|
||||
There are two well-known plugins with the same goal as that of vim-easy-align.
|
||||
There are two well-known plugins with the same goal as that of easy-align.
|
||||
|
||||
- [DrChip's Alignment Tool for Vim](http://www.drchip.org/astronaut/vim/align.html) (herein will be referred to as "Align")
|
||||
- [Tabular](https://github.com/godlygeek/tabular)
|
||||
@@ -642,22 +751,22 @@ There are two well-known plugins with the same goal as that of vim-easy-align.
|
||||
Both are great plugins with very large user bases. I actually had been a Tabular
|
||||
user for a couple of years before I finally made up my mind to roll out my own.
|
||||
|
||||
So why would someone choose vim-easy-align over those two?
|
||||
So why would someone choose easy-align over those two?
|
||||
|
||||
Feature-by-feature comparison I believe is not quite useful, since a typical
|
||||
user will end up using only a small subset of the features.
|
||||
So I will mention just a few core benefits of vim-easy-align.
|
||||
So I will mention just a few core benefits of easy-align.
|
||||
|
||||
### Ease of use
|
||||
|
||||
As the name implies, vim-easy-align is *easier* to use. Its interactive mode
|
||||
As the name implies, easy-align is *easier* to use. Its interactive mode
|
||||
allows you to achieve what you want with just a few keystrokes.
|
||||
The key sequence is mnemonic, so it's easy to remember and execute.
|
||||
It even feels like a native Vim command!
|
||||
|
||||
- *Right-align*: `<Enter><Enter>`
|
||||
- around the *second* occurrences: `2`
|
||||
- of *whitespaces*: `<space>`
|
||||
- of *whitespaces*: `<Space>`
|
||||
|
||||
For the simplest cases, Tabular and Align are also easy to use. But sooner or
|
||||
later, you will find yourself scratching your head, trying to come up with some
|
||||
@@ -668,17 +777,17 @@ without affecting the ones before it?"_
|
||||
|
||||
### Clean
|
||||
|
||||
vim-easy-align doesn't clutter your workspace with mappings and global
|
||||
easy-align doesn't clutter your workspace with mappings and global
|
||||
variables. All you would need is a single mapping to the interactive EasyAlign
|
||||
command, and even that is totally up to you.
|
||||
|
||||
### Optimized for code editing
|
||||
|
||||
vim-easy-align by default performs syntax-aware alignment, which is invaluable
|
||||
easy-align by default performs syntax-aware alignment, which is invaluable
|
||||
when editing codes.
|
||||
|
||||
Try to come up with a regular expression to correctly format the following code
|
||||
snippet. With vim-easy-align under default configuration and a mapping, it can
|
||||
snippet. With easy-align under default configuration and a mapping, it can
|
||||
be done with just two keystrokes: `<Enter>:`
|
||||
|
||||
```javascript
|
||||
@@ -696,10 +805,15 @@ var jdbc = {
|
||||
`g:AlignSkip` function reference which should point to a custom function that
|
||||
looks up the syntax group of a character on a certain position)
|
||||
|
||||
### Thoroughly tested
|
||||
|
||||
Virtually every aspect of easy-align is being tested with a comprehensive
|
||||
set of test cases using [Vader.vim](https://github.com/junegunn/vader.vim).
|
||||
|
||||
### "Okay. So should I switch?"
|
||||
|
||||
Maybe, but I can't really say. I have no ambition to make vim-easy-align
|
||||
an absolute superior to the others. For some cases, vim-easy-align works better
|
||||
Maybe, but I can't really say. I have no ambition to make easy-align
|
||||
an absolute superior to the others. For some cases, easy-align works better
|
||||
than the others, but for some other cases, Tabular or Align.vim might be a
|
||||
better choice.
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ if exists("g:loaded_easy_align")
|
||||
endif
|
||||
let g:loaded_easy_align = 1
|
||||
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
let s:easy_align_delimiters_default = {
|
||||
\ ' ': { 'pattern': ' ', 'left_margin': 0, 'right_margin': 0, 'stick_to_left': 0 },
|
||||
\ '=': { 'pattern': '===\|<=>\|\(&&\|||\|<<\|>>\)=\|=\~[#?]\?\|=>\|[:+/*!%^=><&|.-]\?=[#?]\?',
|
||||
@@ -34,6 +37,9 @@ let s:easy_align_delimiters_default = {
|
||||
\ ',': { 'pattern': ',', 'left_margin': 0, 'right_margin': 1, 'stick_to_left': 1 },
|
||||
\ '|': { 'pattern': '|', 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 },
|
||||
\ '.': { 'pattern': '\.', 'left_margin': 0, 'right_margin': 0, 'stick_to_left': 0 },
|
||||
\ '#': { 'pattern': '#\+', 'delimiter_align': 'l', 'ignore_groups': ['!Comment'] },
|
||||
\ '&': { 'pattern': '\\\@<!&\|\\\\',
|
||||
\ 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 },
|
||||
\ '{': { 'pattern': '(\@<!{',
|
||||
\ 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 },
|
||||
\ '}': { 'pattern': '}', 'left_margin': 1, 'right_margin': 0, 'stick_to_left': 0 }
|
||||
@@ -45,7 +51,7 @@ let s:known_options = {
|
||||
\ 'margin_left': [0, 1], 'margin_right': [0, 1], 'stick_to_left': [0],
|
||||
\ 'left_margin': [0, 1], 'right_margin': [0, 1], 'indentation': [1],
|
||||
\ 'ignore_groups': [3 ], 'ignore_unmatched': [0 ], 'delimiter_align': [1],
|
||||
\ 'mode_sequence': [1 ], 'ignores': [3]
|
||||
\ 'mode_sequence': [1 ], 'ignores': [3], 'filter': [1]
|
||||
\ }
|
||||
|
||||
let s:option_values = {
|
||||
@@ -59,24 +65,36 @@ 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'
|
||||
\ 'mode_sequence': 'm', 'ignores': 'ig', 'filter': 'f'
|
||||
\ }
|
||||
|
||||
if exists("*strwidth")
|
||||
if exists("*strdisplaywidth")
|
||||
function! s:strwidth(str)
|
||||
return strwidth(a:str)
|
||||
return strdisplaywidth(a:str)
|
||||
endfunction
|
||||
else
|
||||
function! s:strwidth(str)
|
||||
return len(split(a:str, '\zs'))
|
||||
return len(split(a:str, '\zs')) + len(matchstr(a:str, '^\t*')) * (&tabstop - 1)
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! s:ceil2(v)
|
||||
return a:v % 2 == 0 ? a:v : a:v + 1
|
||||
endfunction
|
||||
|
||||
function! s:floor2(v)
|
||||
return a:v % 2 == 0 ? a:v : a:v - 1
|
||||
endfunction
|
||||
|
||||
function! s:highlighted_as(line, col, groups)
|
||||
if empty(a:groups) | return 0 | endif
|
||||
let hl = synIDattr(synID(a:line, a:col, 0), 'name')
|
||||
for grp in a:groups
|
||||
if hl =~# grp
|
||||
if grp[0] == '!'
|
||||
if hl !~# grp[1:-1]
|
||||
return 1
|
||||
endif
|
||||
elseif hl =~# grp
|
||||
return 1
|
||||
endif
|
||||
endfor
|
||||
@@ -151,11 +169,11 @@ function! s:exit(msg)
|
||||
endfunction
|
||||
|
||||
function! s:ltrim(str)
|
||||
return substitute(a:str, '^\s*', '', '')
|
||||
return substitute(a:str, '^\s\+', '', '')
|
||||
endfunction
|
||||
|
||||
function! s:rtrim(str)
|
||||
return substitute(a:str, '\s*$', '', '')
|
||||
return substitute(a:str, '\s\+$', '', '')
|
||||
endfunction
|
||||
|
||||
function! s:trim(str)
|
||||
@@ -254,6 +272,7 @@ function! s:split_line(line, nth, modes, cycle, fc, lc, pattern, stick_to_left,
|
||||
" Phase 1: split
|
||||
let ignorable = 0
|
||||
let token = ''
|
||||
let phantom = 0
|
||||
while 1
|
||||
let matches = matchlist(string, pattern, idx)
|
||||
" No match
|
||||
@@ -284,8 +303,7 @@ function! s:split_line(line, nth, modes, cycle, fc, lc, pattern, stick_to_left,
|
||||
" If the string is non-empty and ends with the delimiter,
|
||||
" append an empty token to the list
|
||||
if idx == len(string)
|
||||
call add(tokens, '')
|
||||
call add(delims, '')
|
||||
let phantom = 1
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
@@ -295,6 +313,9 @@ function! s:split_line(line, nth, modes, cycle, fc, lc, pattern, stick_to_left,
|
||||
let ignorable = s:highlighted_as(a:line, len(string) + a:fc - 1, a:ignore_groups)
|
||||
call add(tokens, leftover)
|
||||
call add(delims, '')
|
||||
elseif phantom
|
||||
call add(tokens, '')
|
||||
call add(delims, '')
|
||||
endif
|
||||
let [pmode, mode] = [mode, s:shift(a:modes, a:cycle)]
|
||||
|
||||
@@ -323,30 +344,29 @@ function! s:split_line(line, nth, modes, cycle, fc, lc, pattern, stick_to_left,
|
||||
return [tokens, delims]
|
||||
endfunction
|
||||
|
||||
function! s:max(old, new)
|
||||
for k in keys(a:new)
|
||||
if a:new[k] > a:old[k]
|
||||
let a:old[k] = a:new[k] " max() doesn't work with Floats
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:do_align(modes, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth,
|
||||
\ ml, mr, da, indentation, stick_to_left, ignore_unmatched, ignore_groups, recur)
|
||||
function! s:do_align(todo, modes, all_tokens, all_delims, fl, ll, fc, lc, nth, recur, dict)
|
||||
let mode = a:modes[0]
|
||||
let lines = {}
|
||||
let min_indent = -1
|
||||
let max = { 'pivot_len': 0.0, 'token_len': 0, 'just_len': 0, 'delim_len': 0,
|
||||
let max = { 'pivot_len2': 0, 'token_len': 0, 'just_len': 0, 'delim_len': 0,
|
||||
\ 'indent': 0, 'tokens': 0, 'strip_len': 0 }
|
||||
let d = a:dict
|
||||
let [f, fx] = s:parse_filter(d.filter)
|
||||
|
||||
" Phase 1
|
||||
for line in range(a:fl, a:ll)
|
||||
if f == 1 && getline(line) !~ fx
|
||||
continue
|
||||
elseif f == -1 && getline(line) =~ fx
|
||||
continue
|
||||
endif
|
||||
|
||||
if !has_key(a:all_tokens, line)
|
||||
" Split line into the tokens by the delimiters
|
||||
let [tokens, delims] = s:split_line(
|
||||
\ line, a:nth, copy(a:modes), a:recur == 2,
|
||||
\ a:fc, a:lc, a:pattern,
|
||||
\ a:stick_to_left, a:ignore_unmatched, a:ignore_groups)
|
||||
\ a:fc, a:lc, d.pattern,
|
||||
\ d.stick_to_left, d.ignore_unmatched, d.ignore_groups)
|
||||
|
||||
" Remember tokens for subsequent recursive calls
|
||||
let a:all_tokens[line] = tokens
|
||||
@@ -362,7 +382,7 @@ function! s:do_align(modes, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth
|
||||
endif
|
||||
|
||||
" Calculate the maximum number of tokens for a line within the range
|
||||
call s:max(max, { 'tokens': len(tokens) })
|
||||
let max.tokens = max([max.tokens, len(tokens)])
|
||||
|
||||
if a:nth > 0 " Positive N-th
|
||||
if len(tokens) < a:nth
|
||||
@@ -388,53 +408,79 @@ function! s:do_align(modes, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth
|
||||
let delim = delims[nth]
|
||||
let token = s:rtrim( tokens[nth] )
|
||||
let token = s:rtrim( strpart(token, 0, len(token) - len(s:rtrim(delim))) )
|
||||
if empty(delim) && !exists('tokens[nth + 1]') && a:ignore_unmatched
|
||||
if empty(delim) && !exists('tokens[nth + 1]') && d.ignore_unmatched
|
||||
continue
|
||||
endif
|
||||
|
||||
let indent = len(matchstr(tokens[0], '^\s\+'))
|
||||
let indent = s:strwidth(matchstr(tokens[0], '^\s*'))
|
||||
if min_indent < 0 || indent < min_indent
|
||||
let min_indent = indent
|
||||
endif
|
||||
if mode ==? 'c' | let token .= matchstr(token, '^\s*') | endif
|
||||
let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
|
||||
call s:max(max, { 'indent': indent, 'token_len': tw, 'just_len': pw + tw,
|
||||
\ 'delim_len': s:strwidth(delim) })
|
||||
if mode ==? 'c'
|
||||
call s:max(max, { 'pivot_len': pw + tw / 2.0,
|
||||
\ 'strip_len': s:strwidth(s:trim(token)) })
|
||||
let token .= substitute(matchstr(token, '^\s*'), '\t', repeat(' ', &tabstop), 'g')
|
||||
endif
|
||||
let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
|
||||
let max.indent = max([max.indent, indent])
|
||||
let max.token_len = max([max.token_len, tw])
|
||||
let max.just_len = max([max.just_len, pw + tw])
|
||||
let max.delim_len = max([max.delim_len, s:strwidth(delim)])
|
||||
|
||||
if mode ==? 'c'
|
||||
let pivot_len2 = pw * 2 + tw
|
||||
if max.pivot_len2 < pivot_len2
|
||||
let max.pivot_len2 = pivot_len2
|
||||
endif
|
||||
let max.strip_len = max([max.strip_len, s:strwidth(s:trim(token))])
|
||||
endif
|
||||
let lines[line] = [nth, prefix, token, delim]
|
||||
endfor
|
||||
|
||||
" Phase 1-5: indentation handling (only on a:nth == 1)
|
||||
if a:nth == 1
|
||||
if a:indentation ==? 'd'
|
||||
let indent = repeat(' ', max.indent)
|
||||
elseif a:indentation ==? 's'
|
||||
let indent = repeat(' ', min_indent)
|
||||
elseif a:indentation ==? 'n'
|
||||
let indent = ''
|
||||
elseif a:indentation !=? 'k'
|
||||
call s:exit('Invalid indentation: ' . a:indentation)
|
||||
let idt = d.indentation
|
||||
if idt ==? 'd'
|
||||
let indent = max.indent
|
||||
elseif idt ==? 's'
|
||||
let indent = min_indent
|
||||
elseif idt ==? 'n'
|
||||
let indent = 0
|
||||
elseif idt !=? 'k'
|
||||
call s:exit('Invalid indentation: ' . idt)
|
||||
end
|
||||
|
||||
if a:indentation !=? 'k'
|
||||
let max.just_len = 0
|
||||
let max.token_len = 0
|
||||
let max.pivot_len = 0
|
||||
if idt !=? 'k'
|
||||
let max.just_len = 0
|
||||
let max.token_len = 0
|
||||
let max.pivot_len2 = 0
|
||||
|
||||
for [line, elems] in items(lines)
|
||||
let [nth, prefix, token, delim] = elems
|
||||
|
||||
let token = substitute(token, '^\s*', indent, '')
|
||||
let tindent = matchstr(token, '^\s*')
|
||||
while 1
|
||||
let len = s:strwidth(tindent)
|
||||
if len < indent
|
||||
let tindent .= repeat(' ', indent - len)
|
||||
break
|
||||
elseif len > indent
|
||||
let tindent = tindent[0 : -2]
|
||||
else
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
|
||||
let token = tindent . s:ltrim(token)
|
||||
if mode ==? 'c'
|
||||
let token = substitute(token, '\s*$', indent, '')
|
||||
let token = substitute(token, '\s*$', repeat(' ', indent), '')
|
||||
endif
|
||||
let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
|
||||
call s:max(max, { 'token_len': tw, 'just_len': pw + tw })
|
||||
let max.token_len = max([max.token_len, tw])
|
||||
let max.just_len = max([max.just_len, pw + tw])
|
||||
if mode ==? 'c'
|
||||
call s:max(max, { 'pivot_len': pw + tw / 2.0 })
|
||||
let pivot_len2 = pw * 2 + tw
|
||||
if max.pivot_len2 < pivot_len2
|
||||
let max.pivot_len2 = pivot_len2
|
||||
endif
|
||||
endif
|
||||
|
||||
let lines[line][2] = token
|
||||
@@ -458,26 +504,28 @@ function! s:do_align(modes, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth
|
||||
let rpad = ''
|
||||
if mode ==? 'l'
|
||||
let pad = repeat(' ', max.just_len - pw - tw)
|
||||
if a:stick_to_left
|
||||
if d.stick_to_left
|
||||
let rpad = pad
|
||||
else
|
||||
let token = token . pad
|
||||
endif
|
||||
elseif mode ==? 'r'
|
||||
let pad = repeat(' ', max.just_len - pw - tw)
|
||||
let token = pad . token
|
||||
let indent = matchstr(token, '^\s*')
|
||||
let token = indent . pad . s:ltrim(token)
|
||||
elseif mode ==? 'c'
|
||||
let p1 = max.pivot_len - (pw + tw / 2.0)
|
||||
let p2 = (max.token_len - tw) / 2.0
|
||||
let pf1 = floor(p1)
|
||||
if pf1 < p1 | let p2 = ceil(p2)
|
||||
else | let p2 = floor(p2)
|
||||
let p1 = max.pivot_len2 - (pw * 2 + tw)
|
||||
let p2 = max.token_len - tw
|
||||
let pf1 = s:floor2(p1)
|
||||
if pf1 < p1 | let p2 = s:ceil2(p2)
|
||||
else | let p2 = s:floor2(p2)
|
||||
endif
|
||||
let strip = float2nr(ceil((max.token_len - max.strip_len) / 2.0))
|
||||
let token = repeat(' ', float2nr(pf1)) .token. repeat(' ', float2nr(p2))
|
||||
let strip = s:ceil2(max.token_len - max.strip_len) / 2
|
||||
let indent = matchstr(token, '^\s*')
|
||||
let token = indent. repeat(' ', pf1 / 2) .s:ltrim(token). repeat(' ', p2 / 2)
|
||||
let token = substitute(token, repeat(' ', strip) . '$', '', '')
|
||||
|
||||
if a:stick_to_left
|
||||
if d.stick_to_left
|
||||
if empty(s:rtrim(token))
|
||||
let center = len(token) / 2
|
||||
let [token, rpad] = [strpart(token, 0, center), strpart(token, center)]
|
||||
@@ -490,32 +538,33 @@ function! s:do_align(modes, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth
|
||||
|
||||
" Pad the delimiter
|
||||
let dpadl = max.delim_len - s:strwidth(delim)
|
||||
if a:da ==? 'l'
|
||||
let da = d.delimiter_align
|
||||
if da ==? 'l'
|
||||
let [dl, dr] = ['', repeat(' ', dpadl)]
|
||||
elseif a:da ==? 'c'
|
||||
elseif da ==? 'c'
|
||||
let dl = repeat(' ', dpadl / 2)
|
||||
let dr = repeat(' ', dpadl - dpadl / 2)
|
||||
elseif a:da ==? 'r'
|
||||
elseif da ==? 'r'
|
||||
let [dl, dr] = [repeat(' ', dpadl), '']
|
||||
else
|
||||
call s:exit('Invalid delimiter_align: ' . a:da)
|
||||
call s:exit('Invalid delimiter_align: ' . da)
|
||||
endif
|
||||
|
||||
" Before and after the range (for blockwise visual mode)
|
||||
let cline = getline(line)
|
||||
let before = strpart(cline, 0, a:fc - 1)
|
||||
let after = a:lc ? strpart(cline, a:lc) : ''
|
||||
let cline = getline(line)
|
||||
let before = strpart(cline, 0, a:fc - 1)
|
||||
let after = a:lc ? strpart(cline, a:lc) : ''
|
||||
|
||||
" Determine the left and right margin around the delimiter
|
||||
let rest = join(tokens[nth + 1 : -1], '')
|
||||
let ml = empty(prefix . token) ? '' : a:ml
|
||||
let mr = (empty(rest) ||
|
||||
\ (empty(rest) && stridx(after, a:mr) == 0)) ? '' : a:mr
|
||||
let rest = join(tokens[nth + 1 : -1], '')
|
||||
let nomore = empty(rest.after)
|
||||
let ml = (empty(prefix . token) || empty(delim) && nomore) ? '' : d.ml
|
||||
let mr = nomore ? '' : d.mr
|
||||
|
||||
" 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
|
||||
@@ -528,18 +577,15 @@ function! s:do_align(modes, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth
|
||||
let tokens[nth] = aligned
|
||||
|
||||
" Update the line
|
||||
let newline = s:rtrim(before.join(tokens, '').after)
|
||||
call setline(line, newline)
|
||||
let a:todo[line] = before.join(tokens, '').after
|
||||
endfor
|
||||
|
||||
if a:nth < max.tokens && (a:recur || len(a:modes) > 1)
|
||||
call s:shift(a:modes, a:recur == 2)
|
||||
call s:do_align(
|
||||
\ a:modes, a:all_tokens, a:all_delims,
|
||||
\ a:fl, a:ll, a:fc, a:lc, a:pattern,
|
||||
\ a:nth + 1, a:ml, a:mr, a:da, a:indentation, a:stick_to_left,
|
||||
\ a:ignore_unmatched, a:ignore_groups, a:recur)
|
||||
return [a:todo, a:modes, a:all_tokens, a:all_delims,
|
||||
\ a:fl, a:ll, a:fc, a:lc, a:nth + 1, a:recur, a:dict]
|
||||
endif
|
||||
return [a:todo]
|
||||
endfunction
|
||||
|
||||
function! s:input(str, default, vis)
|
||||
@@ -551,9 +597,7 @@ function! s:input(str, default, vis)
|
||||
" EasyAlign command can be called without visual selection
|
||||
redraw
|
||||
endif
|
||||
call inputsave()
|
||||
let got = input(a:str, a:default)
|
||||
call inputrestore()
|
||||
return got
|
||||
endfunction
|
||||
|
||||
@@ -570,26 +614,56 @@ function! s:shift_opts(opts, key, vals)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:interactive(modes, vis, opts, delims)
|
||||
function! s:interactive(range, modes, n, d, opts, rules, vis, live)
|
||||
let mode = s:shift(a:modes, 1)
|
||||
let n = ''
|
||||
let n = a:n
|
||||
let d = a:d
|
||||
let ch = ''
|
||||
let opts = s:compact_options(a:opts)
|
||||
let vals = deepcopy(s:option_values)
|
||||
let regx = 0
|
||||
let warn = ''
|
||||
let undo = 0
|
||||
|
||||
while 1
|
||||
call s:echon(mode, n, -1, '', opts, warn)
|
||||
" Live preview
|
||||
let rdrw = 0
|
||||
if undo
|
||||
silent! undo
|
||||
let undo = 0
|
||||
let rdrw = 1
|
||||
endif
|
||||
if a:live && !empty(d)
|
||||
let output = s:process(a:range, mode, n, d, s:normalize_options(opts), regx, a:rules, 0)
|
||||
let &undolevels = &undolevels " Break undo block
|
||||
call s:update_lines(output.todo)
|
||||
let undo = 1
|
||||
let rdrw = 1
|
||||
endif
|
||||
if rdrw
|
||||
if a:vis
|
||||
normal! gv
|
||||
endif
|
||||
redraw
|
||||
if a:vis | execute "normal! \<esc>" | endif
|
||||
endif
|
||||
call s:echon(mode, n, -1, regx ? '/'.d.'/' : d, opts, warn)
|
||||
|
||||
let check = 0
|
||||
let warn = ''
|
||||
|
||||
let c = getchar()
|
||||
let ch = nr2char(c)
|
||||
if c == 3 || c == 27 " CTRL-C / ESC
|
||||
if undo
|
||||
silent! undo
|
||||
endif
|
||||
throw 'exit'
|
||||
elseif c == "\<bs>"
|
||||
if len(n) > 0
|
||||
if !empty(d)
|
||||
let d = ''
|
||||
let regx = 0
|
||||
elseif len(n) > 0
|
||||
let n = strpart(n, 0, len(n) - 1)
|
||||
endif
|
||||
elseif c == 13 " Enter key
|
||||
@@ -608,7 +682,7 @@ function! s:interactive(modes, vis, opts, delims)
|
||||
elseif n == '**' | let n = ''
|
||||
else | let check = 1
|
||||
endif
|
||||
elseif (c == 48 && len(n) > 0) || c > 48 && c <= 57 " Numbers
|
||||
elseif empty(d) && ((c == 48 && len(n) > 0) || c > 48 && c <= 57) " Numbers
|
||||
if n[0] == '*' | let check = 1
|
||||
else | let n = n . ch
|
||||
end
|
||||
@@ -660,14 +734,29 @@ function! s:interactive(modes, vis, opts, delims)
|
||||
silent! call remove(opts, 'm')
|
||||
endif
|
||||
elseif ch == "\<C-_>" || ch == "\<C-X>"
|
||||
if a:live && regx && !empty(d)
|
||||
break
|
||||
endif
|
||||
|
||||
let prompt = 'Regular expression: '
|
||||
let ch = s:input(prompt, '', a:vis)
|
||||
if !empty(ch) && s:valid_regexp(ch)
|
||||
let regx = 1
|
||||
break
|
||||
let d = ch
|
||||
if !a:live | break | endif
|
||||
else
|
||||
let warn = 'Invalid regular expression: '.ch
|
||||
endif
|
||||
elseif ch == "\<C-F>"
|
||||
let f = s:input("Filter (g/../ or v/../): ", get(opts, 'f', ''), a:vis)
|
||||
let m = matchlist(f, '^[gv]/\(.\{-}\)/\?$')
|
||||
if empty(f)
|
||||
silent! call remove(opts, 'f')
|
||||
elseif !empty(m) && s:valid_regexp(m[1])
|
||||
let opts['f'] = f
|
||||
else
|
||||
let warn = 'Invalid filter expression'
|
||||
endif
|
||||
elseif ch =~ '[[:print:]]'
|
||||
let check = 1
|
||||
else
|
||||
@@ -675,14 +764,33 @@ function! s:interactive(modes, vis, opts, delims)
|
||||
endif
|
||||
|
||||
if check
|
||||
if has_key(a:delims, ch)
|
||||
break
|
||||
if empty(d)
|
||||
if has_key(a:rules, ch)
|
||||
let d = ch
|
||||
if !a:live
|
||||
break
|
||||
endif
|
||||
else
|
||||
let warn = 'Unknown delimiter key: '.ch
|
||||
endif
|
||||
else
|
||||
let warn = 'Unknown delimiter key: '.ch
|
||||
if regx
|
||||
let warn = 'Press <CTRL-X> to finish'
|
||||
else
|
||||
if d == ch
|
||||
break
|
||||
else
|
||||
let warn = 'Press '''.d.''' again to finish'
|
||||
endif
|
||||
end
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
return [mode, n, ch, s:normalize_options(opts), regx]
|
||||
if a:live
|
||||
let copts = call('s:summarize', output.summarize)
|
||||
let g:easy_align_last_command = s:echon('', n, regx, d, copts, '')
|
||||
end
|
||||
return [mode, n, ch, opts, regx]
|
||||
endfunction
|
||||
|
||||
function! s:valid_regexp(regexp)
|
||||
@@ -701,14 +809,16 @@ function! s:test_regexp(regexp)
|
||||
return a:regexp
|
||||
endfunction
|
||||
|
||||
function! s:parse_shortcut_opts(expr)
|
||||
let s:shorthand_regex =
|
||||
\ '\s*\%('
|
||||
\ .'\(lm\?[0-9]\+\)\|\(rm\?[0-9]\+\)\|\(iu[01]\)\|\(s\%(tl\)\?[01]\)\|'
|
||||
\ .'\(da\?[clr]\)\|\(ms\?[lrc*]\+\)\|\(i\%(dt\)\?[kdsn]\)\|\([gv]/.*/\)\|\(ig\[.*\]\)'
|
||||
\ .'\)\+\s*$'
|
||||
|
||||
function! s:parse_shorthand_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\[.*\]\)'
|
||||
\ .'\)\+$'
|
||||
let regex = '^'. s:shorthand_regex
|
||||
|
||||
if empty(expr)
|
||||
return opts
|
||||
@@ -717,36 +827,44 @@ function! s:parse_shortcut_opts(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'
|
||||
for m in filter(match[ 1 : -1 ], '!empty(v:val)')
|
||||
for key in ['lm', 'rm', 'l', 'r', 'stl', 's', 'iu', 'da', 'd', 'ms', 'm', 'ig', 'i', 'g', 'v']
|
||||
if stridx(tolower(m), key) == 0
|
||||
let rest = strpart(m, len(key))
|
||||
if key == 'i' | let key = 'idt' | endif
|
||||
if key == 'g' || key == 'v'
|
||||
let rest = key.rest
|
||||
let key = 'f'
|
||||
endif
|
||||
catch
|
||||
call s:exit("Invalid ignore_groups: ". a:expr)
|
||||
endtry
|
||||
elseif k == 'i'
|
||||
let opts['idt'] = rest
|
||||
else
|
||||
let opts[k] = rest
|
||||
endif
|
||||
|
||||
if key == 'idt' || index(['d', 'f', '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)
|
||||
if empty(a:args)
|
||||
return ['', '', {}, 0]
|
||||
endif
|
||||
let n = ''
|
||||
let ch = ''
|
||||
let args = a:args
|
||||
@@ -785,66 +903,66 @@ 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*/\(.*\)/\(.\{-}\)$')
|
||||
let matches = matchlist(args, '^\(.\{-}\)\s*/\(.*\)/\s*$')
|
||||
|
||||
" Found regexp
|
||||
if !empty(matches)
|
||||
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]
|
||||
" Try swapping n and ch
|
||||
let [n, ch] = empty(tokens[2]) ? reverse(tokens[1:2]) : tokens[1:2]
|
||||
|
||||
" Resolving command-line ambiguity
|
||||
" '\ ' => ' '
|
||||
" '\' => ' '
|
||||
if ch =~ '^\\\s*$'
|
||||
let ch = ' '
|
||||
" '\\' => '\'
|
||||
elseif ch =~ '^\\\\\s*$'
|
||||
let ch = '\'
|
||||
endif
|
||||
|
||||
return [n, ch, opts, 0]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:modes(bang)
|
||||
function! s:parse_filter(f)
|
||||
let m = matchlist(a:f, '^\([gv]\)/\(.\{-}\)/\?$')
|
||||
if empty(m)
|
||||
return [0, '']
|
||||
else
|
||||
return [m[1] == 'g' ? 1 : -1, m[2]]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:interactive_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']
|
||||
return a:mode ==? 'r' ? 'rl' : 'lr'
|
||||
endfunction
|
||||
|
||||
function! easy_align#align(bang, expr) range
|
||||
try
|
||||
call s:align(a:bang, a:firstline, a:lastline, a:expr)
|
||||
catch 'exit'
|
||||
endtry
|
||||
function! s:update_lines(todo)
|
||||
for [line, content] in items(a:todo)
|
||||
call setline(line, s:rtrim(content))
|
||||
endfor
|
||||
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 regexp = 0
|
||||
" 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, 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
|
||||
endif
|
||||
|
||||
function! s:parse_nth(n)
|
||||
let n = a:n
|
||||
let recur = 0
|
||||
if n == '*' | let [nth, recur] = [1, 1]
|
||||
elseif n == '**' | let [nth, recur] = [1, 2]
|
||||
elseif n == '-' | let nth = -1
|
||||
@@ -854,77 +972,145 @@ function! s:align(bang, first_line, last_line, expr)
|
||||
else
|
||||
let nth = n
|
||||
endif
|
||||
return [nth, recur]
|
||||
endfunction
|
||||
|
||||
if regexp
|
||||
let dict = { 'pattern': ch }
|
||||
function! s:build_dict(delimiters, ch, regexp, opts)
|
||||
if a:regexp
|
||||
let dict = { 'pattern': a:ch }
|
||||
else
|
||||
" Resolving command-line ambiguity
|
||||
if !empty(a:expr)
|
||||
" '\ ' => ' '
|
||||
" '\' => ' '
|
||||
if ch =~ '^\\\s*$'
|
||||
let ch = ' '
|
||||
" '\\' => '\'
|
||||
elseif ch =~ '^\\\\\s*$'
|
||||
let ch = '\'
|
||||
endif
|
||||
if !has_key(a:delimiters, a:ch)
|
||||
call s:exit('Unknown delimiter key: '. a:ch)
|
||||
endif
|
||||
if !has_key(delimiters, ch)
|
||||
call s:exit('Unknown delimiter key: '. ch)
|
||||
endif
|
||||
let dict = copy(delimiters[ch])
|
||||
let dict = copy(a:delimiters[a:ch])
|
||||
endif
|
||||
|
||||
call extend(dict, opts)
|
||||
call extend(dict, a:opts)
|
||||
|
||||
let ml = get(dict, 'left_margin', ' ')
|
||||
let mr = get(dict, 'right_margin', ' ')
|
||||
if type(ml) == 0 | let ml = repeat(' ', ml) | endif
|
||||
if type(mr) == 0 | let mr = repeat(' ', mr) | endif
|
||||
call extend(dict, { 'ml': ml, 'mr': mr })
|
||||
|
||||
let bvisual = vis && char2nr(visualmode()) == 22 " ^V
|
||||
let dict.pattern = get(dict, 'pattern', a:ch)
|
||||
let dict.delimiter_align =
|
||||
\ get(dict, 'delimiter_align', get(g:, 'easy_align_delimiter_align', 'r'))[0]
|
||||
let dict.indentation =
|
||||
\ get(dict, 'indentation', get(g:, 'easy_align_indentation', 'k'))[0]
|
||||
let dict.stick_to_left =
|
||||
\ get(dict, 'stick_to_left', 0)
|
||||
let dict.ignore_unmatched =
|
||||
\ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 2))
|
||||
let dict.ignore_groups =
|
||||
\ get(dict, 'ignore_groups', get(dict, 'ignores', s:ignored_syntax()))
|
||||
let dict.filter =
|
||||
\ get(dict, 'filter', '')
|
||||
return dict
|
||||
endfunction
|
||||
|
||||
if recur && bvisual
|
||||
function! s:build_mode_sequence(expr, recur)
|
||||
let [expr, recur] = [a:expr, a:recur]
|
||||
let suffix = matchstr(a:expr, '\*\+$')
|
||||
if suffix == '*'
|
||||
let expr = expr[0 : -2]
|
||||
let recur = 1
|
||||
elseif suffix == '**'
|
||||
let expr = expr[0 : -3]
|
||||
let recur = 2
|
||||
endif
|
||||
return [tolower(expr), recur]
|
||||
endfunction
|
||||
|
||||
function! s:process(range, mode, n, ch, opts, regexp, rules, bvis)
|
||||
let [nth, recur] = s:parse_nth(a:n)
|
||||
let dict = s:build_dict(a:rules, a:ch, a:regexp, a:opts)
|
||||
let [mode_sequence, recur] = s:build_mode_sequence(
|
||||
\ get(dict, 'mode_sequence', recur == 2 ? s:alternating_modes(a:mode) : a:mode),
|
||||
\ recur)
|
||||
|
||||
if recur && a:bvis
|
||||
call s:exit('Recursive alignment is not supported in blockwise-visual mode')
|
||||
endif
|
||||
|
||||
let aseq = get(dict, 'mode_sequence',
|
||||
\ recur == 2 ? s:alternating_modes(mode) : [mode])
|
||||
let mode_expansion = matchstr(aseq, '\*\+$')
|
||||
if mode_expansion == '*'
|
||||
let aseq = aseq[0 : -2]
|
||||
let recur = 1
|
||||
elseif mode_expansion == '**'
|
||||
let aseq = aseq[0 : -3]
|
||||
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, '')
|
||||
let args = [
|
||||
\ {}, split(mode_sequence, '\zs'),
|
||||
\ {}, {}, a:range[0], a:range[1],
|
||||
\ a:bvis ? min([col("'<"), col("'>")]) : 1,
|
||||
\ a:bvis ? max([col("'<"), col("'>")]) : 0,
|
||||
\ nth, recur, dict ]
|
||||
while len(args) > 1
|
||||
let args = call('s:do_align', args)
|
||||
endwhile
|
||||
|
||||
call s:do_align(
|
||||
\ aseq_list,
|
||||
\ {}, {}, a:first_line, a:last_line,
|
||||
\ bvisual ? min([col("'<"), col("'>")]) : 1,
|
||||
\ bvisual ? max([col("'<"), col("'>")]) : 0,
|
||||
\ get(dict, 'pattern', ch),
|
||||
\ nth,
|
||||
\ ml,
|
||||
\ mr,
|
||||
\ 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', 2)),
|
||||
\ get(dict, 'ignore_groups', get(dict, 'ignores', s:ignored_syntax())),
|
||||
\ recur)
|
||||
|
||||
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, '')
|
||||
" todo: lines to update
|
||||
" summarize: arguments to s:summarize
|
||||
return { 'todo': args[0], 'summarize': [ a:opts, recur, mode_sequence ] }
|
||||
endfunction
|
||||
|
||||
function s:summarize(opts, recur, mode_sequence)
|
||||
let copts = s:compact_options(a:opts)
|
||||
let nbmode = s:interactive_modes(0)[0]
|
||||
if !has_key(copts, 'm') && (
|
||||
\ (a:recur == 2 && s:alternating_modes(nbmode) != a:mode_sequence) ||
|
||||
\ (a:recur != 2 && (a:mode_sequence[0] != nbmode || len(a:mode_sequence) > 1))
|
||||
\ )
|
||||
call extend(copts, { 'm': a:mode_sequence })
|
||||
endif
|
||||
return copts
|
||||
endfunction
|
||||
|
||||
function! s:align(bang, live, visualmode, first_line, last_line, expr)
|
||||
" Heuristically determine if the user was in visual mode
|
||||
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]
|
||||
|
||||
if bvis && a:live
|
||||
call s:exit('Live mode is not supported in blockwise-visual mode')
|
||||
endif
|
||||
|
||||
let rules = s:easy_align_delimiters_default
|
||||
if exists('g:easy_align_delimiters')
|
||||
let rules = extend(copy(rules), g:easy_align_delimiters)
|
||||
endif
|
||||
|
||||
let [n, ch, opts, regexp] = s:parse_args(a:expr)
|
||||
|
||||
let bypass_fold = get(g:, 'easy_align_bypass_fold', 0)
|
||||
let ofm = &l:foldmethod
|
||||
try
|
||||
if bypass_fold | let &l:foldmethod = 'manual' | endif
|
||||
|
||||
if empty(n) && empty(ch) || a:live
|
||||
let [mode, n, ch, opts, regexp] = s:interactive(range, copy(modes), n, ch, opts, rules, vis, a:live)
|
||||
endif
|
||||
|
||||
if !a:live
|
||||
let output = s:process(range, mode, n, ch, s:normalize_options(opts), regexp, rules, bvis)
|
||||
call s:update_lines(output.todo)
|
||||
let copts = call('s:summarize', output.summarize)
|
||||
let g:easy_align_last_command = s:echon('', n, regexp, ch, copts, '')
|
||||
endif
|
||||
finally
|
||||
if bypass_fold | let &l:foldmethod = ofm | endif
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! easy_align#align(bang, live, visualmode, expr) range
|
||||
try
|
||||
call s:align(a:bang, a:live, a:visualmode, a:firstline, a:lastline, a:expr)
|
||||
catch 'exit'
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
||||
|
||||
1013
doc/easy_align.txt
1013
doc/easy_align.txt
File diff suppressed because it is too large
Load Diff
@@ -26,4 +26,116 @@ 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>' == '!', <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:abs(v)
|
||||
return a:v >= 0 ? a:v : - a:v
|
||||
endfunction
|
||||
|
||||
function! s:remember_visual(mode)
|
||||
let s:last_visual = [a:mode, s:abs(line("'>") - line("'<")), s: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>"
|
||||
call s:set_repeat()
|
||||
finally
|
||||
if ve_save != &virtualedit
|
||||
let &virtualedit = ve_save
|
||||
endif
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:repeat_in_visual()
|
||||
if exists('g:easy_align_last_command')
|
||||
call s:remember_visual(visualmode())
|
||||
call s:repeat_visual()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:set_repeat()
|
||||
silent! call repeat#set("\<Plug>(EasyAlignRepeat)")
|
||||
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
|
||||
call s:set_repeat()
|
||||
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>
|
||||
vnoremap <silent> <Plug>(EasyAlignRepeat) :<C-U>call <SID>repeat_in_visual()<Enter>
|
||||
|
||||
" Backward-compatibility (deprecated)
|
||||
nnoremap <silent> <Plug>(EasyAlignOperator) :set opfunc=<SID>easy_align_op<Enter>g@
|
||||
|
||||
|
||||
13
test/README.md
Normal file
13
test/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
Test cases for vim-easy-align
|
||||
=============================
|
||||
|
||||
### Prerequisite
|
||||
|
||||
- [Vader.vim](https://github.com/junegunn/vader.vim)
|
||||
|
||||
### Run
|
||||
|
||||
```
|
||||
./run
|
||||
```
|
||||
|
||||
1075
test/basic.expected
1075
test/basic.expected
File diff suppressed because it is too large
Load Diff
273
test/basic.md
273
test/basic.md
@@ -1,273 +0,0 @@
|
||||
" :source run.vim
|
||||
" @a
|
||||
|
||||
Paul McCartney 1942
|
||||
George Harrison 1943
|
||||
Ringo Starr 1940
|
||||
Pete Best 1941
|
||||
|
||||
| Option| Type | Default | Description |
|
||||
|--|--|--|--|
|
||||
| threads | Fixnum | 1 | number of threads in the thread pool |
|
||||
|queues |Fixnum | 1 | number of concurrent queues |
|
||||
|queue_size | Fixnum | 1000 | size of each queue |
|
||||
| interval | Numeric | 0 | dispatcher interval for batch processing |
|
||||
|batch | Boolean | false | enables batch processing mode |
|
||||
|batch_size | Fixnum | nil | number of maximum items to be assigned at once |
|
||||
|logger | Logger | nil | logger instance for debug logs |
|
||||
|
||||
aaa, bb,c
|
||||
d,eeeeeee
|
||||
fffff, gggggggggg,
|
||||
h, , ii
|
||||
j,,k
|
||||
|
||||
```ruby
|
||||
|
||||
a =
|
||||
a = 1
|
||||
bbbb .= 2
|
||||
ccccccc = 3
|
||||
ccccccccccccccc
|
||||
ddd = #
|
||||
eeee === eee = eee = eee=f
|
||||
fff = ggg += gg &&= gg
|
||||
g != hhhhhhhh == # 8
|
||||
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
|
||||
|
||||
options = { :caching => nil,
|
||||
:versions => 3,
|
||||
"cache=blocks" => false }.merge(options)
|
||||
|
||||
apple = 1 # comment not aligned
|
||||
banana = 'Gros Michel' # comment 2
|
||||
|
||||
# let g:easy_align_delimiters = { '#': { 'pattern': '#\+', 'ignores': ['String'] } }
|
||||
|
||||
apple = 1 # comment not aligned
|
||||
apricot = 'DAD' + 'F#AD'
|
||||
banana = 'Gros Michel' # comment 2
|
||||
|
||||
```
|
||||
|
||||
```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
|
||||
|
||||
```
|
||||
```c
|
||||
|
||||
/* a */ b = c
|
||||
aa >= bb
|
||||
// aaa = bbb = cccc
|
||||
/* aaaa = */ bbbb === cccc " = dddd = " = eeee
|
||||
aaaaa /* bbbbb */ == ccccc /* != eeeee = */ === fffff
|
||||
|
||||
```
|
||||
|
||||
my_object
|
||||
.method1.chain
|
||||
.second_method.call
|
||||
.third.call
|
||||
.method_4.execute
|
||||
|
||||
my_object.
|
||||
method1.chain.
|
||||
second_method.call.
|
||||
third.call.
|
||||
method_4.execute
|
||||
|
||||
| Option| Type | Default | Description |
|
||||
|--|--|--|--|
|
||||
| threads | Fixnum | 1 | number of threads in the thread pool |
|
||||
|queues |Fixnum | 1 | number of concurrent queues |
|
||||
|queue_size | Fixnum | 1000 | size of each queue |
|
||||
| interval | Numeric | 0 | dispatcher interval for batch processing |
|
||||
|batch | Boolean | false | enables batch processing mode |
|
||||
|batch_size | Fixnum | nil | number of maximum items to be assigned at once |
|
||||
|logger | Logger | nil | logger instance for debug logs |
|
||||
|
||||
|
||||
```c
|
||||
|
||||
const char* str = "Hello";
|
||||
int64_t count = 1 + 2;
|
||||
static double pi = 3.14;
|
||||
static std::map<std::string, float>* scores = pointer;
|
||||
|
||||
```
|
||||
|
||||
Paul McCartney 1942
|
||||
George Harrison 1943
|
||||
Ringo Starr 1940
|
||||
Pete Best 1941
|
||||
|
||||
...-.-----
|
||||
..--..----
|
||||
.---...---
|
||||
----....--
|
||||
.---.....-
|
||||
..--......
|
||||
...-.....-
|
||||
|
||||
apple = 1
|
||||
banana = 2
|
||||
cake = 3
|
||||
daisy = 4
|
||||
eggplant = 5
|
||||
|
||||
|
||||
```c
|
||||
|
||||
int a = 1;
|
||||
long b = 2;
|
||||
float c = 3;
|
||||
string d = 4;
|
||||
// this line should not get aligned
|
||||
long int e = 5;
|
||||
std::map f;
|
||||
std::map g; /* this? */
|
||||
short h /* how about this? */ = 6;
|
||||
string i = "asdf";
|
||||
|
||||
```
|
||||
|
||||
```ruby
|
||||
|
||||
a =
|
||||
a = 1
|
||||
bbbb .= 2
|
||||
ccccccc = 3
|
||||
ccccccccccccccc
|
||||
# eeeeeeeeeeeeeeee
|
||||
e # asdf
|
||||
ddd = #
|
||||
eeee === eee = eee = eee=f
|
||||
fff = ggg += gg &&= gg
|
||||
g != hhhhhhhh == # 8
|
||||
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
|
||||
|
||||
a = 1
|
||||
bb = 22
|
||||
ccc = 333
|
||||
dddd = "asdf"
|
||||
|
||||
```
|
||||
|
||||
a a a a a
|
||||
bbb bbb bbb bbb bbb
|
||||
ccccc ccccc ccccc ccccc ccccc
|
||||
d ddd dddd ddd d
|
||||
|
||||
aaaaa = 123456778901234567890 =
|
||||
bbbbbbbbbb = 12345 =
|
||||
|
||||
aaaaa = 123456778901234567890 =
|
||||
cccccccccccccccccc = 123 =
|
||||
|
||||
aaaaa = 123456778901234567890 =
|
||||
cccccccccccccccccc = 12345678 =
|
||||
|
||||
aaaaa = 12345 =
|
||||
bbbbbbbbbb = 123456778901234567890 =
|
||||
|
||||
aaaaa = 12345
|
||||
bbbbbbbbbb = 123456778901234567890
|
||||
|
||||
123456 789
|
||||
1234567890 1
|
||||
|
||||
1234 56
|
||||
123456 7890
|
||||
|
||||
aaaaa = 123456778901234567890 =
|
||||
cccccccccccccccccc = 12345678 =
|
||||
|
||||
```
|
||||
aaaaa = 123456778901234567890 =
|
||||
cccccccccccccccccc =12345678 =
|
||||
|
||||
aaaa = 123456778901234567890 =
|
||||
cccccccccccccccccc = 12345678 =
|
||||
|
||||
aaaaaaaaaaaaa = 123456778901234567890 =
|
||||
cc = 12345678 =
|
||||
|
||||
aaaaaaaaaaa= 123
|
||||
a = 123
|
||||
|
||||
aaaaaaaaaaaa= 123
|
||||
a = 123
|
||||
|
||||
aaaaaaaaaaaa = 123
|
||||
aaaaaaaaaaa = 123
|
||||
aaaaaaaaaa = 123
|
||||
aaa = 123
|
||||
aa = 123
|
||||
a = 123
|
||||
|
||||
aaaa = 123456778901234567890 =
|
||||
cccccccccccccc = 12345678 =
|
||||
|
||||
aaaa = 123456778901234567890 =
|
||||
bbbbbb = 4
|
||||
cccccccccccccccccc = 12345678 =
|
||||
|
||||
aaaa = 123456778901234567890 =
|
||||
cccccccccccccccccc = 12345678 =
|
||||
|
||||
aaaaa = 123456778901234567890 =
|
||||
cc = 12345678 =
|
||||
|
||||
=aaaaa = 123456778901234567890 =
|
||||
= cccccccccccccccccc = 12345678 =
|
||||
|
||||
```
|
||||
|
||||
a,,bbb
|
||||
aa,,bb
|
||||
aaa,,b
|
||||
aaaa,,
|
||||
aaa,b,
|
||||
aa,bb,
|
||||
a,bbb,
|
||||
|
||||
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
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
4Gvipjyvip
|
||||
154
test/commandline.vader
Normal file
154
test/commandline.vader
Normal file
@@ -0,0 +1,154 @@
|
||||
Include: include/setup.vader
|
||||
|
||||
Given (fruits):
|
||||
apple;:;;banana::cake
|
||||
data;;exchange:;::format
|
||||
|
||||
Execute (regular expression):
|
||||
%EasyAlign/[:;]\+/
|
||||
AssertEqual ':EasyAlign /[:;]\+/', g:easy_align_last_command
|
||||
|
||||
Expect:
|
||||
apple ;:;; banana::cake
|
||||
data ;; exchange:;::format
|
||||
|
||||
Execute (options dictionary):
|
||||
%EasyAlign/[:;]\+/{ 'left_margin': '<', 'right_margin': 3 }
|
||||
|
||||
Expect:
|
||||
apple<;:;; banana::cake
|
||||
data < ;; exchange:;::format
|
||||
|
||||
Execute (fuzzy matching):
|
||||
%EasyAlign/[:;]\+/{ 'l':'<', 'r': '>'}
|
||||
|
||||
Expect:
|
||||
apple<;:;;>banana::cake
|
||||
data < ;;>exchange:;::format
|
||||
|
||||
Execute (shorthand notation of margin):
|
||||
%EasyAlign/[:;]\+/l0r0
|
||||
|
||||
Expect:
|
||||
apple;:;;banana::cake
|
||||
data ;;exchange:;::format
|
||||
|
||||
Execute (delimiter align):
|
||||
%EasyAlign*/[:;]\+/l0r0dc
|
||||
|
||||
Expect:
|
||||
apple;:;;banana :: cake
|
||||
data ;; exchange:;::format
|
||||
|
||||
Execute (shorthand notation of mode_sequence and margin):
|
||||
%EasyAlign/[:;]\+/mrc*l2r2
|
||||
|
||||
Expect:
|
||||
apple ;:;; banana :: cake
|
||||
data ;; exchange :;:: format
|
||||
|
||||
Execute (deep indentation):
|
||||
%EasyAlign/[:;]\+/mrc*l2r2
|
||||
%EasyAlign*/[:;]\+/idmrl*
|
||||
|
||||
Expect:
|
||||
apple ;:;; banana :: cake
|
||||
data ;; exchange :;:: format
|
||||
|
||||
Execute (stick_to_left):
|
||||
%EasyAlign*/[:;]\+/stl1l0dlrm3
|
||||
|
||||
Expect:
|
||||
apple;:;; banana:: cake
|
||||
data;; exchange:;:: format
|
||||
|
||||
Execute (different regular expression):
|
||||
%EasyAlign*/../{'lm':'<','rm':'>'}
|
||||
|
||||
Expect:
|
||||
ap><pl><e;><:;><;b><an><an><a:><:c><ak>e
|
||||
da><ta><;;><ex><ch><an><ge><:;><::><fo><rm><at
|
||||
|
||||
Execute (merge different option notations):
|
||||
%EasyAlign*/../iu0 { 'l': '<', 'r': '>' }
|
||||
|
||||
Expect:
|
||||
ap><pl><e;><:;><;b><an><an><a:><:c><ak>e
|
||||
da><ta><;;><ex><ch><an><ge><:;><::><fo> <rm><at
|
||||
|
||||
Given javascript (json):
|
||||
var jdbc = {
|
||||
// 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"
|
||||
};
|
||||
|
||||
Execute (default syntax-aware alignment):
|
||||
%EasyAlign*:
|
||||
|
||||
Expect javascript:
|
||||
var jdbc = {
|
||||
// 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"
|
||||
};
|
||||
|
||||
Execute (do not ignore unmatched):
|
||||
%EasyAlign*:iu0
|
||||
|
||||
Expect javascript:
|
||||
var jdbc = {
|
||||
// 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"
|
||||
};
|
||||
|
||||
Execute (do not ignore any group):
|
||||
%EasyAlign*:ig[]iu0
|
||||
|
||||
Expect javascript:
|
||||
var jdbc = {
|
||||
// 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"
|
||||
};
|
||||
|
||||
Execute (ignore only strings):
|
||||
%EasyAlign*:ig['String']
|
||||
|
||||
Expect javascript:
|
||||
var jdbc = {
|
||||
// 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"
|
||||
};
|
||||
|
||||
Execute (ignore only comments):
|
||||
%EasyAlign*:ig['Comment']
|
||||
|
||||
Expect javascript:
|
||||
var jdbc = {
|
||||
// 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"
|
||||
};
|
||||
|
||||
Include: include/teardown.vader
|
||||
142
test/fixed.vader
Normal file
142
test/fixed.vader
Normal file
@@ -0,0 +1,142 @@
|
||||
Include: include/setup.vader
|
||||
|
||||
Given (Table):
|
||||
|a|b|c|d|
|
||||
| -|-|>-|-|
|
||||
|aaa|bbb|ccc|ddd|
|
||||
|
||||
Do (Partial alignment around 1st |):
|
||||
\<C-V>ljj\<Enter>|
|
||||
|
||||
Expect (Right margin should be correctly attached):
|
||||
| a|b|c|d|
|
||||
| -|-|>-|-|
|
||||
| aaa|bbb|ccc|ddd|
|
||||
|
||||
Given (empty buffer):
|
||||
|
||||
Execute (Aligning lines with many delimiters should not fail):
|
||||
call visualmode(1)
|
||||
call setline(1, repeat('|', &maxfuncdepth + 1))
|
||||
%EasyAlign*|
|
||||
AssertEqual (&maxfuncdepth + 1) * 3 - 2, len(getline(1))
|
||||
|
||||
Given:
|
||||
a | b | c
|
||||
aa | bb | cc
|
||||
|
||||
Execute:
|
||||
%EasyAlign*|iu0{'l':'<', 'r': '>'}
|
||||
|
||||
Expect:
|
||||
a <|>b <|>c
|
||||
aa<|>bb<|>cc
|
||||
|
||||
Given (Trailing delimiter):
|
||||
a | b | c |
|
||||
aa | bb | cc |
|
||||
|
||||
Execute:
|
||||
%EasyAlign*|iu0{'l':'<', 'r': '>'}
|
||||
|
||||
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 = {}
|
||||
|
||||
Given (Tab-indented code (#20)):
|
||||
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 = {}
|
||||
|
||||
Include: include/teardown.vader
|
||||
24
test/fixme.vader
Normal file
24
test/fixme.vader
Normal file
@@ -0,0 +1,24 @@
|
||||
Include: include/setup.vader
|
||||
|
||||
# It is currently possible that EasyAlign command incorrectly judges
|
||||
# that it was executed in block-wise visual mode
|
||||
Given:
|
||||
a|b|c
|
||||
|
||||
Do (FIXME invalid judgement - block-wise visual mode):
|
||||
\<C-V>\<Esc>
|
||||
:%EasyAlign|\<CR>
|
||||
|
||||
Expect:
|
||||
a | b | c
|
||||
|
||||
Do (TODO Workaround: reset visualmode() on error):
|
||||
\<C-V>\<Esc>
|
||||
:%EasyAlign|\<CR>
|
||||
:%EasyAlign|\<CR>
|
||||
|
||||
Expect:
|
||||
a | b | c
|
||||
|
||||
Include: include/teardown.vader
|
||||
|
||||
32
test/include/setup.vader
Normal file
32
test/include/setup.vader
Normal file
@@ -0,0 +1,32 @@
|
||||
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, g:easy_align_bypass_fold
|
||||
Save &tabstop, mapleader
|
||||
|
||||
unlet! g:easy_align_ignore_groups
|
||||
unlet! g:easy_align_ignore_unmatched
|
||||
unlet! g:easy_align_indentation
|
||||
unlet! g:easy_align_delimiter_align
|
||||
unlet! g:easy_align_interactive_modes
|
||||
unlet! g:easy_align_bang_interactive_modes
|
||||
unlet! g:easy_align_bypass_fold
|
||||
|
||||
let g:easy_align_delimiters = {}
|
||||
let mapleader = ' '
|
||||
vnoremap <silent> r<Enter> :EasyAlign!<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)
|
||||
|
||||
set ts=2
|
||||
|
||||
vmap <Enter> <Plug>(EasyAlign)
|
||||
vmap <leader><Enter> <Plug>(LiveEasyAlign)
|
||||
nmap <leader>A <Plug>(EasyAlign)
|
||||
vmap <leader>. <Plug>(EasyAlignRepeat)
|
||||
|
||||
3
test/include/teardown.vader
Normal file
3
test/include/teardown.vader
Normal file
@@ -0,0 +1,3 @@
|
||||
Execute:
|
||||
Restore
|
||||
|
||||
1591
test/interactive.vader
Normal file
1591
test/interactive.vader
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,108 +0,0 @@
|
||||
" :source run.vim
|
||||
" @a
|
||||
|
||||
apple;:banana :: cake
|
||||
data;;exchange :; format
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;; exchange :; format
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;; exchange :; format
|
||||
|
||||
apple ;:____banana::cake
|
||||
data ;;____exchange:;format
|
||||
|
||||
apple ; : banana : : cake
|
||||
data ; ; exchange : ; format
|
||||
|
||||
ap pl e; :b an an a: :c ak e
|
||||
da ta ;; ex ch an ge :; fo rm at
|
||||
|
||||
ap ple;:banana::cake
|
||||
da ta;;exchange:;format
|
||||
|
||||
apple???;:~~~banana???::~~~ cake
|
||||
data???;;~~~ exchange???:;~~~format
|
||||
|
||||
apple;: banana::cake
|
||||
data;; exchange:;format
|
||||
|
||||
apple<<<;:>>>banana::cake
|
||||
data <<<;;>>>exchange:;format
|
||||
|
||||
apple ;: banana::cake
|
||||
data ;; exchange:;format
|
||||
|
||||
apple;:banana :: cake
|
||||
data;;exchange :; format
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;; exchange :; format
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;; exchange :; format
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;; exchange :; format
|
||||
|
||||
apple ;: banana :: cake
|
||||
data ;; exchange :; format
|
||||
|
||||
apple ;: banana::cake
|
||||
data ;; exchange:;format
|
||||
|
||||
apple ; :banana::cake
|
||||
data ; ; exchange: ; format
|
||||
|
||||
apple ; :banana::cake
|
||||
data ; ;exchange:;format
|
||||
|
||||
apple ; :banana::cake
|
||||
data ; ;exchange:;format
|
||||
|
||||
apple;:banana::cake
|
||||
data;;exchange:;format
|
||||
|
||||
apple;: banana: : cake
|
||||
data;;exchange: ;format
|
||||
|
||||
apple;:banana: :cake
|
||||
data;;exchange:;format
|
||||
|
||||
apple;:banana: :cake
|
||||
data;;exchange:;format
|
||||
|
||||
apple;: banana: : cake
|
||||
data;;exchange: ;format
|
||||
|
||||
apple;:banana:: cake
|
||||
data;;exchange: ;format
|
||||
|
||||
apple;: banana: : cake
|
||||
data;;exchange: ;format
|
||||
|
||||
apple;: banana::cake
|
||||
data;;exchange: ;format
|
||||
|
||||
```ruby
|
||||
apple = 1 # comment not aligned
|
||||
apricot = 'DAD' + 'F#AD'
|
||||
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,12 +0,0 @@
|
||||
" :source run.vim
|
||||
" @a
|
||||
|
||||
apple;:banana::cake
|
||||
data;;exchange:;format
|
||||
|
||||
```ruby
|
||||
apple = 1 # comment not aligned
|
||||
apricot = 'DAD' + 'F#AD'
|
||||
banana = 'Gros Michel' # comment 2
|
||||
```
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
4Gvipjyvip:EasyAlign:
|
||||
11
test/run
Executable file
11
test/run
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd $(dirname $BASH_SOURCE)
|
||||
|
||||
vim -Nu <(cat << EOF
|
||||
syntax on
|
||||
for dep in ['vader.vim', 'vim-repeat']
|
||||
execute 'set rtp+=' . finddir(dep, expand('~/.vim').'/**')
|
||||
endfor
|
||||
set rtp+=..
|
||||
EOF) +Vader*
|
||||
51
test/run.vim
51
test/run.vim
@@ -1,51 +0,0 @@
|
||||
e!
|
||||
|
||||
function! GFM()
|
||||
let syntaxes = {
|
||||
\ 'ruby': 'syntax/ruby.vim',
|
||||
\ 'yaml': 'syntax/yaml.vim',
|
||||
\ 'vim': 'syntax/vim.vim',
|
||||
\ 'sh': 'syntax/sh.vim',
|
||||
\ 'python': 'syntax/python.vim',
|
||||
\ 'java': 'syntax/java.vim',
|
||||
\ 'c': 'syntax/c.vim'
|
||||
\ }
|
||||
|
||||
for [lang, syn] in items(syntaxes)
|
||||
unlet b:current_syntax
|
||||
silent! exec printf("syntax include @%s %s", lang, syn)
|
||||
exec printf("syntax region %sSnip matchgroup=Snip start='```%s' end='```' contains=@%s",
|
||||
\ lang, lang, lang)
|
||||
endfor
|
||||
let b:current_syntax='mkd'
|
||||
|
||||
syntax sync fromstart
|
||||
endfunction
|
||||
|
||||
silent! unlet g:easy_align_delimiters
|
||||
silent! unlet g:easy_align_ignore_unmatched
|
||||
silent! unlet g:easy_align_ignores
|
||||
|
||||
vnoremap <silent> <Enter> :EasyAlign<cr>
|
||||
|
||||
noremap <silent> <C-k> <nop>
|
||||
noremap <silent> <C-j> <nop>
|
||||
noremap <silent> <C-h> <nop>
|
||||
noremap <silent> <C-l> <nop>
|
||||
vnoremap <silent> <C-k> <nop>
|
||||
vnoremap <silent> <C-j> <nop>
|
||||
vnoremap <silent> <C-h> <nop>
|
||||
vnoremap <silent> <C-l> <nop>
|
||||
|
||||
set nolazyredraw
|
||||
set buftype=nofile
|
||||
set colorcolumn=
|
||||
|
||||
silent! ScrollPositionHide
|
||||
|
||||
call GFM()
|
||||
|
||||
normal gg
|
||||
let @b=system('cat '. expand('%:p:r') . '.script')
|
||||
let @a='@b:vert diffsplit ' . expand('%:p:r') . '.expected
|
||||
'
|
||||
158
test/tex.vader
Normal file
158
test/tex.vader
Normal file
@@ -0,0 +1,158 @@
|
||||
# http://en.wikibooks.org/wiki/LaTeX/Tables
|
||||
|
||||
Include: include/setup.vader
|
||||
|
||||
Given tex (table with escaped &):
|
||||
\begin{tabular}{ l c r }
|
||||
1&2&3\\
|
||||
44&55&66\\
|
||||
777&8\&8&999\\
|
||||
\end{tabular}
|
||||
|
||||
# FIXME vip doesn't work if folded
|
||||
Do (Align around all &s and \\s):
|
||||
VG\<Enter>*&
|
||||
|
||||
Expect tex:
|
||||
\begin{tabular}{ l c r }
|
||||
1 & 2 & 3 \\
|
||||
44 & 55 & 66 \\
|
||||
777 & 8\&8 & 999 \\
|
||||
\end{tabular}
|
||||
|
||||
Do (right-align with explicit ignore_unmatched):
|
||||
VG\<Enter>\<Enter>\<C-U>\<C-U>*&
|
||||
|
||||
Expect tex:
|
||||
\begin{tabular}{ l c r }
|
||||
1 & 2 & 3 \\
|
||||
44 & 55 & 66 \\
|
||||
777 & 8\&8 & 999 \\
|
||||
\end{tabular}
|
||||
|
||||
Do (center-align with explicit ignore_unmatched):
|
||||
VG\<Enter>\<Enter>\<Enter>\<C-U>\<C-U>*&
|
||||
|
||||
Expect tex:
|
||||
\begin{tabular}{ l c r }
|
||||
1 & 2 & 3 \\
|
||||
44 & 55 & 66 \\
|
||||
777 & 8\&8 & 999 \\
|
||||
\end{tabular}
|
||||
|
||||
Given tex (simple table with \hline):
|
||||
\begin{tabular}{ l c r }
|
||||
1&2&3\\ \hline
|
||||
44&55&66\\ \hline
|
||||
777&8\&&999\\ \hline
|
||||
\end{tabular}
|
||||
|
||||
Do:
|
||||
VG\<Enter>*&
|
||||
|
||||
Expect tex:
|
||||
\begin{tabular}{ l c r }
|
||||
1 & 2 & 3 \\ \hline
|
||||
44 & 55 & 66 \\ \hline
|
||||
777 & 8\& & 999 \\ \hline
|
||||
\end{tabular}
|
||||
|
||||
Given tex (table with lines w/o &s):
|
||||
\begin{tabular}{|r|l|}
|
||||
\hline
|
||||
7C0 & hexadecimal \\
|
||||
3700&octal \\ \cline{2-2}
|
||||
1111100000 & binary \\
|
||||
\hline \hline
|
||||
1984 & decimal \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
|
||||
Do (left-align*):
|
||||
VG\<Enter>*&
|
||||
|
||||
Expect tex:
|
||||
\begin{tabular}{|r|l|}
|
||||
\hline
|
||||
7C0 & hexadecimal \\
|
||||
3700 & octal \\ \cline{2-2}
|
||||
1111100000 & binary \\
|
||||
\hline \hline
|
||||
1984 & decimal \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
|
||||
Do(left-align* and right-align around 2nd):
|
||||
VG\<Enter>*&
|
||||
gv\<Enter>\<Enter>2&
|
||||
|
||||
Expect tex:
|
||||
\begin{tabular}{|r|l|}
|
||||
\hline
|
||||
7C0 & hexadecimal \\
|
||||
3700 & octal \\ \cline{2-2}
|
||||
1111100000 & binary \\
|
||||
\hline \hline
|
||||
1984 & decimal \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
|
||||
Given tex:
|
||||
\begin{tabular}{}
|
||||
32&1.14\e1&&5.65\e2&&&&1.16\e1&&1.28\e1&\\
|
||||
64&1.03\e1&0.1&4.98\e2&0.2&&&9.21\e2&0.3&1.02\e1&0.3\\
|
||||
128&9.86\e2&0.1&4.69\e2&0.1&&&8.46\e2&0.1&9.45\e2&0.1\\
|
||||
256&9.65\e2&0.0&4.59\e2&0.0&&&8.15\e2&0.1&9.11\e2&0.1\\
|
||||
% 512&9.55\e2&0.0&4.56\e2&0.0&&&8.01\e2&0.0&8.96\e2&0.0\\
|
||||
1024&9.49\e2&0.0&4.53\e2&0.0&&&7.94\e2&0.0&8.89\e2&0.0\\
|
||||
2048&9.47\e2&0.0&4.52\e2&0.0&&&7.91\e2&0.0&8.85\e2&0.0\\
|
||||
4096&9.46\e2&0.0&4.51\e2&0.0%&&&7.90\e2&0.0&8.83\e2&0.0\\
|
||||
8192&9.45\e2&0.0&4.51\e2&0.0&&&&&&\\
|
||||
\end{tabular}
|
||||
|
||||
Execute (Alignment around &s, foldmethod should not change):
|
||||
setlocal foldmethod=syntax
|
||||
%EasyAlign*&
|
||||
AssertEqual 'syntax', &l:foldmethod
|
||||
|
||||
setlocal foldmethod=manual
|
||||
%EasyAlign*&
|
||||
AssertEqual 'manual', &l:foldmethod
|
||||
|
||||
Expect tex:
|
||||
\begin{tabular}{}
|
||||
32 & 1.14\e1 & & 5.65\e2 & & & & 1.16\e1 & & 1.28\e1 & \\
|
||||
64 & 1.03\e1 & 0.1 & 4.98\e2 & 0.2 & & & 9.21\e2 & 0.3 & 1.02\e1 & 0.3 \\
|
||||
128 & 9.86\e2 & 0.1 & 4.69\e2 & 0.1 & & & 8.46\e2 & 0.1 & 9.45\e2 & 0.1 \\
|
||||
256 & 9.65\e2 & 0.0 & 4.59\e2 & 0.0 & & & 8.15\e2 & 0.1 & 9.11\e2 & 0.1 \\
|
||||
% 512&9.55\e2&0.0&4.56\e2&0.0&&&8.01\e2&0.0&8.96\e2&0.0\\
|
||||
1024 & 9.49\e2 & 0.0 & 4.53\e2 & 0.0 & & & 7.94\e2 & 0.0 & 8.89\e2 & 0.0 \\
|
||||
2048 & 9.47\e2 & 0.0 & 4.52\e2 & 0.0 & & & 7.91\e2 & 0.0 & 8.85\e2 & 0.0 \\
|
||||
4096 & 9.46\e2 & 0.0 & 4.51\e2 & 0.0%&&&7.90\e2&0.0&8.83\e2&0.0\\
|
||||
8192 & 9.45\e2 & 0.0 & 4.51\e2 & 0.0 & & & & & & \\
|
||||
\end{tabular}
|
||||
|
||||
Execute (g:easy_align_bypass_fold set, foldmethod should not change):
|
||||
let g:easy_align_bypass_fold = 1
|
||||
setlocal foldmethod=syntax
|
||||
%EasyAlign*&
|
||||
AssertEqual 'syntax', &l:foldmethod
|
||||
|
||||
setlocal foldmethod=manual
|
||||
%EasyAlign*&
|
||||
AssertEqual 'manual', &l:foldmethod
|
||||
|
||||
Expect tex:
|
||||
\begin{tabular}{}
|
||||
32 & 1.14\e1 & & 5.65\e2 & & & & 1.16\e1 & & 1.28\e1 & \\
|
||||
64 & 1.03\e1 & 0.1 & 4.98\e2 & 0.2 & & & 9.21\e2 & 0.3 & 1.02\e1 & 0.3 \\
|
||||
128 & 9.86\e2 & 0.1 & 4.69\e2 & 0.1 & & & 8.46\e2 & 0.1 & 9.45\e2 & 0.1 \\
|
||||
256 & 9.65\e2 & 0.0 & 4.59\e2 & 0.0 & & & 8.15\e2 & 0.1 & 9.11\e2 & 0.1 \\
|
||||
% 512&9.55\e2&0.0&4.56\e2&0.0&&&8.01\e2&0.0&8.96\e2&0.0\\
|
||||
1024 & 9.49\e2 & 0.0 & 4.53\e2 & 0.0 & & & 7.94\e2 & 0.0 & 8.89\e2 & 0.0 \\
|
||||
2048 & 9.47\e2 & 0.0 & 4.52\e2 & 0.0 & & & 7.91\e2 & 0.0 & 8.85\e2 & 0.0 \\
|
||||
4096 & 9.46\e2 & 0.0 & 4.51\e2 & 0.0%&&&7.90\e2&0.0&8.83\e2&0.0\\
|
||||
8192 & 9.45\e2 & 0.0 & 4.51\e2 & 0.0 & & & & & & \\
|
||||
\end{tabular}
|
||||
|
||||
Include: include/teardown.vader
|
||||
Reference in New Issue
Block a user