mirror of
https://github.com/junegunn/vim-easy-align.git
synced 2025-11-10 10:53:49 -05:00
Add a proper support for \@=
This commit is contained in:
45
EXAMPLES.md
45
EXAMPLES.md
@@ -127,7 +127,6 @@ Try `<Enter>:` here, to align text around only the first occurrences of colons.
|
||||
In this case, you don't want to align around all the colons: `<Enter>*:`.
|
||||
|
||||
```yaml
|
||||
|
||||
mysql:
|
||||
# JDBC driver for MySQL database:
|
||||
driver: com.mysql.jdbc.Driver
|
||||
@@ -135,7 +134,6 @@ mysql:
|
||||
url: jdbc:mysql://localhost/test
|
||||
database: test
|
||||
"user:pass":r00t:pa55
|
||||
|
||||
```
|
||||
|
||||
Formatting multi-line method chaining
|
||||
@@ -220,7 +218,7 @@ So, how do we align the trailing comments in the above lines?
|
||||
Simply try `<Enter>-<space>`. The spaces in the comments are ignored, so the
|
||||
trailing comment in each line is considered to be a single chunk.
|
||||
|
||||
But this doesn't work in the following case.
|
||||
But that doesn't work in the following case.
|
||||
|
||||
```ruby
|
||||
apple = 1 # comment not aligned
|
||||
@@ -262,17 +260,26 @@ command:
|
||||
|
||||
In this case, the second line is ignored as it doesn't contain a `#`. (The one
|
||||
highlighted as String is ignored.) If you don't want the second line to be
|
||||
ignored, set `g:easy_align_ignore_unmatched` to 0, or use the following
|
||||
commands:
|
||||
ignored, there are three options:
|
||||
|
||||
1. Set `g:easy_align_ignore_unmatched` to 0
|
||||
2. Use the following commands:
|
||||
|
||||
```vim
|
||||
" Using predefined rule with delimiter key #
|
||||
" - "iu" is fuzzy-matched to "*i*gnore_*u*nmatched"
|
||||
:EasyAlign#{'iu':0}`
|
||||
|
||||
" Using regular expression /#/
|
||||
:EasyAlign/#/{'is':['String'],'iu':0}`
|
||||
```
|
||||
|
||||
3. Update the rule with `ignore_unmatched`
|
||||
|
||||
```vim
|
||||
let g:easy_align_delimiters['#'] = { 'pattern': '#', 'ignores': ['String'], 'ignore_unmatched': 0 } }
|
||||
```
|
||||
|
||||
Then we get,
|
||||
|
||||
```ruby
|
||||
@@ -302,18 +309,18 @@ static double pi = 3.14;
|
||||
```
|
||||
|
||||
Not bad. However, the names of the variables, `str`, `count`, and `pi` are not
|
||||
aligned with each other. Can we do better? You can clearly see that simple
|
||||
`<Enter><space>` won't properly align those names. So we define a rule for such
|
||||
cases.
|
||||
aligned with each other. Can we do better? We can clearly see that simple
|
||||
`<Enter><space>` won't properly align those names.
|
||||
So let's define an alignment rule than can handle this case.
|
||||
|
||||
```vim
|
||||
let g:easy_align_delimiters['d'] = {
|
||||
\ 'pattern': '\(const\|static\)\@<!\s\+',
|
||||
\ 'pattern': '\(const\|static\)\@<! ',
|
||||
\ 'left_margin': 0, 'right_margin': 0
|
||||
\ }
|
||||
```
|
||||
|
||||
This new rule aligns text around whitespaces that are not preceded by
|
||||
This new rule aligns text around spaces that are *not* preceded by
|
||||
`const` or `static`. Let's try it with `<Enter>d`.
|
||||
|
||||
```c
|
||||
@@ -322,8 +329,8 @@ int64_t count = 1 + 2;
|
||||
static double pi = 3.14;
|
||||
```
|
||||
|
||||
Okay, now the names are aligned. We select the lines again with `gv`, and then
|
||||
press `<Enter>=` to finalize our alignment.
|
||||
Okay, the names are now aligned. We select the lines again with `gv`, and then
|
||||
press `<Enter>=` to finish our alignment.
|
||||
|
||||
```c
|
||||
const char* str = "Hello";
|
||||
@@ -331,35 +338,35 @@ int64_t count = 1 + 2;
|
||||
static double pi = 3.14;
|
||||
```
|
||||
|
||||
Looks good. However, this rule is not sufficient to handle more complex cases
|
||||
such as C++ templates or Java generics. Take the following examples.
|
||||
So far, so good. However, this rule is not sufficient to handle more complex
|
||||
cases involving C++ templates or Java generics. Take the following examples:
|
||||
|
||||
```c
|
||||
const char* str = "Hello";
|
||||
int64_t count = 1 + 2;
|
||||
static double pi = 3.14;
|
||||
static std::map<std::string, float>* scores = pointer;
|
||||
static std::map<std::string, float>* scores = pointer;
|
||||
```
|
||||
|
||||
We see that our rule fails with the new fourth line.
|
||||
We see that our rule above doesn't work anymore.
|
||||
|
||||
```c
|
||||
const char* str = "Hello";
|
||||
int64_t count = 1 + 2;
|
||||
static double pi = 3.14;
|
||||
static std::map<std::string, float>* scores = pointer;
|
||||
static std::map<std::string, float>* scores = pointer;
|
||||
```
|
||||
|
||||
So what do we do? Let's try to improve our alignment rule.
|
||||
|
||||
```vim
|
||||
let g:easy_align_delimiters['d'] = {
|
||||
\ 'pattern': '\s\+\(\S\+\s*[;=]\)\@=',
|
||||
\ 'pattern': ' \(\S\+\s*[;=]\)\@=',
|
||||
\ 'left_margin': 0, 'right_margin': 0
|
||||
\ }
|
||||
```
|
||||
|
||||
Now the new rule has changed to align text around whitespaces that are followed
|
||||
Now the new rule has changed to align text around spaces that are followed
|
||||
by some non-whitespace characters and then an equals sign or a semi-colon.
|
||||
Try `<Enter>d`
|
||||
|
||||
|
||||
@@ -139,54 +139,75 @@ function! s:validate_options(opts)
|
||||
return a:opts
|
||||
endfunction
|
||||
|
||||
function! s:do_align(just, all_tokens, fl, ll, fc, lc, pattern, nth, ml, mr, stick_to_left, ignore_unmatched, ignores, recursive)
|
||||
function! s:split_line(line, fc, lc, pattern, stick_to_left, ignore_unmatched, ignores)
|
||||
let left = a:lc ?
|
||||
\ strpart(getline(a:line), a:fc - 1, a:lc - a:fc + 1) :
|
||||
\ strpart(getline(a:line), a:fc - 1)
|
||||
let idx = 0
|
||||
" Do not allow \zs
|
||||
" 1: whole match
|
||||
" 2: token
|
||||
" 3: delimiter
|
||||
let pattern = '^\(\(.\{-}\s*\)\(' .a:pattern. '\)\s' . (a:stick_to_left ? '*' : '\{-}') . '\)'
|
||||
let tokens = []
|
||||
let delims = []
|
||||
|
||||
" Phase 1: split
|
||||
let ignorable = 0
|
||||
let token = ''
|
||||
while 1
|
||||
let matches = matchlist(left, pattern, idx)
|
||||
if empty(matches) | break | endif
|
||||
|
||||
let ignorable = s:highlighted_as(a:line, idx + len(matches[2]) + a:fc, a:ignores)
|
||||
if ignorable
|
||||
let token .= matches[1]
|
||||
else
|
||||
call add(tokens, token . matches[1])
|
||||
call add(delims, matches[3])
|
||||
let token = ''
|
||||
endif
|
||||
|
||||
if empty(matches[1])
|
||||
call s:exit("Invalid regular expression")
|
||||
endif
|
||||
let idx += len(matches[1])
|
||||
endwhile
|
||||
|
||||
let leftover = token . strpart(left, idx)
|
||||
if !empty(leftover)
|
||||
call add(tokens, leftover)
|
||||
call add(delims, '')
|
||||
endif
|
||||
|
||||
" Skip comment line
|
||||
if ignorable && len(tokens) == 1 && a:ignore_unmatched
|
||||
let tokens = []
|
||||
let delims = []
|
||||
endif
|
||||
|
||||
return [tokens, delims]
|
||||
endfunction
|
||||
|
||||
function! s:do_align(just, all_tokens, all_delims, fl, ll, fc, lc, pattern, nth, ml, mr, stick_to_left, ignore_unmatched, ignores, recursive)
|
||||
let lines = {}
|
||||
let max_just_len = 0
|
||||
let max_delim_len = 0
|
||||
let max_tokens = 0
|
||||
let min_indent = -1
|
||||
let pattern = '\s*\(' .a:pattern. '\)\s' . (a:stick_to_left ? '*' : '\{-}')
|
||||
|
||||
" Phase 1
|
||||
for line in range(a:fl, a:ll)
|
||||
if !has_key(a:all_tokens, line)
|
||||
" Split line into the tokens by the delimiters
|
||||
let raw_tokens = split(a:lc ?
|
||||
\ strpart(getline(line), a:fc - 1, a:lc - a:fc + 1) :
|
||||
\ strpart(getline(line), a:fc - 1),
|
||||
\ pattern.'\zs')
|
||||
let concat = 0
|
||||
if empty(a:ignores)
|
||||
let tokens = raw_tokens
|
||||
else
|
||||
" Concat adjacent tokens that are split by ignorable delimiters
|
||||
let tokens = []
|
||||
let idx = 0
|
||||
for token in raw_tokens
|
||||
let idx += len(token)
|
||||
if concat
|
||||
let tokens[len(tokens) - 1] .= token
|
||||
else
|
||||
call add(tokens, token)
|
||||
endif
|
||||
let concat = s:highlighted_as(line, idx + a:fc - 1, a:ignores)
|
||||
endfor
|
||||
endif
|
||||
|
||||
" Preserve indentation - merge first two tokens
|
||||
if !empty(tokens) && match(tokens[0], '^\s*$') != -1
|
||||
let tokens = extend([join(tokens[0:1], '')], tokens[2:-1])
|
||||
endif
|
||||
|
||||
" Skip comment line
|
||||
if concat && len(tokens) == 1 && a:ignore_unmatched
|
||||
let tokens = []
|
||||
endif
|
||||
let [tokens, delims] = s:split_line(line, a:fc, a:lc, a:pattern, a:stick_to_left, a:ignore_unmatched, a:ignores)
|
||||
|
||||
" Remember tokens for subsequent recursive calls
|
||||
let a:all_tokens[line] = tokens
|
||||
let a:all_delims[line] = delims
|
||||
else
|
||||
let tokens = a:all_tokens[line]
|
||||
let delims = a:all_delims[line]
|
||||
endif
|
||||
|
||||
" Skip empty lines
|
||||
@@ -204,7 +225,7 @@ function! s:do_align(just, all_tokens, fl, ll, fc, lc, pattern, nth, ml, mr, sti
|
||||
let nth = a:nth - 1 " make it 0-based
|
||||
else " Negative field number
|
||||
let nth = len(tokens) + a:nth
|
||||
if match(tokens[len(tokens) - 1], pattern.'$') == -1
|
||||
if empty(delims[len(delims) - 1])
|
||||
let nth -= 1
|
||||
endif
|
||||
|
||||
@@ -213,11 +234,10 @@ function! s:do_align(just, all_tokens, fl, ll, fc, lc, pattern, nth, ml, mr, sti
|
||||
endif
|
||||
endif
|
||||
|
||||
let last = tokens[nth]
|
||||
let prefix = (nth > 0 ? join(tokens[0 : nth - 1], '') : '')
|
||||
let token = substitute(last, pattern.'$', '', '')
|
||||
|
||||
let delim = get(matchlist(last, pattern.'$'), 1, '')
|
||||
let prefix = nth > 0 ? join(tokens[0 : nth - 1], '') : ''
|
||||
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:just == 0 && a:ignore_unmatched
|
||||
continue
|
||||
endif
|
||||
@@ -234,6 +254,7 @@ function! s:do_align(just, all_tokens, fl, ll, fc, lc, pattern, nth, ml, mr, sti
|
||||
" Phase 2
|
||||
for [line, elems] in items(lines)
|
||||
let tokens = a:all_tokens[line]
|
||||
let delims = a:all_delims[line]
|
||||
let [nth, prefix, token, delim] = elems
|
||||
|
||||
" Remove the leading whitespaces of the next token
|
||||
@@ -296,7 +317,7 @@ function! s:do_align(just, all_tokens, fl, ll, fc, lc, pattern, nth, ml, mr, sti
|
||||
|
||||
if a:recursive && a:nth < max_tokens
|
||||
let just = a:recursive == 2 ? !a:just : a:just
|
||||
call s:do_align(just, a:all_tokens, a:fl, a:ll, a:fc, a:lc, a:pattern,
|
||||
call s:do_align(just, a:all_tokens, a:all_delims, a:fl, a:ll, a:fc, a:lc, a:pattern,
|
||||
\ a:nth + 1, a:ml, a:mr, a:stick_to_left, a:ignore_unmatched,
|
||||
\ a:ignores, a:recursive)
|
||||
endif
|
||||
@@ -384,10 +405,6 @@ function! s:parse_args(args)
|
||||
try | call matchlist('', regexp)
|
||||
catch | call s:exit("Invalid regular expression: ". regexp)
|
||||
endtry
|
||||
" Unsupported regular expression
|
||||
if match(regexp, '\\zs') != -1
|
||||
call s:exit("Using \\zs is not allowed. Use stick_to_left option instead.")
|
||||
endif
|
||||
return [matches[1], regexp, option, 1]
|
||||
else
|
||||
let tokens = matchlist(args, '^\([1-9][0-9]*\|-[0-9]*\|\*\*\?\)\?\s*\(.\{-}\)\?$')
|
||||
@@ -461,7 +478,8 @@ function! easy_align#align(just, expr) range
|
||||
if type(ml) == 0 | let ml = repeat(' ', ml) | endif
|
||||
if type(mr) == 0 | let mr = repeat(' ', mr) | endif
|
||||
|
||||
call s:do_align(just, {}, a:firstline, a:lastline,
|
||||
try
|
||||
call s:do_align(just, {}, {}, a:firstline, a:lastline,
|
||||
\ visualmode() == '' ? min([col("'<"), col("'>")]) : 1,
|
||||
\ visualmode() == '' ? max([col("'<"), col("'>")]) : 0,
|
||||
\ get(dict, 'pattern', ch),
|
||||
@@ -472,6 +490,8 @@ function! easy_align#align(just, expr) range
|
||||
\ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 1)),
|
||||
\ get(dict, 'ignores', s:ignored_syntax()),
|
||||
\ recur)
|
||||
call s:echon(just, n, regexp ? '/'.ch.'/' : ch)
|
||||
call s:echon(just, n, regexp ? '/'.ch.'/' : ch)
|
||||
catch 'exit'
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -233,6 +233,14 @@ 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
|
||||
|
||||
mysql:
|
||||
# JDBC driver for MySQL database:
|
||||
driver: com.mysql.jdbc.Driver
|
||||
@@ -337,15 +345,6 @@ my_object .
|
||||
| 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;
|
||||
|
||||
```
|
||||
|
||||
|Option |Type |Default |Description |
|
||||
|-- |-- |-- |-- |
|
||||
|threads |Fixnum |1 |number of threads in the thread pool |
|
||||
@@ -366,3 +365,12 @@ static std::map<std::string, float>* scores = pointer;
|
||||
| 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;
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ my_object.
|
||||
const char* str = "Hello";
|
||||
int64_t count = 1 + 2;
|
||||
static double pi = 3.14;
|
||||
static std::map<std::string, float>* scores = pointer;
|
||||
static std::map<std::string, float>* scores = pointer;
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
4Gvipjyvip
|
||||
4Gvipjyvip
|
||||
|
||||
@@ -39,4 +39,5 @@ set buftype=nofile
|
||||
silent! ScrollPositionHide
|
||||
|
||||
call GFM()
|
||||
syntax sync fromstart
|
||||
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
e!
|
||||
execute 'source '. expand('%:p:h') . '/include.vim'
|
||||
|
||||
while line('.') < line('$')
|
||||
normal 30j
|
||||
redraw
|
||||
endwhile
|
||||
|
||||
normal gg
|
||||
let @b=system('cat '. expand('%:p:r') . '.script')
|
||||
let @a='@b:vert diffsplit ' . expand('%:p:r') . '.expected
|
||||
'
|
||||
" Syntax highlighting doesn't work
|
||||
'
|
||||
|
||||
Reference in New Issue
Block a user