113 changed files with 10090 additions and 1218 deletions
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
MIT license |
||||
|
||||
Copyright (c) 2020 Andy Massimino |
||||
|
||||
Copyright (c) 2016 Karl Yngve Lervåg |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||
this software and associated documentation files (the "Software"), to deal in |
||||
the Software without restriction, including without limitation the rights to |
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
||||
of the Software, and to permit persons to whom the Software is furnished to do |
||||
so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,780 @@
@@ -0,0 +1,780 @@
|
||||
# vim match-up |
||||
|
||||
match-up is a plugin that lets you highlight, navigate, and operate on |
||||
sets of matching text. It extends vim's `%` key to language-specific |
||||
words instead of just single characters. |
||||
|
||||
<img src='https://github.com/andymass/matchup.vim/wiki/images/teaser.jpg' width='300px' alt='and in this corner...'> |
||||
|
||||
## Screenshot |
||||
|
||||
<img src='https://raw.githubusercontent.com/wiki/andymass/vim-matchup/images/match-up-hl1.gif' width='450px'> |
||||
|
||||
## Table of contents |
||||
|
||||
* [Overview](#overview) |
||||
* [Installation](#installation) |
||||
* [Features](#features) |
||||
* [Options](#options) |
||||
* [FAQ](#faq) |
||||
* [Interoperability](#interoperability) |
||||
* [Acknowledgments](#acknowledgments) |
||||
* [Development](#development) |
||||
|
||||
## Overview |
||||
|
||||
match-up can be used as a drop-in replacement for the classic plugin [matchit.vim]. |
||||
match-up aims to enhance all of matchit's features, fix a number of its |
||||
deficiencies and bugs, and add a few totally new features. It also |
||||
replaces the standard plugin [matchparen], allowing all of matchit's words |
||||
to be highlighted along with the `matchpairs` (`(){}[]`). |
||||
|
||||
[matchit.vim]: http://ftp.vim.org/pub/vim/runtime/macros/matchit.txt |
||||
[matchparen]: http://ftp.vim.org/pub/vim/runtime/doc/pi_paren.txt |
||||
|
||||
See [detailed feature documentation](#detailed-feature-documentation) for |
||||
more information. This plugin: |
||||
|
||||
- Extends vim's `%` motion to language-specific words. The following vim |
||||
file type plugins currently provide support for match-up: |
||||
|
||||
> abaqus, ada, aspvbs, c, clojure, cobol, config, context, csc, csh, |
||||
> dtd, dtrace, eiffel, eruby, falcon, fortran, framescript, haml, |
||||
> hamster, hog, html, ishd, j, jsp, kconfig, liquid, lua, make, matlab, |
||||
> mf, mp, ocaml, pascal, pdf, perl, php, plaintex, postscr, ruby, sh, |
||||
> spec, sql, tex, vb, verilog, vhdl, vim, xhtml, xml, zimbu, zsh |
||||
|
||||
Note: match-up uses the same `b:match_words` as matchit. |
||||
- Adds motions `g%`, `[%`, `]%`, and `z%`. |
||||
- Combines these motions into convenient text objects `i%` and `a%`. |
||||
- Highlights symbols and words under the cursor which `%` can work on, |
||||
and highlights matching symbols and words. Now you can easily tell |
||||
where `%` will jump to. |
||||
|
||||
## Installation |
||||
|
||||
If you use [vim-plug](https://github.com/junegunn/vim-plug), then add the following line to your vimrc file: |
||||
|
||||
```vim |
||||
Plug 'andymass/vim-matchup' |
||||
``` |
||||
|
||||
and then use `:PlugInstall`. Or, you can use any other plugin manager such as |
||||
[vundle](https://github.com/gmarik/vundle), |
||||
[dein](https://github.com/Shougo/dein.vim), |
||||
[neobundle](https://github.com/Shougo/neobundle.vim), or |
||||
[pathogen](https://github.com/tpope/vim-pathogen). |
||||
|
||||
match-up should automatically disable matchit and matchparen, but if you |
||||
are still having trouble, try placing this near the top of your vimrc: |
||||
|
||||
```vim |
||||
let g:loaded_matchit = 1 |
||||
``` |
||||
|
||||
See [Interoperability](#interoperability) for more information about working |
||||
together with other plugins. |
||||
|
||||
## Features |
||||
|
||||
| | feature | __match-up__ | matchit | matchparen | |
||||
| ------- | -------------------------------- | -------------- | ------------- | ------------- | |
||||
| ([a.1]) | jump between matching words | :thumbsup: | :thumbsup: | :x: | |
||||
| ([a.2]) | jump to open & close words | :thumbsup: | :thumbsup: | :x: | |
||||
| ([a.3]) | jump inside | :thumbsup: | :x: | :x: | |
||||
| ([b.1]) | full set of text objects | :thumbsup: | :question: | :x: | |
||||
| ([c.1]) | highlight `()`, `[]`, & `{}` | :thumbsup: | :x: | :thumbsup: | |
||||
| ([c.2]) | highlight _all_ matches | :thumbsup: | :x: | :x: | |
||||
| ([c.3]) | display matches off-screen | :thumbsup: | :x: | :x: | |
||||
| ([d.1]) | modern, modular coding style | :thumbsup: | :x: | :x: | |
||||
| ([d.2]) | actively developed | :thumbsup: | :x: | :x: | |
||||
|
||||
[a.1]: #a1-jump-between-matching-words |
||||
[a.2]: #a2-jump-to-open-and-close-words |
||||
[a.3]: #a3-jump-inside |
||||
[b.1]: #b1-full-set-of-text-objects |
||||
[c.1]: #c1-highlight---and- |
||||
[c.2]: #c2-highlight-all-matches |
||||
[c.3]: #c3-display-matches-off-screen |
||||
[d.1]: #development |
||||
[d.2]: #development |
||||
[inclusive]: #inclusive-and-exclusive-motions |
||||
[exclusive]: #inclusive-and-exclusive-motions |
||||
|
||||
Legend: :thumbsup: supported. :construction: TODO, planned, or in progress. |
||||
:question: poorly implemented, broken, or uncertain. :x: not possible. |
||||
|
||||
### Detailed feature documentation |
||||
|
||||
What do we mean by open, close, mid? This depends on the specific file |
||||
type and is configured through the variable `b:match_words`. Here are a |
||||
couple examples: |
||||
|
||||
#### vim-script |
||||
|
||||
```vim |
||||
if l:x == 1 |
||||
call one() |
||||
elseif l:x == 2 |
||||
call two() |
||||
else |
||||
call three() |
||||
endif |
||||
``` |
||||
|
||||
For the vim-script language, match-up understands the words `if`, |
||||
`else`, `elseif`, `endif` and that they form a sequential construct. The |
||||
"open" word is `if`, the "close" word is `endif`, and the "mid" |
||||
words are `else` and `elseif`. The `if`/`endif` pair is called an |
||||
"open-to-close" block and the `if`/`else`, `else`/`elsif`, and |
||||
`elseif`/`endif` are called "any" blocks. |
||||
|
||||
#### C, C++ |
||||
```c |
||||
#if 0 |
||||
#else |
||||
#endif |
||||
|
||||
void some_func() { |
||||
if (true) { |
||||
one(); |
||||
} else if (false && false) { |
||||
two(); |
||||
} else { |
||||
three(); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
Since in C and C++, blocks are delimited using braces (`{` & `}`), |
||||
match-up will recognize `{` as the open word and `}` as the close word. |
||||
It will ignore the `if` and `else if` because they are not defined in |
||||
vim's C file type plugin. |
||||
|
||||
On the other hand, match-up will recognize the `#if`, `#else`, `#endif` |
||||
preprocessor directives. |
||||
|
||||
#### (a.1) jump between matching words |
||||
- `%` go forwards to next matching word. If at a close word, |
||||
cycle back to the corresponding open word. |
||||
- `{count}%` forwards `{count}` times. Requires |
||||
`{count} <= g:matchup_motion_override_Npercent`. For larger |
||||
`{count}`, `{count}%` goes to the `{count}` percentage in the file. |
||||
- `g%` go backwards to `[count]`th previous matching word. If at an |
||||
open word, cycle around to the corresponding close word. |
||||
|
||||
#### (a.2) jump to open and close words |
||||
- `[%` go to `[count]`th previous outer open word. Allows navigation |
||||
to the start of blocks surrounding the cursor. This is similar to vim's |
||||
built-in `[(` and `[{` and is an [exclusive] motion. |
||||
- `]%` go to `[count]`th next surrounding close word. This is an |
||||
[exclusive] motion. |
||||
|
||||
#### (a.3) jump inside |
||||
- `z%` go to inside `[count]`th nearest inner contained block. This |
||||
is an [exclusive] motion when used with operators, except it eats |
||||
whitespace. For example, where `█` is the cursor position, |
||||
|
||||
```vim |
||||
█ call somefunction(param1, param2) |
||||
``` |
||||
`dz%` produces |
||||
```vim |
||||
param1, param2) |
||||
``` |
||||
but in |
||||
```vim |
||||
█ call somefunction( param1, param2) |
||||
``` |
||||
`dz%` also produces |
||||
```vim |
||||
param1, param2) |
||||
``` |
||||
|
||||
#### (b.1) full set of text objects |
||||
- `i%` the inside of an any block |
||||
- `1i%` the inside of an open-to-close block |
||||
- `{count}i%` If count is greater than 1, the inside of the `{count}`th |
||||
surrounding open-to-close block |
||||
|
||||
- `a%` an any block. |
||||
- `1a%` an open-to-close block. Includes mids but does not include open |
||||
and close words. |
||||
- `{count}a%` if `{count}` is greater than 1, the `{count}`th surrounding |
||||
open-to-close block. |
||||
|
||||
See [here](#line-wise-operatortext-object-combinations) |
||||
for some examples and important special cases. |
||||
|
||||
#### (c.1) highlight `()`, `[]`, and `{}` |
||||
|
||||
match-up emulates vim's matchparen to highlight the symbols contained |
||||
in the `matchpairs` setting. |
||||
|
||||
#### (c.2) highlight _all_ matches |
||||
|
||||
To disable match highlighting at startup, use |
||||
`let g:matchup_matchparen_enabled = 0` |
||||
in your vimrc. |
||||
See [here](#module-matchparen) for more information and related |
||||
options. |
||||
|
||||
You can enable highlighting on the fly using `:DoMatchParen`. |
||||
Likewise, you can disable highlighting at any time using |
||||
`:NoMatchParen`. |
||||
|
||||
After start-up, is better to use `:NoMatchParen` and `:DoMatchParen` |
||||
to toggle highlighting globally than setting the global variable |
||||
since these commands make sure not to leave stale matches around. |
||||
|
||||
#### (c.3) display matches off screen |
||||
|
||||
If a open or close which would have been highlighted is on a line |
||||
positioned outside the current window, the match is shown in the |
||||
status line. If both the open and close match are off-screen, the |
||||
close match is preferred. |
||||
(See the option `g:matchup_matchparen_offscreen`). |
||||
|
||||
### Inclusive and exclusive motions |
||||
|
||||
In vim, character motions following operators (such as `d` for delete |
||||
and `c` for change) are either _inclusive_ or _exclusive_. This means |
||||
they either include the ending position or not. Here, "ending position" |
||||
means the line and column closest to the end of the buffer of the region |
||||
swept over by the motion. match-up is designed so that `d]%` inside a set |
||||
of parenthesis behaves exactly like `d])`, except generalized to words. |
||||
|
||||
Put differently, _forward_ exclusive motions will not include the close |
||||
word. In this example, where `█` is the cursor position, |
||||
|
||||
```vim |
||||
if █x | continue | endif |
||||
``` |
||||
|
||||
pressing `d]%` will produce (cursor on the `e`) |
||||
|
||||
```vim |
||||
if endif |
||||
``` |
||||
|
||||
To include the close word, use either `dv]%` or `vd]%`. This is also |
||||
compatible with vim's `d])` and `d]}`. |
||||
|
||||
Operators over _backward_ exclusive motions will instead exclude the |
||||
position the cursor was on before the operator was invoked. For example, |
||||
in |
||||
|
||||
```vim |
||||
if █x | continue | endif |
||||
``` |
||||
pressing `d[%` will produce |
||||
|
||||
```vim |
||||
█x | continue | endif |
||||
``` |
||||
This is compatible with vim's `d[(` and `d[{`. |
||||
|
||||
Unlike `]%`, `%` is an _inclusive_ motion. As a special case for the |
||||
`d` (delete) operator, if `d%` leaves behind lines white-space, they will |
||||
be deleted also. In effect, it will be operating line-wise. As an |
||||
example, pressing `d%` will leave behind nothing. |
||||
|
||||
```text |
||||
█( |
||||
|
||||
) |
||||
``` |
||||
|
||||
To operate character-wise in this situation, use `dv%` or `vd%`. |
||||
This is vim compatible with the built-in `d%` on `matchpairs`. |
||||
|
||||
### Line-wise operator/text-object combinations |
||||
|
||||
Normally, the text objects `i%` and `a%` work character-wise. However, |
||||
there are some special cases. For certain operators combined with `i%`, |
||||
under certain conditions, match-up will effectively operate line-wise |
||||
instead. For example, in |
||||
```vim |
||||
if condition |
||||
█call one() |
||||
call two() |
||||
endif |
||||
``` |
||||
pressing `di%` will produce |
||||
```vim |
||||
if condition |
||||
endif |
||||
``` |
||||
even though deleting ` condition` would be suggested by the object `i%`. |
||||
The intention is to make operators more useful in some cases. The |
||||
following rules apply: |
||||
1. The operator must be listed in `g:matchup_text_obj_linewise_operators`. |
||||
By default this is `d` and `y` (e.g., `di%` and `ya%`). |
||||
2. The outer block must span multiple lines. |
||||
3. The open and close delimiters must be more than one character long. In |
||||
particular, `di%` involving a `(`...`)` block will not be subject to |
||||
these special rules. |
||||
|
||||
To prevent this behavior for a particular operation, use `vi%d`. Note that |
||||
special cases involving indentation still apply (like with |i)| etc). |
||||
|
||||
To disable this entirely, remove the operator from the following variable, |
||||
```vim |
||||
let g:matchup_text_obj_linewise_operators = [ 'y' ] |
||||
``` |
||||
|
||||
Note: unlike vim's built-in `i)`, `ab`, etc., `i%` does not make an |
||||
existing visual mode character-wise. |
||||
|
||||
A second special case involves `da%`. In this example, |
||||
```vim |
||||
if condition |
||||
█call one() |
||||
call two() |
||||
endif |
||||
``` |
||||
pressing `da%` will delete all four lines and leave no white-space. This |
||||
is vim compatible with `da(`, `dab`, etc. |
||||
|
||||
## Options |
||||
|
||||
To disable the plugin entirely, |
||||
```vim |
||||
let g:matchup_enabled = 0 |
||||
``` |
||||
default: 1 |
||||
|
||||
To disable a particular module, |
||||
```vim |
||||
let g:matchup_matchparen_enabled = 0 |
||||
let g:matchup_motion_enabled = 0 |
||||
let g:matchup_text_obj_enabled = 0 |
||||
``` |
||||
defaults: 1 |
||||
|
||||
To enable the delete surrounding (`ds%`) and change surrounding (`cs%`) |
||||
maps, |
||||
```vim |
||||
let g:matchup_surround_enabled = 1 |
||||
``` |
||||
default: 0 |
||||
|
||||
To enable the experimental [transmute](#d1-parallel-transmutation) |
||||
module, |
||||
```vim |
||||
let g:matchup_transmute_enabled = 1 |
||||
``` |
||||
default: 0 |
||||
|
||||
To configure the number of lines to search in either direction while using |
||||
motions and text objects. Does not apply to match highlighting |
||||
(see `g:matchup_matchparen_stopline` instead). |
||||
```vim |
||||
let g:matchup_delim_stopline = 1500 |
||||
``` |
||||
default: 1500 |
||||
|
||||
To disable matching within strings and comments, |
||||
```vim |
||||
let g:matchup_delim_noskips = 1 " recognize symbols within comments |
||||
let g:matchup_delim_noskips = 2 " don't recognize anything in comments |
||||
``` |
||||
default: 0 (matching is enabled within strings and comments) |
||||
|
||||
### Variables |
||||
|
||||
match-up understands the following variables from matchit. |
||||
- `b:match_words` |
||||
- `b:match_skip` |
||||
- `b:match_ignorecase` |
||||
|
||||
These are set in the respective ftplugin files. They may not exist for |
||||
every file type. To support a new file type, create a file |
||||
`after/ftplugin/{filetype}.vim` which sets them appropriately. |
||||
|
||||
### Module matchparen |
||||
|
||||
To disable match highlighting at startup, use |
||||
`let g:matchup_matchparen_enabled = 0` in your vimrc. |
||||
Note: vim's built-in plugin |pi_paren| plugin is also disabled. |
||||
The variable `g:loaded_matchparen` has no effect on match-up. |
||||
|
||||
#### Customizing the highlighting colors |
||||
|
||||
match-up uses the `MatchParen` highlighting group by default, which can be |
||||
configured. For example, |
||||
```vim |
||||
:hi MatchParen ctermbg=blue guibg=lightblue cterm=italic gui=italic |
||||
``` |
||||
|
||||
You may want to put this inside a `ColorScheme` `autocmd` so it is |
||||
preserved after colorscheme changes: |
||||
```vim |
||||
augroup matchup_matchparen_highlight |
||||
autocmd! |
||||
autocmd ColorScheme * hi MatchParen guifg=red |
||||
augroup END |
||||
``` |
||||
|
||||
You can also highlight words differently than parentheses using the |
||||
`MatchWord` highlighting group. You might do this if you find the |
||||
`MatchParen` style distracting for large blocks. |
||||
```vim |
||||
:hi MatchWord ctermfg=red guifg=blue cterm=underline gui=underline |
||||
``` |
||||
|
||||
There are also `MatchParenCur` and `MatchWordCur` which allow you to |
||||
configure the highlight separately for the match under the cursor. |
||||
```vim |
||||
:hi MatchParenCur cterm=underline gui=underline |
||||
:hi MatchWordCur cterm=underline gui=underline |
||||
``` |
||||
|
||||
The matchparen module can be disabled on a per-buffer basis (there is |
||||
no command for this). By default, when disabling highlighting for a |
||||
particular buffer, the standard plugin matchparen will still be used |
||||
for that buffer. |
||||
|
||||
```vim |
||||
let b:matchup_matchparen_enabled = 0 |
||||
``` |
||||
default: 1 |
||||
|
||||
If this module is disabled on a particular buffer, match-up will still |
||||
fall-back to the vim standard plugin matchparen, which will highlight |
||||
`matchpairs` such as `()`, `[]`, & `{}`. To disable this, |
||||
```vim |
||||
let b:matchup_matchparen_fallback = 0 |
||||
``` |
||||
default: 1 |
||||
|
||||
A common usage of these options is to automatically disable |
||||
matchparen for particular file types; |
||||
```vim |
||||
augroup matchup_matchparen_disable_ft |
||||
autocmd! |
||||
autocmd FileType tex let [b:matchup_matchparen_fallback, |
||||
\ b:matchup_matchparen_enabled] = [0, 0] |
||||
augroup END |
||||
``` |
||||
|
||||
Whether to highlight known words even if there is no match: |
||||
```vim |
||||
let g:matchup_matchparen_singleton = 1 |
||||
``` |
||||
default: 0 |
||||
|
||||
Dictionary controlling the behavior with off-screen matches. |
||||
```vim |
||||
let g:matchup_matchparen_offscreen = { ... } |
||||
``` |
||||
|
||||
default: `{'method': 'status'}` |
||||
|
||||
If empty, this feature is disabled. Else, it should contain the |
||||
following optional keys: |
||||
|
||||
- `method`: |
||||
Sets the method to use to show off-screen matches. |
||||
Possible values are: |
||||
|
||||
`'status'` (default): Replace the |status-line| for off-screen matches. |
||||
|
||||
If a match is off of the screen, the line belonging to that match will be |
||||
displayed syntax-highlighted in the status line along with the line number |
||||
(if line numbers are enabled). If the match is above the screen border, |
||||
an additional Δ symbol will be shown to indicate that the matching line is |
||||
really above the cursor line. |
||||
|
||||
`'status_manual'`: Compute the status-line but do not display it (future |
||||
extension). |
||||
|
||||
- `scrolloff`: |
||||
When enabled, off-screen matches will not be shown in the statusline while |
||||
the cursor is at the screen edge (respects the value of 'scrolloff'). |
||||
This is intended to prevent flickering while scrolling with j and k. |
||||
|
||||
default: 0. |
||||
|
||||
The number of lines to search in either direction while highlighting |
||||
matches. Set this conservatively since high values may cause performance |
||||
issues. |
||||
```vim |
||||
let g:matchup_matchparen_stopline = 400 " for match highlighting only |
||||
``` |
||||
|
||||
default: 400 |
||||
|
||||
#### highlighting timeouts |
||||
|
||||
Adjust timeouts in milliseconds for matchparen highlighting: |
||||
```vim |
||||
let g:matchup_matchparen_timeout = 300 |
||||
let g:matchup_matchparen_insert_timeout = 60 |
||||
``` |
||||
default: 300, 60 |
||||
|
||||
#### deferred highlighting |
||||
|
||||
Deferred highlighting improves cursor movement performance (for example, |
||||
when using `hjkl`) by delaying highlighting for a short time and waiting |
||||
to see if the cursor continues moving; |
||||
```vim |
||||
let g:matchup_matchparen_deferred = 1 |
||||
``` |
||||
default: 0 (disabled) |
||||
|
||||
Note: this feature is only available if your vim version has `timers` and |
||||
the function `timer_pause`, version 7.4.2180 and after. For neovim, this |
||||
will only work in nvim-0.2.1 and after. |
||||
|
||||
Adjust delays in milliseconds for deferred highlighting: |
||||
```vim |
||||
let g:matchup_matchparen_deferred_show_delay = 50 |
||||
let g:matchup_matchparen_deferred_hide_delay = 700 |
||||
``` |
||||
default: 50, 700 |
||||
|
||||
Note: these delays cannot be changed dynamically and should be configured |
||||
before the plugin loads (e.g., in your vimrc). |
||||
|
||||
#### highlight surrounding |
||||
|
||||
To highlight the surrounding delimiters until the cursor moves, use a map |
||||
such as the following |
||||
```vim |
||||
nmap <silent> <F7> <plug>(matchup-hi-surround) |
||||
``` |
||||
There is no default map for this feature. |
||||
|
||||
You can also highlight surrounding delimiters always as the cursor moves. |
||||
```vim |
||||
let g:matchup_matchparen_deferred = 1 |
||||
let g:matchup_matchparen_hi_surround_always = 1 |
||||
``` |
||||
default: 0 (off) |
||||
|
||||
This can be set on a per-buffer basis: |
||||
```vim |
||||
autocmd FileType tex let b:matchup_matchparen_hi_surround_always = 1 |
||||
``` |
||||
|
||||
Note: this feature _requires_ |
||||
[deferred highlighting](#deferred-highlighting) to be supported and |
||||
enabled. |
||||
|
||||
### Module motion |
||||
|
||||
In vim, `{count}%` goes to the `{count}` percentage in the file. |
||||
match-up overrides this motion for small `{count}` (by default, anything |
||||
less than 7). To allow `{count}%` for `{count}` up to 11, |
||||
```vim |
||||
g:matchup_motion_override_Npercent = 11 |
||||
``` |
||||
To disable this feature, and restore vim's default `{count}%`, |
||||
```vim |
||||
g:matchup_motion_override_Npercent = 0 |
||||
``` |
||||
default: 6 |
||||
|
||||
If enabled, cursor will land on the end of mid and close words while |
||||
moving downwards (`%`/`]%`). While moving upwards (`g%`, `[%`) the cursor |
||||
will land on the beginning. To disable, |
||||
```vim |
||||
let g:matchup_motion_cursor_end = 0 |
||||
``` |
||||
default: 1 |
||||
|
||||
### Module text_obj |
||||
|
||||
Modify the set of operators which may operate |
||||
[line-wise](#line-wise-operatortext-object-combinations) |
||||
```vim |
||||
let g:matchup_text_obj_linewise_operators' = ['d', 'y'] |
||||
``` |
||||
default: `['d', 'y']` |
||||
|
||||
### Module transmute |
||||
|
||||
_Options planned_. |
||||
|
||||
## FAQ |
||||
|
||||
- match-up doesn't work |
||||
|
||||
This plugin requires at least vim 7.4. It should work in vim 7.4.898 |
||||
but at least vim 7.4.1689 is better. I recommend using the most recent |
||||
version of vim if possible. |
||||
|
||||
If you have issues, please tell me your vim version and error messages. |
||||
Try updating vim and see if the problem persists. |
||||
|
||||
- Why does jumping not work for construct X in language Y? |
||||
|
||||
Please open a new issue |
||||
|
||||
- Highlighting is not correct for construct X |
||||
|
||||
match-up uses matchit's filetype-specific data, which may not give |
||||
enough information to create proper highlights. To fix this, you may |
||||
need to modify `b:match_words`. |
||||
|
||||
For help, please open a new issue and be as specific as possible. |
||||
|
||||
- I'm having performance problems |
||||
|
||||
match-up aims to be as fast as possible, but highlighting matching words |
||||
can be intensive and may be slow on less powerful machines. There are a |
||||
few things you can try to improve performance: |
||||
|
||||
1. Update to a recent version of vim. Newer versions are faster, more |
||||
extensively tested, and better supported by match-up. |
||||
2. Try [deferred highlighting](#deferred-highlighting), which delays |
||||
highlighting until the cursor is stationary to improve cursor movement |
||||
performance. |
||||
3. Lower the [highlighting timeouts](#highlighting-timeouts). Note that |
||||
if highlighting takes longer than the timeout, highlighting will not be |
||||
attempted again until the cursor moves. |
||||
|
||||
If are having any other performance issues, please open a new issue and |
||||
report the output of `:MatchupShowTimes`. |
||||
|
||||
- Why is there a weird entry on the status line? |
||||
|
||||
This is a feature which helps you see matches that are outside of the |
||||
vim screen, similar to some IDEs. If you wish to disable it, use |
||||
|
||||
```vim |
||||
let g:matchup_matchparen_offscreen = {} |
||||
``` |
||||
|
||||
- Matching does not work when lines are too far apart. |
||||
|
||||
The number of search lines is limited for performance reasons. You may |
||||
increase the limits with the following options: |
||||
|
||||
```vim |
||||
let g:matchup_delim_stopline = 1500 " generally |
||||
let g:matchup_matchparen_stopline = 400 " for match highlighting only |
||||
``` |
||||
- The maps `1i%` and `1a%` are difficult to press. |
||||
|
||||
You may use the following maps `I%` and `A%` for convenience: |
||||
|
||||
```vim |
||||
function! s:matchup_convenience_maps() |
||||
xnoremap <sid>(std-I) I |
||||
xnoremap <sid>(std-A) A |
||||
xmap <expr> I mode()=='<c-v>'?'<sid>(std-I)':(v:count?'':'1').'i' |
||||
xmap <expr> A mode()=='<c-v>'?'<sid>(std-A)':(v:count?'':'1').'a' |
||||
for l:v in ['', 'v', 'V', '<c-v>'] |
||||
execute 'omap <expr>' l:v.'I%' "(v:count?'':'1').'".l:v."i%'" |
||||
execute 'omap <expr>' l:v.'A%' "(v:count?'':'1').'".l:v."a%'" |
||||
endfor |
||||
endfunction |
||||
call s:matchup_convenience_maps() |
||||
``` |
||||
|
||||
Note: this is not compatible with the plugin targets.vim. |
||||
|
||||
- How can I contribute? |
||||
|
||||
Read the [contribution guidelines](CONTRIBUTING.md) and [issue |
||||
template](ISSUE_TEMPLATE.md). Be as precise and detailed as possible |
||||
when submitting issues and pull requests. |
||||
|
||||
## Interoperability |
||||
|
||||
### vimtex, for LaTeX documents |
||||
|
||||
By default, match-up will be disabled automatically for tex files when |
||||
[vimtex] is detected. To enable match-up for tex files, use |
||||
|
||||
```vim |
||||
let g:matchup_override_vimtex = 1 |
||||
``` |
||||
|
||||
match-up's matching engine is more advanced than vimtex's and supports |
||||
middle delimiters such as `\middle|` and `\else`. The exact set of |
||||
delimiters recognized may differ between the two plugins. For example, |
||||
the mappings `da%` and `dad` will not always match, particularly if you |
||||
have customized vimtex's delimiters. |
||||
|
||||
### Surroundings |
||||
|
||||
match-up provides built-in support for [vim-surround]-style `ds%` and |
||||
`cs%` operations. If vim-surround is installed, you can use vim-surround |
||||
replacements such as `cs%)`. `%` cannot be used as a replacement. |
||||
An alternative plugin is [vim-sandwich], which allows more complex |
||||
surround replacement rules but is not currently supported. |
||||
|
||||
[vim-surround]: https://github.com/tpope/vim-surround |
||||
[vim-sandwich]: https://github.com/machakann/vim-sandwich |
||||
|
||||
### Auto-closing plugins |
||||
|
||||
match-up does not provide auto-complete or auto-insertion of matches. |
||||
See for instance one of the following plugins for this; |
||||
|
||||
- [vim-endwise](https://github.com/tpope/vim-endwise) |
||||
- [auto-pairs](https://github.com/jiangmiao/auto-pairs) |
||||
- [delimitMate](https://github.com/Raimondi/delimitMate) |
||||
- [splitjoin.vim](https://github.com/AndrewRadev/splitjoin.vim) |
||||
- [Pear Tree](https://github.com/tmsvg/pear-tree) |
||||
|
||||
### Matchit |
||||
|
||||
match-up tries to work around matchit.vim in all cases, but if |
||||
you experience problems, read the following. |
||||
matchit.vim should not be loaded. If it is loaded, it should be loaded |
||||
after match-up (in this case, matchit.vim will be disabled). Note that |
||||
some plugins, such as |
||||
[vim-sensible](https://github.com/tpope/vim-sensible), |
||||
load matchit.vim so these should also be initialized after match-up. |
||||
|
||||
### Matchparen emulation |
||||
|
||||
match-up loads [matchparen] if it is not already loaded. Ordinarily, match-up |
||||
disables matchparen's highlighting and emulates it to highlight the symbol |
||||
contained in the 'matchpairs' option (by default `()`, `[]`, and `{}`). If match-up |
||||
is disabled per-buffer using `b:matchup_matchparen_enabled`, match-up will use |
||||
matchparen instead of its own highlighting. See `b:matchup_matchparen_fallback` |
||||
for more information. |
||||
|
||||
## Acknowledgments |
||||
|
||||
### Origins |
||||
|
||||
match-up was originally based on [@lervag](https://github.com/lervag)'s |
||||
[vimtex]. The concept and style of this plugin and its development are |
||||
heavily influenced by vimtex. :beers: |
||||
|
||||
[vimtex]: https://github.com/lervag/vimtex |
||||
|
||||
### Other inspirations |
||||
|
||||
- [matchit](http://ftp.vim.org/pub/vim/runtime/macros/matchit.txt) |
||||
- [matchparen](http://ftp.vim.org/pub/vim/runtime/doc/pi_paren.txt) |
||||
- [MatchTag](https://github.com/gregsexton/MatchTag) |
||||
- [MatchTagAlways](https://github.com/Valloric/MatchTagAlways) |
||||
- [vim-textobj-anyblock](https://github.com/rhysd/vim-textobj-anyblock) |
||||
|
||||
## Development |
||||
|
||||
### Reporting problems |
||||
|
||||
This is a new plugin and there are likely to be some bugs. |
||||
Thorough issue reports are encouraged. Please read the [issue |
||||
template](ISSUE_TEMPLATE.md) first. Be as precise and detailed as |
||||
possible when submitting issues. |
||||
|
||||
Feature requests are also welcome. |
||||
|
||||
### Contributing |
||||
|
||||
Please read the [contribution guidelines](CONTRIBUTING.md) before |
||||
contributing. |
||||
|
||||
A major goal of this project is to keep a modern and modular code base. |
||||
Contributions are welcome! |
||||
|
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
if matchup#util#check_match_words('bb2bcbee') |
||||
call matchup#util#append_match_words('/\*:\*/') |
||||
endif |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
if matchup#util#matchpref('template', 0) |
||||
call matchup#util#append_match_words( |
||||
\ '\%(\s\@<!<\|<\s\@!\)=\@!:\%(\s\@<!>\|>\s\@!\)=\@!') |
||||
if stridx(&matchpairs, '<:>') |
||||
setlocal matchpairs-=<:> |
||||
endif |
||||
endif |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
call matchup#util#patch_match_words('\<if', '\<if\>') |
||||
call matchup#util#patch_match_words('\<end\s*if', '\<end\>\s*if') |
||||
|
||||
call matchup#util#append_match_words( |
||||
\ '^\s*#\s*if\(\|def\|ndef\)\>' |
||||
\ . ':^\s*#\s*elif\>:^\s*#\s*else\>' |
||||
\ . ':^\s*#\s*endif\>') |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
call matchup#util#patch_match_words( |
||||
\ '<\@<=\([^/][^ \t>]*\)[^>]*\%(>\|$\):<\@<=/\1>', |
||||
\ '<\@<=\([^/][^ \t>]*\)\%(>\|$\|[ \t][^>]*\%(>\|$\)\):<\@<=/\1>' |
||||
\) |
||||
|
||||
if matchup#util#matchpref('nolists', |
||||
\ get(g:, 'matchup_matchpref_html_nolists', 0)) |
||||
call matchup#util#patch_match_words( |
||||
\ '<\@<=[ou]l\>[^>]*\%(>\|$\):<\@<=li\>:<\@<=/[ou]l>', |
||||
\ '') |
||||
call matchup#util#patch_match_words( |
||||
\ '<\@<=dl\>[^>]*\%(>\|$\):<\@<=d[td]\>:<\@<=/dl>', |
||||
\ '') |
||||
endif |
||||
|
||||
if matchup#util#matchpref('tagnameonly', 0) |
||||
call matchup#util#patch_match_words( |
||||
\ '\)\%(', |
||||
\ '\)\g{hlend}\%(') |
||||
call matchup#util#patch_match_words( |
||||
\ ']l\>[', |
||||
\ ']l\>\g{hlend}[') |
||||
call matchup#util#patch_match_words( |
||||
\ 'dl\>', |
||||
\ 'dl\>\g{hlend}') |
||||
endif |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
let b:match_midmap = [ |
||||
\ ['luaFunction', 'return'], |
||||
\] |
||||
let b:undo_ftplugin .= '| unlet! b:match_midmap' |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let b:matchup_matchparen_timeout=100 |
||||
let b:undo_ftplugin .= ' | unlet! b:matchup_matchparen_timeout' |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
call matchup#util#patch_match_words('retry', 'retry\|return') |
||||
|
||||
let b:match_midmap = [ |
||||
\ ['rubyRepeat', 'next'], |
||||
\ ['rubyDefine', 'return'], |
||||
\] |
||||
let b:undo_ftplugin .= '| unlet! b:match_midmap' |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,117 @@
@@ -0,0 +1,117 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! s:has_plugin(plug) |
||||
return !empty(filter(split(&rtp,','), 'v:val =~? ''\<'.a:plug.'\>''')) |
||||
endfunction |
||||
|
||||
let s:not_bslash = '\v%(\\@<!%(\\\\)*)@4<=\m' |
||||
|
||||
function! s:get_match_words() |
||||
" left and right modifiers, any delimiters |
||||
let l:delim = '\%(\\\w\+\>\|\\[|{}]\|.\)' |
||||
let l:match_words = '\\left\>'.l:delim |
||||
\ .':\\middle\>'.l:delim |
||||
\ .':\\right\>'.l:delim |
||||
let l:match_words .= ',\(\\[bB]igg\?\)l\>'.l:delim |
||||
\ . ':\1m\>'.l:delim |
||||
\ . ':\1r\>'.l:delim |
||||
|
||||
" un-sided sized, left and right delimiters |
||||
let l:mod = '\(\\[bB]igg\?\)' |
||||
let l:wdelim = '\%(angle\|floor\|ceil\|[vV]ert\|brace\)\>' |
||||
let l:ldelim = '\%(\\l'.l:wdelim.'\|\\[lu]lcorner\>\|(\|\[\|\\{\)' |
||||
let l:mdelim = '\%(\\vert\>\||\|\\|\)' |
||||
let l:rdelim = '\%(\\r'.l:wdelim.'\|\\[lu]rcorner\>\|)\|]\|\\}\)' |
||||
let l:mtopt = '\%(\%(\w\[\)\@2<!\|\%(\\[bB]igg\?\[\)\@6<=\)' |
||||
let l:match_words .= ','.l:mod.l:ldelim |
||||
\ . ':\1'.l:mdelim |
||||
\ . ':'.l:mtopt.'\1'.l:rdelim |
||||
|
||||
" unmodified delimiters |
||||
let l:nomod = '\%(\\left\|\\right\|\[\@1<!\\[bB]igg\?[lr]\?\)\@6<!' |
||||
for l:pair in [['\\{', '\\}'], ['\[', ']'], ['(', ')'], |
||||
\ ['\\[lu]lcorner', '\\[lu]rcorner']] |
||||
let l:match_words .= ','.l:nomod.s:not_bslash.l:pair[0] |
||||
\ . ':'.l:nomod.s:not_bslash.l:pair[1] |
||||
endfor |
||||
let l:match_words .= ','.l:nomod.s:not_bslash.'\\l\('.l:wdelim.'\)' |
||||
\ . ':'.l:nomod.s:not_bslash.'\\r\1\>' |
||||
|
||||
" the curly braces |
||||
let l:match_words .= ',{:}' |
||||
|
||||
" latex equation markers |
||||
let l:match_words .= ',\\(:\\),\\\[:\\]' |
||||
|
||||
" simple blocks |
||||
let l:match_words .= ',\\if\%(\w\|@\)*\>:\\else\>:\\fi\>' |
||||
let l:match_words .= ',\\makeatletter:\\makeatother' |
||||
let l:match_words .= ',\\begingroup:\\endgroup,\\bgroup:\\egroup' |
||||
|
||||
" environments |
||||
let l:match_words .= ',\\begin{tabular}' |
||||
\ . ':\\toprule\>:\\midrule\>:\\bottomrule\>' |
||||
\ . ':\\end{tabular}' |
||||
|
||||
" enumerate, itemize |
||||
let l:match_words .= ',\\begin\s*{\(enumerate\*\=\|itemize\*\=\)}' |
||||
\ . ':\\item\>:\\end\s*{\1}' |
||||
|
||||
" generic environment |
||||
let l:match_words .= ',\\begin\s*{\([^}]*\)}:\\end\s*{\1}' |
||||
|
||||
return l:match_words |
||||
endfunction |
||||
|
||||
function! s:setup_match_words() |
||||
setlocal matchpairs=(:),{:},[:] |
||||
let b:matchup_delim_nomatchpairs = 1 |
||||
let b:match_words = s:get_match_words() |
||||
|
||||
" the syntax method is too slow for latex |
||||
let b:match_skip = 'r:\\\@<!\%(\\\\\)*%' |
||||
|
||||
" the old regexp engine is a bit faster '\%#=1' |
||||
let b:matchup_regexpengine = 1 |
||||
|
||||
let b:undo_ftplugin = |
||||
\ (exists('b:undo_ftplugin') ? b:undo_ftplugin . '|' : '') |
||||
\ . 'unlet! b:matchup_delim_nomatchpairs b:match_words' |
||||
\ . ' b:match_skip b:matchup_regexpengine' |
||||
endfunction |
||||
|
||||
if get(g:, 'vimtex_enabled', |
||||
\ s:has_plugin('vimtex') || exists('*vimtex#init')) |
||||
if get(g:, 'matchup_override_vimtex', 0) |
||||
silent! nunmap <buffer> % |
||||
silent! xunmap <buffer> % |
||||
silent! ounmap <buffer> % |
||||
|
||||
" lervag/vimtex/issues/1051 |
||||
let g:vimtex_matchparen_enabled = 0 |
||||
silent! call vimtex#matchparen#disable() |
||||
|
||||
call s:setup_match_words() |
||||
else |
||||
let b:matchup_matchparen_enabled = 0 |
||||
let b:matchup_matchparen_fallback = 0 |
||||
endif |
||||
else |
||||
call s:setup_match_words() |
||||
endif |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
let b:match_skip = 's:comment\|string\|vimSynReg' |
||||
\ . '\|vimSet\|vimFuncName\|vimNotPatSep' |
||||
\ . '\|vimVar\|vimFuncVar\|vimFBVar\|vimOperParen' |
||||
\ . '\|vimUserFunc' |
||||
|
||||
call matchup#util#patch_match_words( |
||||
\ '\<aug\%[roup]\s\+\%(END\>\)\@!\S:', |
||||
\ '\<aug\%[roup]\ze\s\+\%(END\>\)\@!\S:' |
||||
\) |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
runtime after/ftplugin/html_matchup.vim |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !exists('g:loaded_matchup') || !exists('b:did_ftplugin') |
||||
finish |
||||
endif |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
if matchup#util#matchpref('tagnameonly', 0) |
||||
call matchup#util#patch_match_words('\)\%(', '\)\g{hlend}\%(') |
||||
call matchup#util#patch_match_words('\)\%(', '\)\g{hlend}\%(') |
||||
endif |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,362 @@
@@ -0,0 +1,362 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#init() |
||||
call matchup#perf#tic('loading') |
||||
|
||||
call s:init_options() |
||||
call s:init_modules() |
||||
call s:init_default_mappings() |
||||
|
||||
call matchup#perf#toc('loading', 'init_done') |
||||
endfunction |
||||
|
||||
function! s:init_options() |
||||
call s:init_option('matchup_matchparen_enabled', |
||||
\ !(&t_Co < 8 && !has('gui_running'))) |
||||
let l:offs = {'method': 'status'} |
||||
if !get(g:, 'matchup_matchparen_status_offscreen', 1) |
||||
let l:offs = {} |
||||
endif |
||||
if get(g:, 'matchup_matchparen_status_offscreen_manual', 0) |
||||
let l:offs.method = 'status_manual' |
||||
endif |
||||
if exists('g:matchup_matchparen_scrolloff') |
||||
let l:offs.scrolloff = g:matchup_matchparen_scrolloff |
||||
endif |
||||
call s:init_option('matchup_matchparen_offscreen', l:offs) |
||||
call s:init_option('matchup_matchparen_singleton', 0) |
||||
call s:init_option('matchup_matchparen_deferred', 0) |
||||
call s:init_option('matchup_matchparen_deferred_show_delay', 50) |
||||
call s:init_option('matchup_matchparen_deferred_hide_delay', 700) |
||||
call s:init_option('matchup_matchparen_deferred_fade_time', 0) |
||||
call s:init_option('matchup_matchparen_stopline', 400) |
||||
call s:init_option('matchup_matchparen_pumvisible', 1) |
||||
call s:init_option('matchup_matchparen_nomode', '') |
||||
call s:init_option('matchup_matchparen_hi_surround_always', 0) |
||||
call s:init_option('matchup_matchparen_hi_background', 0) |
||||
|
||||
call s:init_option('matchup_matchparen_timeout', |
||||
\ get(g:, 'matchparen_timeout', 300)) |
||||
call s:init_option('matchup_matchparen_insert_timeout', |
||||
\ get(g:, 'matchparen_insert_timeout', 60)) |
||||
|
||||
call s:init_option('matchup_delim_count_fail', 0) |
||||
call s:init_option('matchup_delim_count_max', 8) |
||||
call s:init_option('matchup_delim_start_plaintext', 1) |
||||
call s:init_option('matchup_delim_noskips', 0) |
||||
|
||||
call s:init_option('matchup_motion_enabled', 1) |
||||
call s:init_option('matchup_motion_cursor_end', 1) |
||||
call s:init_option('matchup_motion_override_Npercent', 6) |
||||
|
||||
call s:init_option('matchup_text_obj_enabled', 1) |
||||
call s:init_option('matchup_text_obj_linewise_operators', ['d', 'y']) |
||||
|
||||
call s:init_option('matchup_transmute_enabled', 0) |
||||
call s:init_option('matchup_transmute_breakundo', 0) |
||||
|
||||
call s:init_option('matchup_mouse_enabled', 1) |
||||
|
||||
call s:init_option('matchup_surround_enabled', 0) |
||||
|
||||
call s:init_option('matchup_where_enabled', 1) |
||||
call s:init_option('matchup_where_separator', '') |
||||
|
||||
call s:init_option('matchup_matchpref', {}) |
||||
endfunction |
||||
|
||||
function! s:init_option(option, default) |
||||
let l:option = 'g:' . a:option |
||||
if !exists(l:option) |
||||
let {l:option} = a:default |
||||
endif |
||||
endfunction |
||||
|
||||
function! s:init_modules() |
||||
for l:mod in [ 'loader', 'matchparen' ] |
||||
if !get(g:, 'matchup_'.l:mod.'_enabled', 1) |
||||
continue |
||||
endif |
||||
call matchup#perf#tic('loading_module') |
||||
call matchup#{l:mod}#init_module() |
||||
call matchup#perf#toc('loading_module', l:mod) |
||||
endfor |
||||
|
||||
call s:motion_init_module() |
||||
call s:text_obj_init_module() |
||||
call s:misc_init_module() |
||||
call s:surround_init_module() |
||||
call s:where_init_module() |
||||
endfunction |
||||
|
||||
function! s:init_oldstyle_ops() " {{{1 |
||||
if get(g:, 'matchup_motion_enabled', 0) |
||||
\ || get(g:, 'matchup_text_obj_enabled', 0) |
||||
for l:opforce in ['', 'v', 'V', '<c-v>'] |
||||
call s:map('onore', '<expr> <plug>(matchup-o_'.l:opforce.')', |
||||
\ '<sid>force('''.l:opforce.''')') |
||||
endfor |
||||
endif |
||||
|
||||
if get(g:, 'matchup_motion_enabled', 0) |
||||
for l:opforce in ['', 'v', 'V', '<c-v>'] |
||||
call s:map('o', l:opforce.'%', |
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-%)') |
||||
call s:map('o', l:opforce.'g%', |
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-g%)') |
||||
call s:map('o', l:opforce.']%', |
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-]%)') |
||||
call s:map('o', l:opforce.'[%', |
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-[%)') |
||||
call s:map('o', l:opforce.'z%', |
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-z%)') |
||||
endfor |
||||
endif |
||||
|
||||
if get(g:, 'matchup_text_obj_enabled', 0) |
||||
for l:opforce in ['', 'v', 'V', '<c-v>'] |
||||
call s:map('o', l:opforce.'i%', |
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-i%)') |
||||
call s:map('o', l:opforce.'a%', |
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-a%)') |
||||
endfor |
||||
endif |
||||
endfunction |
||||
|
||||
function! s:make_oldstyle_omaps(lhs, rhs) |
||||
if !s:old_style_ops |
||||
return 0 |
||||
endif |
||||
for l:opforce in ['', 'v', 'V', '<c-v>'] |
||||
silent! execute 'omap' l:opforce.a:lhs |
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-'.a:rhs.')' |
||||
endfor |
||||
return 1 |
||||
endfunction |
||||
|
||||
let s:old_style_ops = !has('patch-8.1.0648') |
||||
|
||||
let g:v_motion_force = '' |
||||
function! s:force(wise) |
||||
let g:v_motion_force = a:wise |
||||
return '' |
||||
endfunction |
||||
|
||||
function! matchup#motion_force() abort |
||||
if !s:old_style_ops |
||||
let l:mode = mode(1) |
||||
let g:v_motion_force = len(l:mode) >= 3 |
||||
\ && l:mode[0:1] ==# 'no' ? l:mode[2] : '' |
||||
endif |
||||
return g:v_motion_force |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:init_default_mappings() |
||||
if !get(g:,'matchup_mappings_enabled', 1) | return | endif |
||||
|
||||
function! s:map(mode, lhs, rhs, ...) |
||||
if !hasmapto(a:rhs, a:mode) |
||||
\ && ((a:0 > 0) || (maparg(a:lhs, a:mode) ==# '')) |
||||
silent execute a:mode . 'map <silent> ' a:lhs a:rhs |
||||
endif |
||||
endfunction |
||||
|
||||
if s:old_style_ops |
||||
call s:init_oldstyle_ops() |
||||
endif |
||||
|
||||
" these won't conflict since matchit should not be loaded at this point |
||||
if get(g:, 'matchup_motion_enabled', 0) |
||||
call s:map('n', '%', '<plug>(matchup-%)' ) |
||||
call s:map('n', 'g%', '<plug>(matchup-g%)') |
||||
|
||||
call s:map('x', '%', '<plug>(matchup-%)' ) |
||||
call s:map('x', 'g%', '<plug>(matchup-g%)') |
||||
|
||||
call s:map('n', ']%', '<plug>(matchup-]%)') |
||||
call s:map('n', '[%', '<plug>(matchup-[%)') |
||||
|
||||
call s:map('x', ']%', '<plug>(matchup-]%)') |
||||
call s:map('x', '[%', '<plug>(matchup-[%)') |
||||
|
||||
call s:map('n', 'z%', '<plug>(matchup-z%)') |
||||
call s:map('x', 'z%', '<plug>(matchup-z%)') |
||||
|
||||
if !s:old_style_ops |
||||
call s:map('o', '%', '<plug>(matchup-%)') |
||||
call s:map('o', 'g%', '<plug>(matchup-g%)') |
||||
call s:map('o', ']%', '<plug>(matchup-]%)') |
||||
call s:map('o', '[%', '<plug>(matchup-[%)') |
||||
call s:map('o', 'z%', '<plug>(matchup-z%)') |
||||
endif |
||||
|
||||
call s:map('i', '<c-g>%', '<plug>(matchup-c_g%)') |
||||
endif |
||||
|
||||
if get(g:, 'matchup_text_obj_enabled', 0) |
||||
call s:map('x', 'i%', '<plug>(matchup-i%)') |
||||
call s:map('x', 'a%', '<plug>(matchup-a%)') |
||||
|
||||
if !s:old_style_ops |
||||
call s:map('o', 'i%', '<plug>(matchup-i%)') |
||||
call s:map('o', 'a%', '<plug>(matchup-a%)') |
||||
endif |
||||
endif |
||||
|
||||
if get(g:, 'matchup_mouse_enabled', 1) |
||||
call s:map('n', '<2-LeftMouse>', '<plug>(matchup-double-click)') |
||||
endif |
||||
|
||||
if get(g:, 'matchup_surround_enabled', 0) |
||||
call s:map('n', 'ds%', '<plug>(matchup-ds%)') |
||||
call s:map('n', 'cs%', '<plug>(matchup-cs%)') |
||||
endif |
||||
endfunction |
||||
|
||||
" module initialization |
||||
|
||||
function! s:motion_init_module() " {{{1 |
||||
if !g:matchup_motion_enabled | return | endif |
||||
|
||||
call matchup#perf#tic('loading_module') |
||||
|
||||
" gets the current forced motion type |
||||
nnoremap <silent><expr> <sid>(wise) |
||||
\ empty(g:v_motion_force) ? 'v' : g:v_motion_force |
||||
|
||||
" the basic motions % and g% |
||||
nnoremap <silent> <plug>(matchup-%) |
||||
\ :<c-u>call matchup#motion#find_matching_pair(0, 1)<cr> |
||||
nnoremap <silent> <plug>(matchup-g%) |
||||
\ :<c-u>call matchup#motion#find_matching_pair(0, 0)<cr> |
||||
|
||||
" visual and operator-pending |
||||
xnoremap <silent> <sid>(matchup-%) |
||||
\ :<c-u>call matchup#motion#find_matching_pair(1, 1)<cr> |
||||
xmap <silent> <plug>(matchup-%) <sid>(matchup-%) |
||||
onoremap <silent> <plug>(matchup-%) |
||||
\ :<c-u>call matchup#motion#op('%')<cr> |
||||
|
||||
xnoremap <silent> <sid>(matchup-g%) |
||||
\ :<c-u>call matchup#motion#find_matching_pair(1, 0)<cr> |
||||
xmap <silent> <plug>(matchup-g%) <sid>(matchup-g%) |
||||
onoremap <silent> <plug>(matchup-g%) |
||||
\ :<c-u>call matchup#motion#op('g%')<cr> |
||||
|
||||
" ]% and [% |
||||
nnoremap <silent> <plug>(matchup-]%) |
||||
\ :<c-u>call matchup#motion#find_unmatched(0, 1)<cr> |
||||
nnoremap <silent> <plug>(matchup-[%) |
||||
\ :<c-u>call matchup#motion#find_unmatched(0, 0)<cr> |
||||
|
||||
xnoremap <silent> <sid>(matchup-]%) |
||||
\ :<c-u>call matchup#motion#find_unmatched(1, 1)<cr> |
||||
xnoremap <silent> <sid>(matchup-[%) |
||||
\ :<c-u>call matchup#motion#find_unmatched(1, 0)<cr> |
||||
xmap <plug>(matchup-]%) <sid>(matchup-]%) |
||||
xmap <plug>(matchup-[%) <sid>(matchup-[%) |
||||
onoremap <silent> <plug>(matchup-]%) |
||||
\ :<c-u>call matchup#motion#op(']%')<cr> |
||||
onoremap <silent> <plug>(matchup-[%) |
||||
\ :<c-u>call matchup#motion#op('[%')<cr> |
||||
|
||||
" jump inside z% |
||||
nnoremap <silent> <plug>(matchup-z%) |
||||
\ :<c-u>call matchup#motion#jump_inside(0)<cr> |
||||
|
||||
xnoremap <silent> <sid>(matchup-z%) |
||||
\ :<c-u>call matchup#motion#jump_inside(1)<cr> |
||||
xmap <silent> <plug>(matchup-z%) <sid>(matchup-z%) |
||||
onoremap <silent> <plug>(matchup-z%) |
||||
\ :<c-u>call matchup#motion#op('z%')<cr> |
||||
|
||||
inoremap <silent> <plug>(matchup-c_g%) |
||||
\ <c-\><c-o>:call matchup#motion#insert_mode()<cr> |
||||
|
||||
call matchup#perf#toc('loading_module', 'motion') |
||||
endfunction |
||||
|
||||
" TODO redo this |
||||
function! s:snr() |
||||
return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_snr$')) |
||||
endfunction |
||||
let s:sid = printf("\<SNR>%d_", s:snr()) |
||||
|
||||
function! matchup#motion_sid() |
||||
return s:sid |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:text_obj_init_module() " {{{1 |
||||
if !g:matchup_text_obj_enabled | return | endif |
||||
|
||||
call matchup#perf#tic('loading_module') |
||||
|
||||
for [l:map, l:name, l:opt] in [ |
||||
\ ['%', 'delimited', 'delim_all'], |
||||
\] |
||||
let l:p1 = 'noremap <silent> <plug>(matchup-' |
||||
let l:p2 = l:map . ') :<c-u>call matchup#text_obj#' . l:name |
||||
let l:p3 = empty(l:opt) ? ')<cr>' : ', ''' . l:opt . ''')<cr>' |
||||
execute 'x' . l:p1 . 'i' . l:p2 . '(1, 1' . l:p3 |
||||
execute 'x' . l:p1 . 'a' . l:p2 . '(0, 1' . l:p3 |
||||
execute 'o' . l:p1 . 'i' . l:p2 . '(1, 0' . l:p3 |
||||
execute 'o' . l:p1 . 'a' . l:p2 . '(0, 0' . l:p3 |
||||
endfor |
||||
|
||||
nnoremap <silent> <plug>(matchup-double-click) |
||||
\ :<c-u>call matchup#text_obj#double_click()<cr> |
||||
|
||||
call matchup#perf#toc('loading_module', 'motion') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:misc_init_module() " {{{1 |
||||
call matchup#perf#tic('loading_module') |
||||
command! MatchupReload call matchup#misc#reload() |
||||
nnoremap <plug>(matchup-reload) :<c-u>MatchupReload<cr> |
||||
call matchup#perf#toc('loading_module', 'misc') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:surround_init_module() " {{{1 |
||||
if !g:matchup_surround_enabled | return | endif |
||||
|
||||
call matchup#perf#tic('loading_module') |
||||
|
||||
for [l:map, l:name, l:opt] in [ |
||||
\ ['%', 'delimited', 'delim_all'], |
||||
\] |
||||
let l:p1 = 'noremap <silent> <plug>(matchup-' |
||||
let l:p2 = l:map . ') :<c-u>call matchup#surround#' . l:name |
||||
let l:p3 = empty(l:opt) ? ')<cr>' : ', ''' . l:opt . ''')<cr>' |
||||
execute 'n' . l:p1 . 'ds' . l:p2 . '(0, "d"' . l:p3 |
||||
execute 'n' . l:p1 . 'cs' . l:p2 . '(0, "c"' . l:p3 |
||||
endfor |
||||
|
||||
call matchup#perf#toc('loading_module', 'surround') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:where_init_module() " {{{1 |
||||
if !g:matchup_where_enabled | return | endif |
||||
|
||||
command! -nargs=? -bang MatchupWhereAmI |
||||
\ call matchup#where#print('<bang>' . <q-args>) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,152 @@
@@ -0,0 +1,152 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
"" |
||||
" example motion as described in issues/49: |
||||
" - if on a delim, go to {count} next matching delim, up or down |
||||
" - if not on a delim, go to {count} local surrounding, up or down |
||||
" |
||||
" {info} dict with the following fields: |
||||
" visual : 1 if visual or operator mode |
||||
" count/count1: v:count/v:count1 for this map |
||||
" operator : if non-empty, the operator in op mode |
||||
" motion_force: forced operator mode, e.g, for 'dvx' this is 'v' |
||||
" {opts} user data dict from motion definition |
||||
function! matchup#custom#example_motion(info, opts) abort |
||||
let l:delim = matchup#delim#get_current('all', 'both_all') |
||||
if !empty(l:delim) |
||||
let l:matches = matchup#delim#get_matching(l:delim, 1) |
||||
if len(l:matches) |
||||
for _ in range(a:info.count1) |
||||
let l:delim = l:delim.links[a:opts.down ? 'next': 'prev'] |
||||
endfor |
||||
return matchup#custom#suggest_pos(l:delim, a:opts) |
||||
endif |
||||
endif |
||||
|
||||
let [l:open_, l:close_] = matchup#delim#get_surrounding( |
||||
\ 'delim_all', v:count1) |
||||
if empty(l:open_) || empty(l:close_) |
||||
return [] |
||||
endif |
||||
let [l:open, l:close] = matchup#delim#get_surround_nearest(l:open_) |
||||
if empty(l:open) |
||||
let [l:open, l:close] = [l:open_, l:open_.links.next] |
||||
endif |
||||
let l:delim = a:opts.down ? l:close : l:open |
||||
|
||||
" exclude delim in operators unless v is given |
||||
if !empty(a:info.operator) && a:info.motion_force !=# 'v' |
||||
if a:opts.down |
||||
return matchup#pos#prev(l:delim) |
||||
else |
||||
return matchup#pos#next(matchup#delim#end_pos(l:delim)) |
||||
endif |
||||
else |
||||
return matchup#custom#suggest_pos(l:delim, a:opts) |
||||
endif |
||||
endfunction |
||||
|
||||
"" |
||||
" api function: get the preferred cursor location for delim |
||||
" {delim} delimiter object |
||||
" {opts} field 'down' denotes motion direction |
||||
function! matchup#custom#suggest_pos(delim, opts) abort |
||||
if g:matchup_motion_cursor_end && (a:delim.side ==# 'close' |
||||
\ || a:delim.side ==# 'mid' && get(a:opts, 'down', 0)) |
||||
return [a:delim.lnum, matchup#delim#jump_target(a:delim)] |
||||
endif |
||||
return matchup#pos#(a:delim) |
||||
endfunction |
||||
|
||||
"" |
||||
" define a custom motion |
||||
" {modes} specify which modes modes of {n,o,x} the mapping is active in |
||||
" {keys} key sequence for map |
||||
" {fcn} function to call, must take two arguments |
||||
" [@opts] user data dict passed to function |
||||
function! matchup#custom#define_motion(modes, keys, fcn, ...) abort |
||||
if a:modes !~# '^[nox]\+$' |
||||
echoerr "invalid modes" |
||||
endif |
||||
|
||||
let s:custom_counter += 1 |
||||
let l:k = s:custom_counter |
||||
let l:opts = a:0 ? deepcopy(a:1) : {} |
||||
call extend(l:opts, { 'fcn': a:fcn, 'keys': a:keys }) |
||||
let s:custom_opts[l:k] = l:opts |
||||
|
||||
if a:modes =~# 'n' |
||||
execute 'nnoremap <silent> <plug>(matchup-custom-'.a:keys.')' |
||||
\ ':<c-u>call matchup#custom#wrap(0, '.l:k.')<cr>' |
||||
execute 'nmap' a:keys '<plug>(matchup-custom-'.a:keys.')' |
||||
endif |
||||
|
||||
if a:modes =~# '[xo]' |
||||
let l:sid = substitute(matchup#motion_sid(), "\<snr>", '<snr>', '') |
||||
execute 'xnoremap <silent>' l:sid.'(matchup-custom-'.l:k.')' |
||||
\ ':<c-u>call matchup#custom#wrap(1, '.l:k.')<cr>' |
||||
endif |
||||
|
||||
if a:modes =~# 'x' |
||||
execute 'xmap <silent> <plug>(matchup-custom-'.a:keys.')' |
||||
\ l:sid.'(matchup-custom-'.l:k.')' |
||||
execute 'xmap <silent>' a:keys '<plug>(matchup-custom-'.a:keys.')' |
||||
endif |
||||
|
||||
if a:modes =~# 'o' |
||||
execute 'onoremap <silent> <plug>(matchup-custom-'.a:keys.')' |
||||
\ ':<c-u>call matchup#motion#op(' |
||||
\ . string('custom-'.l:k).')<cr>' |
||||
if !call(matchup#motion_sid().'make_oldstyle_omaps', |
||||
\ [a:keys, 'custom-'.a:keys]) |
||||
execute 'omap' a:keys '<plug>(matchup-custom-'.a:keys.')' |
||||
endif |
||||
endif |
||||
endfunction |
||||
|
||||
if !exists('s:custom_opts') |
||||
let s:custom_opts = {} |
||||
let s:custom_counter = 0 |
||||
endif |
||||
|
||||
" motion wrapper |
||||
function! matchup#custom#wrap(visual, id) abort |
||||
" default to 1 second (can override in custom motion) |
||||
call matchup#perf#timeout_start(1000) |
||||
|
||||
let l:info = { |
||||
\ 'visual': a:visual, |
||||
\ 'count': v:count, |
||||
\ 'count1': v:count1, |
||||
\ 'operator': matchup#motion#getoper(), |
||||
\ 'motion_force': g:v_motion_force, |
||||
\} |
||||
let l:is_oper = !empty(l:info.operator) |
||||
let l:opts = s:custom_opts[a:id] |
||||
|
||||
if a:visual |
||||
normal! gv |
||||
endif |
||||
|
||||
let l:ret = call(l:opts.fcn, [l:info, l:opts]) |
||||
|
||||
if type(l:ret) != type([]) || empty(l:ret) |
||||
if !a:visual || l:is_oper |
||||
execute "normal! \<esc>" |
||||
endif |
||||
elseif type(l:ret) == type([]) && len(l:ret) >= 2 |
||||
call matchup#pos#set_cursor(l:ret) |
||||
endif |
||||
endfunction |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,918 @@
@@ -0,0 +1,918 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#delim#get_next(type, side, ...) " {{{1 |
||||
return s:get_delim(extend({ |
||||
\ 'direction' : 'next', |
||||
\ 'type' : a:type, |
||||
\ 'side' : a:side, |
||||
\}, get(a:, '1', {}))) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#delim#get_prev(type, side, ...) " {{{1 |
||||
return s:get_delim(extend({ |
||||
\ 'direction' : 'prev', |
||||
\ 'type' : a:type, |
||||
\ 'side' : a:side, |
||||
\}, get(a:, '1', {}))) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#delim#get_current(type, side, ...) " {{{1 |
||||
return s:get_delim(extend({ |
||||
\ 'direction' : 'current', |
||||
\ 'type' : a:type, |
||||
\ 'side' : a:side, |
||||
\}, get(a:, '1', {}))) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#delim#get_matching(delim, ...) " {{{1 |
||||
if empty(a:delim) || !has_key(a:delim, 'lnum') | return {} | endif |
||||
|
||||
let l:opts = a:0 && type(a:1) == type({}) ? a:1 : {} |
||||
let l:stopline = get(l:opts, 'stopline', s:stopline) |
||||
|
||||
" get all the matching position(s) |
||||
" *important*: in the case of mid, we search up before searching down |
||||
" this gives us a context object which we use for the other side |
||||
" TODO: what if no open is found here? |
||||
let l:matches = [] |
||||
let l:save_pos = matchup#pos#get_cursor() |
||||
for l:down in {'open': [1], 'close': [0], 'mid': [0,1]}[a:delim.side] |
||||
call matchup#pos#set_cursor(a:delim) |
||||
|
||||
" second iteration: [] refers to the current match |
||||
if !empty(l:matches) |
||||
call add(l:matches, []) |
||||
endif |
||||
|
||||
let l:res = a:delim.get_matching(l:down, l:stopline) |
||||
if l:res[0][1] > 0 |
||||
call extend(l:matches, l:res) |
||||
elseif l:down |
||||
let l:matches = [] |
||||
endif |
||||
endfor |
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
|
||||
if a:delim.side ==# 'open' |
||||
call insert(l:matches, []) |
||||
endif |
||||
if a:delim.side ==# 'close' |
||||
call add(l:matches, []) |
||||
endif |
||||
|
||||
" create the match result(s) |
||||
let l:matching_list = [] |
||||
for l:i in range(len(l:matches)) |
||||
if empty(l:matches[l:i]) |
||||
let a:delim.match_index = l:i |
||||
call add(l:matching_list, a:delim) |
||||
continue |
||||
end |
||||
|
||||
let [l:match, l:lnum, l:cnum] = l:matches[l:i] |
||||
|
||||
let l:matching = copy(a:delim) |
||||
let l:matching.class = copy(a:delim.class) |
||||
|
||||
let l:matching.lnum = l:lnum |
||||
let l:matching.cnum = l:cnum |
||||
let l:matching.match = l:match |
||||
let l:matching.side = l:i == 0 ? 'open' |
||||
\ : l:i == len(l:matches)-1 ? 'close' : 'mid' |
||||
let l:matching.class[1] = 'FIXME' |
||||
let l:matching.match_index = l:i |
||||
|
||||
call add(l:matching_list, l:matching) |
||||
endfor |
||||
|
||||
" set up links between matches |
||||
for l:i in range(len(l:matching_list)) |
||||
let l:c = l:matching_list[l:i] |
||||
let l:c.links = {} |
||||
let l:c.links.next = l:matching_list[(l:i+1) % len(l:matching_list)] |
||||
let l:c.links.prev = l:matching_list[l:i-1] |
||||
let l:c.links.open = l:matching_list[0] |
||||
let l:c.links.close = l:matching_list[-1] |
||||
endfor |
||||
|
||||
return l:matching_list |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#delim#get_surrounding(type, ...) " {{{1 |
||||
call matchup#perf#tic('delim#get_surrounding') |
||||
|
||||
let l:save_pos = matchup#pos#get_cursor() |
||||
let l:pos_val_cursor = matchup#pos#val(l:save_pos) |
||||
let l:pos_val_last = l:pos_val_cursor |
||||
let l:pos_val_open = l:pos_val_cursor - 1 |
||||
|
||||
let l:count = a:0 >= 1 ? a:1 : 1 |
||||
let l:counter = l:count |
||||
|
||||
" third argument specifies local any block, otherwise, |
||||
" provided count == 0 refers to local any block |
||||
let l:opts = a:0 >= 2 ? a:2 : {} |
||||
let l:local = get(l:opts, 'local', l:count == 0 ? 1 : 0) |
||||
|
||||
let l:delimopts = {} |
||||
let s:invert_skip = 0 " TODO: this logic is still bad |
||||
if matchup#delim#skip() " TODO: check for insert mode (?) |
||||
let l:delimopts.check_skip = 0 |
||||
endif |
||||
" TODO: pin skip |
||||
if get(l:opts, 'check_skip', 0) |
||||
let l:delimopts.check_skip = 1 |
||||
endif |
||||
|
||||
" keep track of the outermost pair found so far |
||||
" returned when g:matchup_delim_count_fail = 1 |
||||
let l:best = [] |
||||
|
||||
while l:pos_val_open < l:pos_val_last |
||||
let l:open = matchup#delim#get_prev(a:type, |
||||
\ l:local ? 'open_mid' : 'open', l:delimopts) |
||||
if empty(l:open) | break | endif |
||||
|
||||
" if configured, we may still accept this match |
||||
if matchup#perf#timeout_check() && !g:matchup_delim_count_fail |
||||
break |
||||
endif |
||||
|
||||
let l:matches = matchup#delim#get_matching(l:open, 1) |
||||
|
||||
" TODO: getting one match result here is surely wrong |
||||
if len(l:matches) == 1 |
||||
let l:matches = [] |
||||
endif |
||||
|
||||
if has_key(l:opts, 'matches') |
||||
let l:opts.matches = l:matches |
||||
endif |
||||
|
||||
if len(l:matches) |
||||
let l:close = l:local ? l:open.links.next : l:open.links.close |
||||
let l:pos_val_try = matchup#pos#val(l:close) |
||||
\ + matchup#delim#end_offset(l:close) |
||||
endif |
||||
|
||||
if len(l:matches) && l:pos_val_try >= l:pos_val_cursor |
||||
if l:counter <= 1 |
||||
" restore cursor and accept |
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
call matchup#perf#toc('delim#get_surrounding', 'accept') |
||||
return [l:open, l:close] |
||||
endif |
||||
let l:counter -= 1 |
||||
let l:best = [l:open, l:close] |
||||
else |
||||
let l:pos_val_last = l:pos_val_open |
||||
let l:pos_val_open = matchup#pos#val(l:open) |
||||
endif |
||||
|
||||
if l:open.lnum == 1 && l:open.cnum == 1 |
||||
break |
||||
endif |
||||
call matchup#pos#set_cursor(matchup#pos#prev(l:open)) |
||||
endwhile |
||||
|
||||
if !empty(l:best) && g:matchup_delim_count_fail |
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
call matchup#perf#toc('delim#get_surrounding', 'bad_count') |
||||
return l:best |
||||
endif |
||||
|
||||
" restore cursor and return failure |
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
call matchup#perf#toc('delim#get_surrounding', 'fail') |
||||
return [{}, {}] |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#delim#get_surround_nearest(open, ...) " {{{1 |
||||
" finds the first consecutive pair whose start |
||||
" positions surround pos (default to the cursor) |
||||
let l:cur_pos = a:0 ? a:1 : matchup#pos#get_cursor() |
||||
let l:pos_val_cursor = matchup#pos#val(l:cur_pos) |
||||
let l:pos_val_open = matchup#pos#val(a:open) |
||||
|
||||
let l:pos_val_prev = l:pos_val_open |
||||
let l:delim = a:open.links.next |
||||
let l:pos_val_next = matchup#pos#val(l:delim) |
||||
while l:pos_val_next > l:pos_val_open |
||||
let l:end_offset = matchup#delim#end_offset(l:delim) |
||||
if l:pos_val_prev <= l:pos_val_cursor |
||||
\ && l:pos_val_next + l:end_offset >= l:pos_val_cursor |
||||
return [l:delim.links.prev, l:delim] |
||||
endif |
||||
let l:pos_val_prev = l:pos_val_next |
||||
let l:delim = l:delim.links.next |
||||
let l:pos_val_next = matchup#pos#val(l:delim) |
||||
endwhile |
||||
|
||||
return [{}, {}] |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#delim#jump_target(delim) " {{{1 |
||||
let l:save_pos = matchup#pos#get_cursor() |
||||
|
||||
" unicode note: technically wrong, but works in practice |
||||
" since the cursor snaps back to start of multi-byte chars |
||||
let l:column = a:delim.cnum |
||||
let l:column += strlen(a:delim.match) - 1 |
||||
|
||||
if strlen(a:delim.match) < 2 |
||||
return l:column |
||||
endif |
||||
|
||||
for l:tries in range(strlen(a:delim.match)-1) |
||||
call matchup#pos#set_cursor(a:delim.lnum, l:column) |
||||
|
||||
let l:delim_test = matchup#delim#get_current('all', 'both_all') |
||||
if l:delim_test.class[0] ==# a:delim.class[0] |
||||
break |
||||
endif |
||||
|
||||
let l:column -= 1 |
||||
endfor |
||||
|
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
return l:column |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#delim#end_offset(delim) " {{{1 |
||||
return max([0, match(a:delim.match, '.$')]) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#delim#end_pos(delim) abort " {{{1 |
||||
return [a:delim.lnum, a:delim.cnum + matchup#delim#end_offset(a:delim)] |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:get_delim(opts) " {{{1 |
||||
" arguments: {{{2 |
||||
" opts = { |
||||
" 'direction' : 'next' | 'prev' | 'current' |
||||
" 'type' : 'delim_tex' |
||||
" | 'delim_all' |
||||
" | 'all' |
||||
" 'side' : 'open' | 'close' |
||||
" | 'both' | 'mid' |
||||
" | 'both_all' | 'open_mid' |
||||
" } |
||||
" |
||||
" }}}2 |
||||
" returns: {{{2 |
||||
" delim = { |
||||
" type : 'delim' |
||||
" lnum : line number |
||||
" cnum : column number |
||||
" match : the actual text match |
||||
" augment : how to match a corresponding open |
||||
" groups : dict of captured groups |
||||
" side : 'open' | 'close' | 'mid' |
||||
" class : [ c1, c2 ] identifies the kind of match_words |
||||
" regexone : the regex item, like \1foo |
||||
" regextwo : the regex_capture item, like \(group\)foo |
||||
" } |
||||
" |
||||
" }}}2 |
||||
|
||||
if !get(b:, 'matchup_delim_enabled', 0) |
||||
return {} |
||||
endif |
||||
|
||||
call matchup#perf#tic('s:get_delim') |
||||
|
||||
let l:save_pos = matchup#pos#get_cursor() |
||||
|
||||
call matchup#loader#refresh_match_words() |
||||
|
||||
" this contains all the patterns for the specified type and side |
||||
let l:re = b:matchup_delim_re[a:opts.type][a:opts.side] |
||||
|
||||
let l:cursorpos = col('.') |
||||
|
||||
let l:insertmode = get(a:opts, 'insertmode', 0) |
||||
if l:cursorpos > 1 && l:insertmode |
||||
let l:cursorpos -= 1 |
||||
endif |
||||
if l:cursorpos > strlen(getline('.')) |
||||
\ && stridx("vV\<c-v>", mode()) > -1 |
||||
let l:cursorpos -= 1 |
||||
endif |
||||
|
||||
let s:invert_skip = 0 |
||||
|
||||
if a:opts.direction ==# 'current' |
||||
let l:check_skip = get(a:opts, 'check_skip', |
||||
\ g:matchup_delim_noskips >= 2 |
||||
\ || g:matchup_delim_noskips >= 1 |
||||
\ && getline(line('.'))[l:cursorpos-1] =~ '[^[:punct:]]') |
||||
if l:check_skip && matchup#delim#skip(line('.'), l:cursorpos) |
||||
return {} |
||||
endif |
||||
else |
||||
" check skip if cursor is not currently in skip |
||||
let l:check_skip = get(a:opts, 'check_skip', |
||||
\ !matchup#delim#skip(line('.'), l:cursorpos) |
||||
\ || g:matchup_delim_noskips >= 2) |
||||
endif |
||||
|
||||
let a:opts.cursorpos = l:cursorpos |
||||
|
||||
" for current, we want to find matches that end after the cursor |
||||
" note: we expect this to give false-positives with \ze |
||||
if a:opts.direction ==# 'current' |
||||
let l:re .= '\%>'.(l:cursorpos).'c' |
||||
" let l:re = '\%<'.(l:cursorpos+1).'c' . l:re |
||||
endif |
||||
|
||||
" allow overlapping delimiters |
||||
" without this, the > in <tag> would not be found |
||||
if b:matchup_delim_re[a:opts.type]._engine_info.has_zs[a:opts.side] |
||||
let l:save_cpo = &cpo |
||||
noautocmd set cpo-=c |
||||
else |
||||
" faster than changing cpo but doesn't work right with \zs |
||||
let l:re .= '\&' |
||||
endif |
||||
|
||||
" move cursor one left for searchpos if necessary |
||||
let l:need_restore_cursor = 0 |
||||
if l:insertmode |
||||
call matchup#pos#set_cursor(line('.'), col('.')-1) |
||||
let l:need_restore_cursor = 1 |
||||
endif |
||||
|
||||
" stopline may depend on the current action |
||||
let l:stopline = get(a:opts, 'stopline', s:stopline) |
||||
|
||||
" in the first pass, we get matching line and column numbers |
||||
" this is intended to be as fast as possible, with no capture groups |
||||
" we look for a match on this line (if direction == current) |
||||
" or forwards or backwards (if direction == next or prev) |
||||
" for current, we actually search leftwards from the cursor |
||||
while 1 |
||||
let l:to = matchup#perf#timeout() |
||||
let [l:lnum, l:cnum] = a:opts.direction ==# 'next' |
||||
\ ? searchpos(l:re, 'cnW', line('.') + l:stopline, l:to) |
||||
\ : a:opts.direction ==# 'prev' |
||||
\ ? searchpos(l:re, 'bcnW', |
||||
\ max([line('.') - l:stopline, 1]), l:to) |
||||
\ : searchpos(l:re, 'bcnW', line('.'), l:to) |
||||
if l:lnum == 0 | break | endif |
||||
|
||||
" note: the skip here should not be needed |
||||
" in 'current' mode, but be explicit |
||||
if a:opts.direction !=# 'current' |
||||
\ && (l:check_skip || g:matchup_delim_noskips == 1 |
||||
\ && getline(l:lnum)[l:cnum-1] =~ '[^[:punct:]]') |
||||
\ && matchup#delim#skip(l:lnum, l:cnum) |
||||
\ && (a:opts.direction ==# 'prev' ? (l:lnum > 1 || l:cnum > 1) |
||||
\ : (l:lnum < line('$') || l:cnum < len(getline('$')))) |
||||
|
||||
" invalid match, move cursor and keep looking |
||||
call matchup#pos#set_cursor(a:opts.direction ==# 'next' |
||||
\ ? matchup#pos#next(l:lnum, l:cnum) |
||||
\ : matchup#pos#prev(l:lnum, l:cnum)) |
||||
let l:need_restore_cursor = 1 |
||||
continue |
||||
endif |
||||
|
||||
break |
||||
endwhile |
||||
|
||||
" restore cpo if necessary |
||||
" note: this messes with cursor position |
||||
if exists('l:save_cpo') |
||||
noautocmd let &cpo = l:save_cpo |
||||
let l:need_restore_cursor = 1 |
||||
endif |
||||
|
||||
" restore cursor |
||||
if l:need_restore_cursor |
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
endif |
||||
|
||||
call matchup#perf#toc('s:get_delim', 'first_pass') |
||||
|
||||
" nothing found, leave now |
||||
if l:lnum == 0 |
||||
call matchup#perf#toc('s:get_delim', 'nothing_found') |
||||
return {} |
||||
endif |
||||
|
||||
if matchup#perf#timeout_check() |
||||
return {} |
||||
endif |
||||
|
||||
let l:skip_state = 0 |
||||
if !l:check_skip && (!&synmaxcol || l:cnum <= &synmaxcol) |
||||
" XXX: workaround an apparent obscure vim bug where the |
||||
" reported syntax id is incorrect on the first synID() call |
||||
call matchup#delim#skip(l:lnum, l:cnum) |
||||
if matchup#perf#timeout_check() |
||||
return {} |
||||
endif |
||||
|
||||
let l:skip_state = matchup#delim#skip(l:lnum, l:cnum) |
||||
endif |
||||
|
||||
" now we get more data about the match in this position |
||||
" there may be capture groups which need to be stored |
||||
|
||||
" result stub, to be filled by the parser when there is a match |
||||
let l:result = { |
||||
\ 'lnum' : l:lnum, |
||||
\ 'cnum' : l:cnum, |
||||
\ 'type' : '', |
||||
\ 'match' : '', |
||||
\ 'augment' : '', |
||||
\ 'groups' : '', |
||||
\ 'side' : '', |
||||
\ 'class' : [], |
||||
\ 'regexone' : '', |
||||
\ 'regextwo' : '', |
||||
\ 'skip' : l:skip_state, |
||||
\} |
||||
|
||||
for l:type in s:types[a:opts.type] |
||||
let l:parser_result = l:type.parser(l:lnum, l:cnum, a:opts) |
||||
if !empty(l:parser_result) |
||||
let l:result = extend(l:parser_result, l:result, 'keep') |
||||
break |
||||
endif |
||||
endfor |
||||
|
||||
call matchup#perf#toc('s:get_delim', 'got_results') |
||||
|
||||
return empty(l:result.type) ? {} : l:result |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:parser_delim_new(lnum, cnum, opts) " {{{1 |
||||
let l:cursorpos = a:opts.cursorpos |
||||
let l:found = 0 |
||||
|
||||
let l:sides = matchup#loader#sidedict()[a:opts.side] |
||||
let l:rebrs = b:matchup_delim_lists[a:opts.type].regex_capture |
||||
|
||||
" use b:match_ignorecase |
||||
let l:ic = get(b:, 'match_ignorecase', 0) ? '\c' : '\C' |
||||
|
||||
" loop through all (index, side) pairs, |
||||
let l:ns = len(l:sides) |
||||
let l:found = 0 |
||||
for l:i in range(len(l:rebrs)*l:ns) |
||||
let l:side = l:sides[ l:i % l:ns ] |
||||
|
||||
if l:side ==# 'mid' |
||||
let l:res = l:rebrs[l:i / l:ns].mid_list |
||||
if empty(l:res) | continue | end |
||||
else |
||||
let l:res = [ l:rebrs[l:i / l:ns][l:side] ] |
||||
if empty(l:res[0]) | continue | end |
||||
endif |
||||
|
||||
" if pattern may contain \zs, extra processing is required |
||||
let l:extra_info = l:rebrs[l:i / l:ns].extra_info |
||||
let l:has_zs = get(l:extra_info, 'has_zs', 0) |
||||
|
||||
let l:mid_id = 0 |
||||
for l:re in l:res |
||||
let l:mid_id += 1 |
||||
|
||||
" check whether hlend needs to be handled |
||||
let l:id = l:side ==# 'mid' ? l:mid_id : l:side ==# 'open' ? 0 : -1 |
||||
let l:extra_entry = l:rebrs[l:i / l:ns].extra_list[l:id] |
||||
let l:has_hlend = has_key(l:extra_entry, 'hlend') |
||||
|
||||
if l:has_hlend && get(a:opts, 'highlighting', 0) |
||||
let l:re = s:process_hlend(l:re, l:cursorpos) |
||||
endif |
||||
|
||||
" prepend the column number and append the cursor column |
||||
" to anchor the match; we don't use {start} for matchlist |
||||
" because there may be zero-width look behinds |
||||
let l:re_anchored = l:ic . s:anchor_regex(l:re, a:cnum, l:has_zs) |
||||
|
||||
" for current we want the first match which the cursor is inside |
||||
if a:opts.direction ==# 'current' |
||||
let l:re_anchored .= '\%>'.(l:cursorpos).'c' |
||||
endif |
||||
|
||||
let l:matches = matchlist(getline(a:lnum), l:re_anchored) |
||||
if empty(l:matches) | continue | endif |
||||
|
||||
" reject matches which the cursor is outside of |
||||
" this matters only for \ze |
||||
if !l:has_hlend && a:opts.direction ==# 'current' |
||||
\ && a:cnum + strlen(l:matches[0]) <= l:cursorpos |
||||
continue |
||||
endif |
||||
|
||||
" if pattern contains \zs we need to re-check the starting column |
||||
if l:has_zs && match(getline(a:lnum), l:re_anchored) != a:cnum-1 |
||||
continue |
||||
endif |
||||
|
||||
let l:found = 1 |
||||
break |
||||
endfor |
||||
|
||||
if !l:found | continue | endif |
||||
|
||||
break |
||||
endfor |
||||
|
||||
" reset ignorecase (defunct) |
||||
|
||||
if !l:found |
||||
return {} |
||||
endif |
||||
|
||||
let l:match = l:matches[0] |
||||
|
||||
let l:list = b:matchup_delim_lists[a:opts.type] |
||||
let l:thisre = l:list.regex[l:i / l:ns] |
||||
let l:thisrebr = l:list.regex_capture[l:i / l:ns] |
||||
|
||||
let l:augment = {} |
||||
|
||||
" these are the capture groups indexed by their 'open' id |
||||
let l:groups = {} |
||||
let l:id = 0 |
||||
|
||||
if l:side ==# 'open' |
||||
" XXX we might as well store all the groups... |
||||
"for l:br in keys(l:thisrebr.need_grp) |
||||
for l:br in range(1,9) |
||||
if empty(l:matches[l:br]) | continue | endif |
||||
let l:groups[l:br] = l:matches[l:br] |
||||
endfor |
||||
else |
||||
let l:id = (l:side ==# 'close') |
||||
\ ? len(l:thisrebr.mid_list)+1 |
||||
\ : l:mid_id |
||||
|
||||
if has_key(l:thisrebr.grp_renu, l:id) |
||||
for [l:br, l:to] in items(l:thisrebr.grp_renu[l:id]) |
||||
let l:groups[l:to] = l:matches[l:br] |
||||
endfor |
||||
endif |
||||
|
||||
" fill in augment pattern |
||||
" TODO all the augment patterns should match, |
||||
" but checking might be too slow |
||||
if has_key(l:thisrebr.aug_comp, l:id) |
||||
let l:aug = l:thisrebr.aug_comp[l:id][0] |
||||
let l:augment.str = matchup#delim#fill_backrefs( |
||||
\ l:aug.str, l:groups, 0) |
||||
let l:augment.unresolved = deepcopy(l:aug.outputmap) |
||||
endif |
||||
endif |
||||
|
||||
let l:result = { |
||||
\ 'type' : 'delim_tex', |
||||
\ 'match' : l:match, |
||||
\ 'augment' : l:augment, |
||||
\ 'groups' : l:groups, |
||||
\ 'side' : l:side, |
||||
\ 'class' : [(l:i / l:ns), l:id], |
||||
\ 'get_matching' : s:basetypes['delim_tex'].get_matching, |
||||
\ 'regexone' : l:thisre, |
||||
\ 'regextwo' : l:thisrebr, |
||||
\ 'midmap' : get(l:list, 'midmap', {}), |
||||
\ 'highlighting' : get(a:opts, 'highlighting', 0), |
||||
\} |
||||
|
||||
return l:result |
||||
endfunction |
||||
" }}}1 |
||||
|
||||
function! s:get_matching_delims(down, stopline) dict " {{{1 |
||||
" called as: a:delim.get_matching(...) |
||||
" called from: matchup#delim#get_matching <- matchparen, motion |
||||
" from: matchup#delim#get_surrounding <- matchparen, motion, text_obj |
||||
|
||||
call matchup#perf#tic('get_matching_delims') |
||||
|
||||
" first, we figure out what the furthest match is, which will be |
||||
" either the open or close depending on the direction |
||||
let [l:re, l:flags, l:stopline] = a:down |
||||
\ ? [self.regextwo.close, 'W', line('.') + a:stopline] |
||||
\ : [self.regextwo.open, 'bW', max([line('.') - a:stopline, 1])] |
||||
|
||||
" these are the anchors for searchpairpos |
||||
let l:open = self.regexone.open " TODO is this right? BADLOGIC |
||||
let l:close = self.regexone.close |
||||
|
||||
" if we're searching up, we anchor by the augment, if it exists |
||||
if !a:down && !empty(self.augment) |
||||
let l:open = self.augment.str |
||||
endif |
||||
|
||||
" TODO temporary workaround for BADLOGIC |
||||
if a:down && self.side ==# 'mid' |
||||
let l:open = self.regextwo.open |
||||
endif |
||||
|
||||
" turn \(\) into \%(\) for searchpairpos |
||||
let l:open = matchup#loader#remove_capture_groups(l:open) |
||||
let l:close = matchup#loader#remove_capture_groups(l:close) |
||||
|
||||
" fill in back-references |
||||
" TODO: BADLOGIC2: when going up we don't have these groups yet.. |
||||
" the second anchor needs to be mid/self for mid self |
||||
let l:open = matchup#delim#fill_backrefs(l:open, self.groups, 0) |
||||
let l:close = matchup#delim#fill_backrefs(l:close, self.groups, 0) |
||||
|
||||
let s:invert_skip = self.skip |
||||
if empty(b:matchup_delim_skip) |
||||
let l:skip = 'matchup#delim#skip_default()' |
||||
else |
||||
let l:skip = 'matchup#delim#skip0()' |
||||
endif |
||||
|
||||
" disambiguate matches for languages like julia, matlab, ruby, etc |
||||
if !empty(self.midmap) |
||||
let l:midmap = self.midmap.elements |
||||
if self.side ==# 'mid' |
||||
let l:idx = filter(range(len(l:midmap)), |
||||
\ 'self.match =~# l:midmap[v:val][1]') |
||||
else |
||||
let l:syn = synIDattr(synID(self.lnum, self.cnum, 0), 'name') |
||||
let l:idx = filter(range(len(l:midmap)), |
||||
\ 'l:syn =~# l:midmap[v:val][0]') |
||||
endif |
||||
if len(l:idx) |
||||
let l:valid = l:midmap[l:idx[0]] |
||||
let l:skip = printf('matchup#delim#skip1(%s, %s)', |
||||
\ string(l:midmap[l:idx[0]]), string(l:skip)) |
||||
else |
||||
let l:skip = printf('matchup#delim#skip2(%s, %s)', |
||||
\ string(self.midmap.strike), string(l:skip)) |
||||
endif |
||||
endif |
||||
|
||||
if matchup#perf#timeout_check() | return [['', 0, 0]] | endif |
||||
|
||||
" improves perceptual performance in insert mode |
||||
if mode() ==# 'i' || mode() ==# 'R' |
||||
if !g:matchup_matchparen_deferred |
||||
sleep 1m |
||||
endif |
||||
endif |
||||
|
||||
" use b:match_ignorecase |
||||
let l:ic = get(b:, 'match_ignorecase', 0) ? '\c' : '\C' |
||||
let l:open = l:ic . l:open |
||||
let l:close = l:ic . l:close |
||||
|
||||
let [l:lnum_corr, l:cnum_corr] = searchpairpos(l:open, '', l:close, |
||||
\ 'n'.l:flags, l:skip, l:stopline, matchup#perf#timeout()) |
||||
|
||||
call matchup#perf#toc('get_matching_delims', 'initial_pair') |
||||
|
||||
" if nothing found, bail immediately |
||||
if l:lnum_corr == 0 |
||||
" reset ignorecase (defunct) |
||||
|
||||
return [['', 0, 0]] |
||||
endif |
||||
|
||||
" when highlighting, respect hlend |
||||
let l:extra_entry = self.regextwo.extra_list[a:down ? -1 : 0] |
||||
if self.highlighting && has_key(l:extra_entry, 'hlend') |
||||
let l:re = s:process_hlend(l:re, -1) |
||||
endif |
||||
|
||||
" get the match and groups |
||||
let l:has_zs = self.regextwo.extra_info.has_zs |
||||
let l:re_anchored = l:ic . s:anchor_regex(l:re, l:cnum_corr, l:has_zs) |
||||
let l:matches = matchlist(getline(l:lnum_corr), l:re_anchored) |
||||
let l:match_corr = l:matches[0] |
||||
|
||||
" reset ignorecase (defunct) |
||||
|
||||
" store these in these groups |
||||
if a:down |
||||
" let l:id = len(self.regextwo.mid_list)+1 |
||||
" for [l:from, l:to] in items(self.regextwo.grp_renu[l:id]) |
||||
" let self.groups[l:to] = l:matches[l:from] |
||||
" endfor |
||||
else |
||||
for l:to in range(1,9) |
||||
if !has_key(self.groups, l:to) && !empty(l:matches[l:to]) |
||||
let self.groups[l:to] = l:matches[l:to] |
||||
endif |
||||
endfor |
||||
endif |
||||
|
||||
call matchup#perf#toc('get_matching_delims', 'get_matches') |
||||
|
||||
" fill in additional groups |
||||
let l:mids = matchup#loader#remove_capture_groups(self.regexone.mid) |
||||
let l:mids = matchup#delim#fill_backrefs(l:mids, self.groups, 1) |
||||
|
||||
" if there are no mids, we're done |
||||
if empty(l:mids) |
||||
return [[l:match_corr, l:lnum_corr, l:cnum_corr]] |
||||
endif |
||||
|
||||
let l:re = l:mids |
||||
|
||||
" when highlighting, respect hlend |
||||
if get(self.regextwo.extra_info, 'mid_hlend') && self.highlighting |
||||
let l:re = s:process_hlend(l:re, -1) |
||||
endif |
||||
|
||||
" use b:match_ignorecase |
||||
let l:mid = l:ic . l:mids |
||||
let l:re = l:ic . l:re |
||||
|
||||
let l:list = [] |
||||
while 1 |
||||
if matchup#perf#timeout_check() | break | endif |
||||
|
||||
let [l:lnum, l:cnum] = searchpairpos(l:open, l:mids, l:close, |
||||
\ l:flags, l:skip, l:lnum_corr, matchup#perf#timeout()) |
||||
if l:lnum <= 0 | break | endif |
||||
|
||||
if a:down |
||||
if l:lnum > l:lnum_corr || l:lnum == l:lnum_corr |
||||
\ && l:cnum >= l:cnum_corr | break | endif |
||||
else |
||||
if l:lnum < l:lnum_corr || l:lnum == l:lnum_corr |
||||
\ && l:cnum <= l:cnum_corr | break | endif |
||||
endif |
||||
|
||||
let l:re_anchored = s:anchor_regex(l:re, l:cnum, l:has_zs) |
||||
let l:matches = matchlist(getline(l:lnum), l:re_anchored) |
||||
if empty(l:matches) |
||||
" this should never happen |
||||
continue |
||||
endif |
||||
let l:match = l:matches[0] |
||||
|
||||
call add(l:list, [l:match, l:lnum, l:cnum]) |
||||
endwhile |
||||
|
||||
" reset ignorecase (defunct) |
||||
|
||||
call add(l:list, [l:match_corr, l:lnum_corr, l:cnum_corr]) |
||||
|
||||
if !a:down |
||||
call reverse(l:list) |
||||
endif |
||||
|
||||
return l:list |
||||
endfunction |
||||
" }}}1 |
||||
|
||||
function! matchup#delim#skip(...) " {{{1 |
||||
if a:0 >= 2 |
||||
let [l:lnum, l:cnum] = [a:1, a:2] |
||||
else |
||||
let [l:lnum, l:cnum] = matchup#pos#get_cursor()[1:2] |
||||
endif |
||||
|
||||
if empty(get(b:, 'matchup_delim_skip', '')) |
||||
return matchup#util#in_comment_or_string(l:lnum, l:cnum) |
||||
\ ? !s:invert_skip : s:invert_skip |
||||
endif |
||||
|
||||
let s:eff_curpos = [l:lnum, l:cnum] |
||||
execute 'return' (s:invert_skip ? '!(' : '(') b:matchup_delim_skip ')' |
||||
endfunction |
||||
|
||||
function! matchup#delim#skip_default() |
||||
return matchup#util#in_comment_or_string(line('.'), col('.')) |
||||
\ ? !s:invert_skip : s:invert_skip |
||||
endfunction |
||||
|
||||
function! matchup#delim#skip0() |
||||
let s:eff_curpos = [line('.'), col('.')] |
||||
execute 'return' (s:invert_skip ? '!(' : '(') b:matchup_delim_skip ')' |
||||
endfunction |
||||
|
||||
"" |
||||
" advanced mid/syntax skip when found in midmap |
||||
" {val} is a 2 element array of allowed [syntax, words] |
||||
" {def} is the fallback skip expression |
||||
function! matchup#delim#skip1(val, def) |
||||
if getline('.')[col('.')-1:] =~# '^'.a:val[1] |
||||
return eval(a:def) |
||||
endif |
||||
let l:s = synIDattr(synID(line('.'),col('.'), 0), 'name') |
||||
return l:s !~# a:val[0] || eval(a:def) |
||||
endfunction |
||||
|
||||
"" |
||||
" advanced mid/syntax skip when word is not in midmap |
||||
" {strike} pattern of disallowed mid words |
||||
" {def} is the fallback skip expression |
||||
function! matchup#delim#skip2(strike, def) |
||||
return getline('.')[col('.')-1:] =~# '^' . a:strike || eval(a:def) |
||||
endfunction |
||||
|
||||
let s:invert_skip = 0 |
||||
let s:eff_curpos = [1, 1] |
||||
|
||||
" effective column/line |
||||
function! s:effline(expr) |
||||
return a:expr ==# '.' ? s:eff_curpos[0] : line(a:expr) |
||||
endfunction |
||||
|
||||
function! s:effcol(expr) |
||||
return a:expr ==# '.' ? s:eff_curpos[1] : col(a:expr) |
||||
endfunction |
||||
|
||||
function! s:geteffline(expr) |
||||
return a:expr ==# '.' ? getline(s:effline(a:expr)) : getline(a:expr) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#delim#fill_backrefs(re, groups, warn) " {{{1 |
||||
return substitute(a:re, g:matchup#re#backref, |
||||
\ '\=s:get_backref(a:groups, submatch(1), a:warn)', 'g') |
||||
" \ '\=get(a:groups, submatch(1), "")', 'g') |
||||
endfunction |
||||
|
||||
function! s:get_backref(groups, bref, warn) |
||||
if !has_key(a:groups, a:bref) |
||||
if a:warn |
||||
echohl WarningMsg |
||||
echo 'match-up: requested invalid backreference \'.a:bref |
||||
echohl None |
||||
endif |
||||
return '' |
||||
endif |
||||
return '\V'.escape(get(a:groups, a:bref), '\').'\m' |
||||
endfunction |
||||
|
||||
"}}}1 |
||||
|
||||
function! s:anchor_regex(re, cnum, method) " {{{1 |
||||
if a:method |
||||
" trick to re-match at a particular column |
||||
" handles the case where pattern contains \ze, \zs, and assertions |
||||
" but doesn't work with overlapping matches and is possibly slower |
||||
return '\%<'.(a:cnum+1).'c\%('.a:re.'\)\%>'.(a:cnum).'c' |
||||
else |
||||
" fails to match with \zs |
||||
return '\%'.(a:cnum).'c\%('.a:re.'\)' |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:process_hlend(re, cursorpos) " {{{1 |
||||
" first replace all \ze with \%>{cursorpos}c |
||||
let l:re = substitute(a:re, g:matchup#re#ze, |
||||
\ a:cursorpos < 0 ? '' : '\\%>'.a:cursorpos.'c', 'g') |
||||
" next convert hlend mark to \ze |
||||
return substitute(l:re, '\V\\%(hlend\\)\\{0}', '\\ze', 'g') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
" initialize script variables |
||||
let s:stopline = get(g:, 'matchup_delim_stopline', 1500) |
||||
|
||||
let s:basetypes = { |
||||
\ 'delim_tex': { |
||||
\ 'parser' : function('s:parser_delim_new'), |
||||
\ 'get_matching' : function('s:get_matching_delims'), |
||||
\ }, |
||||
\} |
||||
|
||||
let s:types = { |
||||
\ 'all' : [ s:basetypes.delim_tex ], |
||||
\ 'delim_all' : [ s:basetypes.delim_tex ], |
||||
\ 'delim_tex' : [ s:basetypes.delim_tex ], |
||||
\} |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,721 @@
@@ -0,0 +1,721 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#loader#init_module() abort " {{{1 |
||||
augroup matchup_filetype |
||||
au! |
||||
autocmd FileType * call matchup#loader#init_buffer() |
||||
if g:matchup_delim_start_plaintext |
||||
autocmd BufWinEnter,CmdWinEnter * call matchup#loader#bufwinenter() |
||||
endif |
||||
augroup END |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#loader#init_buffer() abort " {{{1 |
||||
call matchup#perf#tic('loader_init_buffer') |
||||
|
||||
" initialize lists of delimiter pairs and regular expressions |
||||
" this is the data obtained from parsing b:match_words |
||||
let b:matchup_delim_lists = s:init_delim_lists() |
||||
|
||||
" this is the combined set of regular expressions used for matching |
||||
" its structure is matchup_delim_re[type][open,close,both,mid,both_all] |
||||
let b:matchup_delim_re = s:init_delim_regexes() |
||||
|
||||
" process match_skip |
||||
let b:matchup_delim_skip = s:init_delim_skip() |
||||
|
||||
" enable/disable for this buffer |
||||
let b:matchup_delim_enabled = !empty(b:matchup_delim_lists.all.regex) |
||||
|
||||
call matchup#perf#toc('loader_init_buffer', 'done') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#loader#bufwinenter() abort " {{{1 |
||||
if get(b:, 'matchup_delim_enabled', 0) |
||||
return |
||||
endif |
||||
call matchup#loader#init_buffer() |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#loader#refresh_match_words() abort " {{{1 |
||||
if get(b:, 'match_words', ':') !~# ':' |
||||
call matchup#perf#tic('refresh') |
||||
|
||||
" protect the cursor from the match_words function |
||||
let l:save_pos = matchup#pos#get_cursor() |
||||
execute 'let l:match_words = ' b:match_words |
||||
if l:save_pos != matchup#pos#get_cursor() |
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
endif |
||||
|
||||
call matchup#perf#toc('refresh', 'function') |
||||
|
||||
if has_key(s:match_word_cache, l:match_words) |
||||
let b:matchup_delim_lists |
||||
\ = s:match_word_cache[l:match_words].delim_lists |
||||
let b:matchup_delim_re |
||||
\ = s:match_word_cache[l:match_words].delim_regexes |
||||
call matchup#perf#toc('refresh', 'cache_hit') |
||||
else |
||||
" re-parse match words |
||||
let b:matchup_delim_lists = s:init_delim_lists() |
||||
let b:matchup_delim_re = s:init_delim_regexes() |
||||
let s:match_word_cache[l:match_words] = { |
||||
\ 'delim_lists' : b:matchup_delim_lists, |
||||
\ 'delim_regexes': b:matchup_delim_re, |
||||
\} |
||||
call matchup#perf#toc('refresh', 'parse') |
||||
endif |
||||
endif |
||||
endfunction |
||||
|
||||
let s:match_word_cache = {} |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:init_delim_lists(...) abort " {{{1 |
||||
let l:lists = { |
||||
\ 'delim_tex': { |
||||
\ 'regex': [], |
||||
\ 'regex_capture': [], |
||||
\ 'midmap': {}, |
||||
\ }, |
||||
\} |
||||
|
||||
" very tricky examples: |
||||
" good: let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' |
||||
" bad: let b:match_words = '\(foo\)\(bar\):more\1:and\2:end\1\2' |
||||
|
||||
" *subtlety*: there is a huge assumption in matchit: |
||||
" ``It should be possible to resolve back references |
||||
" from any pattern in the group.'' |
||||
" we don't explicitly check this, but the behavior might |
||||
" be unpredictable if such groups are encountered.. (ref-1) |
||||
|
||||
if exists('g:matchup_hotfix') && has_key(g:matchup_hotfix, &filetype) |
||||
call call(g:matchup_hotfix[&filetype], []) |
||||
elseif exists('g:matchup_hotfix_'.&filetype) |
||||
call call(g:matchup_hotfix_{&filetype}, []) |
||||
elseif exists('b:matchup_hotfix') |
||||
call call(b:matchup_hotfix, []) |
||||
endif |
||||
|
||||
" parse matchpairs and b:match_words |
||||
let l:match_words = a:0 ? a:1 : get(b:, 'match_words', '') |
||||
if !empty(l:match_words) && l:match_words !~# ':' |
||||
if a:0 |
||||
echohl ErrorMsg |
||||
echo 'match-up: function b:match_words error' |
||||
echohl None |
||||
let l:match_words = '' |
||||
else |
||||
execute 'let l:match_words =' b:match_words |
||||
" echohl ErrorMsg |
||||
" echo 'match-up: function b:match_words not supported' |
||||
" echohl None |
||||
" let l:match_words = '' |
||||
endif |
||||
endif |
||||
let l:simple = empty(l:match_words) |
||||
|
||||
let l:mps = escape(&matchpairs, '[$^.*~\\/?]') |
||||
if !get(b:, 'matchup_delim_nomatchpairs', 0) && !empty(l:mps) |
||||
let l:match_words .= (l:simple ? '' : ',').l:mps |
||||
endif |
||||
|
||||
if l:simple |
||||
return s:init_delim_lists_fast(l:match_words) |
||||
endif |
||||
|
||||
let l:sets = split(l:match_words, g:matchup#re#not_bslash.',') |
||||
|
||||
" do not duplicate whole groups of match words |
||||
let l:seen = {} |
||||
for l:s in l:sets |
||||
" very special case, escape bare [:] |
||||
" TODO: the bare [] bug might show up in other places too |
||||
if l:s ==# '[:]' || l:s ==# '\[:\]' |
||||
let l:s = '\[:]' |
||||
endif |
||||
|
||||
if has_key(l:seen, l:s) | continue | endif |
||||
let l:seen[l:s] = 1 |
||||
|
||||
if l:s =~# '^\s*$' | continue | endif |
||||
|
||||
let l:words = split(l:s, g:matchup#re#not_bslash.':') |
||||
|
||||
if len(l:words) < 2 | continue | endif |
||||
|
||||
" stores series-level information |
||||
let l:extra_info = {} |
||||
|
||||
" stores information for each word |
||||
let l:extra_list = map(range(len(l:words)), '{}') |
||||
|
||||
" pre-process various \g{special} instructions |
||||
let l:replacement = { |
||||
\ 'hlend': '\%(hlend\)\{0}', |
||||
\ 'syn': '' |
||||
\} |
||||
for l:i in range(len(l:words)) |
||||
let l:special_flags = [] |
||||
let l:words[l:i] = substitute(l:words[l:i], |
||||
\ g:matchup#re#gspec, |
||||
\ '\=[get(l:replacement,submatch(1),""),' |
||||
\ . 'add(l:special_flags,' |
||||
\ . '[submatch(1),submatch(2)])][0]', 'g') |
||||
for [l:f, l:a] in l:special_flags |
||||
let l:extra_list[l:i][l:f] = len(l:a) ? l:a : 1 |
||||
endfor |
||||
endfor |
||||
|
||||
" we will resolve backrefs to produce two sets of words, |
||||
" one with \(foo\)s and one with \1s, along with a set of |
||||
" bookkeeping structures |
||||
let l:words_backref = copy(l:words) |
||||
|
||||
" *subtlety*: backref numbers refer to the capture groups |
||||
" in the 'open' pattern so we have to carefully keep track |
||||
" of the group renumbering |
||||
let l:group_renumber = {} |
||||
let l:augment_comp = {} |
||||
let l:all_needed_groups = {} |
||||
|
||||
" *subtlety*: when replacing things like \1 with \(...\) |
||||
" the insertion could possibly contain back references of |
||||
" its own; this poses a very difficult bookkeeping problem, |
||||
" so we just disallow it.. (ref-2) |
||||
|
||||
" get the groups like \(foo\) in the 'open' pattern |
||||
let l:cg = matchup#loader#get_capture_groups(l:words[0]) |
||||
|
||||
" if any of these contain \d raise a warning |
||||
" and substitute it out (ref-2) |
||||
for l:cg_i in keys(l:cg) |
||||
if l:cg[l:cg_i].str =~# g:matchup#re#backref |
||||
echohl WarningMsg |
||||
echom 'match-up: capture group' l:cg[l:cg_i].str |
||||
\ 'should not contain backrefs (ref-2)' |
||||
echohl None |
||||
let l:cg[l:cg_i].str = substitute(l:cg[l:cg_i].str, |
||||
\ g:matchup#re#backref, '', 'g') |
||||
endif |
||||
endfor |
||||
|
||||
" for the 'open' pattern, create a series of replacements |
||||
" of the capture groups with \9, \8, ..., \1 |
||||
" this must be done deepest to shallowest |
||||
let l:augments = {} |
||||
let l:order = matchup#loader#capture_group_replacement_order(l:cg) |
||||
|
||||
let l:curaug = l:words[0] |
||||
" TODO: \0 should match the whole pattern.. |
||||
" augments[0] is the original words[0] with original capture groups |
||||
let l:augments[0] = l:curaug " XXX does putting this in 0 make sense? |
||||
for l:j in l:order |
||||
" these indexes are not invalid because we work backwards |
||||
let l:curaug = strpart(l:curaug, 0, l:cg[l:j].pos[0]) |
||||
\ .('\'.l:j).strpart(l:curaug, l:cg[l:j].pos[1]) |
||||
let l:augments[l:j] = l:curaug |
||||
endfor |
||||
|
||||
" TODO this logic might be bad BADLOGIC |
||||
" should we not fill groups that aren't needed? |
||||
" dragons: create the augmentation operators from the |
||||
" open pattern- this is all super tricky!! |
||||
" TODO we should be building the augment later, so |
||||
" we can remove augments that can never be filled |
||||
|
||||
" now for the rest of the words... |
||||
for l:i in range(1, len(l:words)-1) |
||||
|
||||
" first get rid of the capture groups in this pattern |
||||
let l:words_backref[l:i] = matchup#loader#remove_capture_groups( |
||||
\ l:words_backref[l:i]) |
||||
|
||||
" get the necessary \1, \2, etc back-references |
||||
let l:needed_groups = [] |
||||
call substitute(l:words_backref[l:i], g:matchup#re#backref, |
||||
\ '\=len(add(l:needed_groups, submatch(1)))', 'g') |
||||
call filter(l:needed_groups, |
||||
\ 'index(l:needed_groups, v:val) == v:key') |
||||
|
||||
" warn if the back-referenced groups don't actually exist |
||||
for l:ng in l:needed_groups |
||||
if has_key(l:cg, l:ng) |
||||
let l:all_needed_groups[l:ng] = 1 |
||||
else |
||||
echohl WarningMsg |
||||
echom 'match-up: backref \' . l:ng 'requested but no ' |
||||
\ . 'matching capture group provided' |
||||
echohl None |
||||
endif |
||||
endfor |
||||
|
||||
" substitute capture groups into the backrefs and keep |
||||
" track of the mapping to the original backref number |
||||
let l:group_renumber[l:i] = {} |
||||
|
||||
let l:cg2 = {} |
||||
for l:bref in l:needed_groups |
||||
|
||||
" turn things like \1 into \(...\) |
||||
" replacement is guaranteed to exist and not contain \d |
||||
let l:words_backref[l:i] = substitute(l:words_backref[l:i], |
||||
\ g:matchup#re#backref, |
||||
\ '\='''.l:cg[l:bref].str."'", '') " not global!! |
||||
|
||||
" complicated: need to count the number of inserted groups |
||||
let l:prev_max = max(keys(l:cg2)) |
||||
let l:cg2 = matchup#loader#get_capture_groups(l:words_backref[l:i]) |
||||
|
||||
for l:cg2_i in sort(keys(l:cg2), s:Nsort) |
||||
if l:cg2_i > l:prev_max |
||||
" maps capture groups to 'open' back reference numbers |
||||
let l:group_renumber[l:i][l:cg2_i] = l:bref |
||||
\ + (l:cg2_i - 1 - l:prev_max) |
||||
endif |
||||
endfor |
||||
|
||||
" if any backrefs remain, replace with re-numbered versions |
||||
let l:words_backref[l:i] = substitute(l:words_backref[l:i], |
||||
\ g:matchup#re#not_bslash.'\\'.l:bref, |
||||
\ '\\\=l:group_renumber[l:i][submatch(1)]', 'g') |
||||
endfor |
||||
|
||||
" mostly a sanity check |
||||
if matchup#util#has_duplicate_str(values(l:group_renumber[l:i])) |
||||
echohl ErrorMsg |
||||
echom 'match-up: duplicate bref in set ' l:s ':' l:i |
||||
echohl None |
||||
endif |
||||
|
||||
" compile the augment list for this set of backrefs, going |
||||
" deepest first and combining as many steps as possible |
||||
let l:resolvable = {} |
||||
let l:dependency = {} |
||||
|
||||
let l:instruct = [] |
||||
for l:j in l:order |
||||
" the in group is the local number from this word pattern |
||||
let l:in_grp_l = keys(filter( |
||||
\ deepcopy(l:group_renumber[l:i]), 'v:val == l:j')) |
||||
|
||||
if empty(l:in_grp_l) | continue | endif |
||||
let l:in_grp = l:in_grp_l[0] |
||||
|
||||
" if anything depends on this, flush out the current resolvable |
||||
if has_key(l:dependency, l:j) |
||||
call add(l:instruct, copy(l:resolvable)) |
||||
let l:dependency = {} |
||||
endif |
||||
|
||||
" walk up the tree marking any new dependency |
||||
let l:node = l:j |
||||
for l:dummy in range(11) |
||||
let l:node = l:cg[l:node].parent |
||||
if l:node == 0 | break | endif |
||||
let l:dependency[l:node] = 1 |
||||
endfor |
||||
|
||||
" mark l:j as resolvable |
||||
let l:resolvable[l:j] = l:in_grp |
||||
endfor |
||||
|
||||
if !empty(l:resolvable) |
||||
call add(l:instruct, copy(l:resolvable)) |
||||
endif |
||||
|
||||
" *note*: recall that l:augments[2] is the result of augments |
||||
" up to and including 2 |
||||
|
||||
" this is a set of instructions of which brefs to resolve |
||||
let l:augment_comp[l:i] = [] |
||||
for l:instr in l:instruct |
||||
" the smallest key is the greediest, due to l:order |
||||
let l:minkey = min(keys(l:instr)) |
||||
call insert(l:augment_comp[l:i], { |
||||
\ 'inputmap': {}, |
||||
\ 'outputmap': {}, |
||||
\ 'str': l:augments[l:minkey], |
||||
\}) |
||||
|
||||
let l:remaining_out = {} |
||||
for l:out_grp in keys(l:cg) |
||||
let l:remaining_out[l:out_grp] = 1 |
||||
endfor |
||||
|
||||
" input map turns this word pattern numbers into 'open' numbers |
||||
for [l:out_grp, l:in_grp] in items(l:instr) |
||||
let l:augment_comp[l:i][0].inputmap[l:in_grp] = l:out_grp |
||||
if has_key(l:remaining_out, l:out_grp) |
||||
call remove(l:remaining_out, l:out_grp) |
||||
endif |
||||
endfor |
||||
|
||||
" output map turns remaining group numbers into 'open' numbers |
||||
let l:counter = 1 |
||||
for l:out_grp in sort(keys(l:remaining_out), s:Nsort) |
||||
let l:augment_comp[l:i][0].outputmap[l:counter] = l:out_grp |
||||
let l:counter += 1 |
||||
endfor |
||||
endfor |
||||
|
||||
" if l:instruct was empty, there are no constraints |
||||
if empty(l:instruct) && !empty(l:augments) |
||||
let l:augment_comp[l:i] = [{ |
||||
\ 'inputmap': {}, |
||||
\ 'outputmap': {}, |
||||
\ 'str': l:augments[0], |
||||
\}] |
||||
for l:cg_i in keys(l:cg) |
||||
let l:augment_comp[l:i][0].outputmap[l:cg_i] = l:cg_i |
||||
endfor |
||||
endif |
||||
endfor |
||||
|
||||
" strip out unneeded groups in output maps |
||||
for l:i in keys(l:augment_comp) |
||||
for l:aug in l:augment_comp[l:i] |
||||
call filter(l:aug.outputmap, |
||||
\ 'has_key(l:all_needed_groups, v:key)') |
||||
endfor |
||||
endfor |
||||
|
||||
" TODO should l:words[0] actually be used? BADLOGIC |
||||
" the last element in the order gives the most augmented string |
||||
" this includes groups that might not actually be needed elsewhere |
||||
" as a concrete example, |
||||
" l:augments = { '0': '\<\(wh\%[ile]\|for\)\>', '1': '\<\1\>'} |
||||
" l:words[0] = \<\1\> (bad) |
||||
" instead, get the furthest out needed augment.. Heuristic TODO |
||||
for l:g in add(reverse(copy(l:order)), 0) |
||||
if has_key(l:all_needed_groups, l:g) |
||||
let l:words[0] = l:augments[l:g] |
||||
break |
||||
endif |
||||
endfor |
||||
|
||||
" check whether any of these patterns has \zs |
||||
let l:extra_info.has_zs |
||||
\ = match(l:words_backref, g:matchup#re#zs) >= 0 |
||||
|
||||
if !empty(filter(copy(l:extra_list[1:-2]), |
||||
\ 'get(v:val, "hlend")')) |
||||
let l:extra_info.mid_hlend = 1 |
||||
endif |
||||
|
||||
" this is the original set of words plus the set of augments |
||||
" TODO this should probably be renamed |
||||
" (also called regexone) |
||||
call add(l:lists.delim_tex.regex, { |
||||
\ 'open' : l:words[0], |
||||
\ 'close' : l:words[-1], |
||||
\ 'mid' : join(l:words[1:-2], '\|'), |
||||
\ 'mid_list' : l:words[1:-2], |
||||
\ 'augments' : l:augments, |
||||
\}) |
||||
|
||||
" this list has \(groups\) and we also stuff recapture data |
||||
" TODO this should probably be renamed |
||||
" (also called regextwo) |
||||
call add(l:lists.delim_tex.regex_capture, { |
||||
\ 'open' : l:words_backref[0], |
||||
\ 'close' : l:words_backref[-1], |
||||
\ 'mid' : join(l:words_backref[1:-2], '\|'), |
||||
\ 'mid_list' : l:words_backref[1:-2], |
||||
\ 'need_grp' : l:all_needed_groups, |
||||
\ 'grp_renu' : l:group_renumber, |
||||
\ 'aug_comp' : l:augment_comp, |
||||
\ 'extra_list' : l:extra_list, |
||||
\ 'extra_info' : l:extra_info, |
||||
\}) |
||||
endfor |
||||
|
||||
" load info for advanced mid-mapper |
||||
if exists('b:match_midmap') && type(b:match_midmap) == type([]) |
||||
let l:elems = deepcopy(b:match_midmap) |
||||
let l:lists.delim_tex.midmap = { |
||||
\ 'elements': l:elems, |
||||
\ 'strike': '\%(' . join(map(range(len(l:elems)), |
||||
\ '"\\(".l:elems[v:val][1]."\\)"'), '\|') . '\)' |
||||
\} |
||||
endif |
||||
|
||||
" generate combined lists |
||||
let l:lists.delim_all = {} |
||||
let l:lists.all = {} |
||||
for l:k in ['regex', 'regex_capture', 'midmap'] |
||||
let l:lists.delim_all[l:k] = l:lists.delim_tex[l:k] |
||||
let l:lists.all[l:k] = l:lists.delim_all[l:k] |
||||
endfor |
||||
|
||||
return l:lists |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:init_delim_lists_fast(mps) abort " {{{1 |
||||
let l:lists = { 'delim_tex': { 'regex': [], 'regex_capture': [] } } |
||||
|
||||
let l:sets = split(a:mps, ',') |
||||
let l:seen = {} |
||||
|
||||
for l:s in l:sets |
||||
if l:s =~# '^\s*$' | continue | endif |
||||
|
||||
if l:s ==# '[:]' || l:s ==# '\[:\]' |
||||
let l:s = '\[:]' |
||||
endif |
||||
|
||||
if has_key(l:seen, l:s) | continue | endif |
||||
let l:seen[l:s] = 1 |
||||
|
||||
let l:words = split(l:s, ':') |
||||
if len(l:words) < 2 | continue | endif |
||||
|
||||
call add(l:lists.delim_tex.regex, { |
||||
\ 'open' : l:words[0], |
||||
\ 'close' : l:words[-1], |
||||
\ 'mid' : '', |
||||
\ 'mid_list' : [], |
||||
\ 'augments' : {}, |
||||
\}) |
||||
call add(l:lists.delim_tex.regex_capture, { |
||||
\ 'open' : l:words[0], |
||||
\ 'close' : l:words[-1], |
||||
\ 'mid' : '', |
||||
\ 'mid_list' : [], |
||||
\ 'need_grp' : {}, |
||||
\ 'grp_renu' : {}, |
||||
\ 'aug_comp' : {}, |
||||
\ 'has_zs' : 0, |
||||
\ 'extra_list' : [{}, {}], |
||||
\ 'extra_info' : { 'has_zs': 0, }, |
||||
\}) |
||||
endfor |
||||
|
||||
" TODO if this is empty! |
||||
|
||||
" generate combined lists |
||||
let l:lists.delim_all = {} |
||||
let l:lists.all = {} |
||||
for l:k in ['regex', 'regex_capture'] |
||||
let l:lists.delim_all[l:k] = l:lists.delim_tex[l:k] |
||||
let l:lists.all[l:k] = l:lists.delim_all[l:k] |
||||
endfor |
||||
|
||||
return l:lists |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:init_delim_regexes() abort " {{{1 |
||||
let l:re = {} |
||||
let l:re.delim_all = {} |
||||
let l:re.all = {} |
||||
|
||||
let l:re.delim_tex = s:init_delim_regexes_generator('delim_tex') |
||||
let l:re.delim_tex._engine_info = { 'has_zs': {} } |
||||
|
||||
" use a flag for b:match_ignorecase |
||||
let l:ic = get(b:, 'match_ignorecase', 0) ? '\c' : '\C' |
||||
|
||||
" if a particular engine is specified, use that for the patterns |
||||
" (currently only applied to delim_re TODO) |
||||
let l:eng = string(get(b:, 'matchup_regexpengine', 0)) |
||||
let l:eng = l:eng > 0 ? '\%#='.l:eng : '' |
||||
|
||||
for l:k in keys(s:sidedict) |
||||
let l:re.delim_tex._engine_info.has_zs[l:k] |
||||
\ = l:re.delim_tex[l:k] =~# g:matchup#re#zs |
||||
|
||||
if l:re.delim_tex[l:k] ==# '\%(\)' |
||||
let l:re.delim_tex[l:k] = '' |
||||
else |
||||
" since these patterns are used in searchpos(), |
||||
" be explicit about regex mode (set magic mode and ignorecase) |
||||
let l:re.delim_tex[l:k] = l:eng . '\m' . l:ic . l:re.delim_tex[l:k] |
||||
endif |
||||
|
||||
let l:re.delim_all[l:k] = l:re.delim_tex[l:k] |
||||
let l:re.all[l:k] = l:re.delim_all[l:k] |
||||
endfor |
||||
|
||||
let l:re.delim_all._engine_info = l:re.delim_tex._engine_info |
||||
let l:re.all._engine_info = l:re.delim_all._engine_info |
||||
|
||||
return l:re |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:init_delim_regexes_generator(list_name) abort " {{{1 |
||||
let l:list = b:matchup_delim_lists[a:list_name].regex_capture |
||||
|
||||
" build the full regex strings: order matters here |
||||
let l:regexes = {} |
||||
for [l:key, l:sidelist] in items(s:sidedict) |
||||
let l:relist = [] |
||||
|
||||
for l:set in l:list |
||||
for l:side in l:sidelist |
||||
if strlen(l:set[l:side]) |
||||
call add(l:relist, l:set[l:side]) |
||||
endif |
||||
endfor |
||||
endfor |
||||
|
||||
let l:regexes[l:key] = matchup#loader#remove_capture_groups( |
||||
\ '\%(' . join(l:relist, '\|') . '\)') |
||||
endfor |
||||
|
||||
return l:regexes |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#loader#capture_group_replacement_order(cg) abort " {{{1 |
||||
let l:order = reverse(sort(keys(a:cg), s:Nsort)) |
||||
call sort(l:order, 's:capture_group_sort', a:cg) |
||||
return l:order |
||||
endfunction |
||||
|
||||
function! s:capture_group_sort(a, b) abort dict |
||||
return self[a:b].depth - self[a:a].depth |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#loader#get_capture_groups(str, ...) abort " {{{1 |
||||
let l:allow_percent = a:0 ? a:1 : 0 |
||||
let l:pat = g:matchup#re#not_bslash . '\(\\%(\|\\(\|\\)\)' |
||||
|
||||
let l:start = 0 |
||||
|
||||
let l:brefs = {} |
||||
let l:stack = [] |
||||
let l:counter = 0 |
||||
while 1 |
||||
let l:match = s:matchstrpos(a:str, l:pat, l:start) |
||||
if l:match[1] < 0 | break | endif |
||||
let l:start = l:match[2] |
||||
|
||||
if l:match[0] ==# '\(' || (l:match[0] ==# '\%(' && l:allow_percent) |
||||
let l:counter += 1 |
||||
call add(l:stack, l:counter) |
||||
let l:cgstack = filter(copy(l:stack), 'v:val > 0') |
||||
let l:brefs[l:counter] = { |
||||
\ 'str': '', |
||||
\ 'depth': len(l:cgstack), |
||||
\ 'parent': (len(l:cgstack) > 1 ? l:cgstack[-2] : 0), |
||||
\ 'pos': [l:match[1], 0], |
||||
\} |
||||
elseif l:match[0] ==# '\%(' |
||||
call add(l:stack, 0) |
||||
else |
||||
if empty(l:stack) | break | endif |
||||
let l:i = remove(l:stack, -1) |
||||
if l:i < 1 | continue | endif |
||||
let l:j = l:brefs[l:i].pos[0] |
||||
let l:brefs[l:i].str = strpart(a:str, l:j, l:match[2]-l:j) |
||||
let l:brefs[l:i].pos[1] = l:match[2] |
||||
endif |
||||
endwhile |
||||
|
||||
call filter(l:brefs, 'has_key(v:val, "str")') |
||||
|
||||
return l:brefs |
||||
endfunction |
||||
|
||||
" compatibility |
||||
if exists('*matchstrpos') |
||||
function! s:matchstrpos(expr, pat, start) abort |
||||
return matchstrpos(a:expr, a:pat, a:start) |
||||
endfunction |
||||
else |
||||
function! s:matchstrpos(expr, pat, start) abort |
||||
return [matchstr(a:expr, a:pat, a:start), |
||||
\ match(a:expr, a:pat, a:start), |
||||
\ matchend(a:expr, a:pat, a:start)] |
||||
endfunction |
||||
endif |
||||
|
||||
" }}}1 |
||||
function! matchup#loader#remove_capture_groups(re) abort "{{{1 |
||||
let l:sub_grp = '\(\\\@<!\(\\\\\)*\)\@<=\\(' |
||||
return substitute(a:re, l:sub_grp, '\\%(', 'g') |
||||
endfunction |
||||
|
||||
"}}}1 |
||||
|
||||
function! s:init_delim_skip() abort "{{{1 |
||||
let l:skip = get(b:, 'match_skip', '') |
||||
if empty(l:skip) | return '' | endif |
||||
|
||||
" s:foo becomes (current syntax item) =~ foo |
||||
" S:foo becomes (current syntax item) !~ foo |
||||
" r:foo becomes (line before cursor) =~ foo |
||||
" R:foo becomes (line before cursor) !~ foo |
||||
let l:cursyn = "synIDattr(synID(s:effline('.'),s:effcol('.'),1),'name')" |
||||
let l:preline = "strpart(s:geteffline('.'),0,s:effcol('.'))" |
||||
|
||||
if l:skip =~# '^[sSrR]:' |
||||
let l:syn = strpart(l:skip, 2) |
||||
|
||||
let l:skip = { |
||||
\ 's': l:cursyn."=~?'".l:syn."'", |
||||
\ 'S': l:cursyn."!~?'".l:syn."'", |
||||
\ 'r': l:preline."=~?'".l:syn."'", |
||||
\ 'R': l:preline."!~?'".l:syn."'", |
||||
\}[l:skip[0]] |
||||
endif |
||||
|
||||
for [l:pat, l:str] in [ |
||||
\ [ '\<col\ze(', 's:effcol' ], |
||||
\ [ '\<line\ze(', 's:effline' ], |
||||
\ [ '\<getline\ze(', 's:geteffline' ], |
||||
\] |
||||
let l:skip = substitute(l:skip, l:pat, l:str, 'g') |
||||
endfor |
||||
|
||||
return l:skip |
||||
endfunction |
||||
|
||||
"}}}1 |
||||
|
||||
function! s:Nsort_func(a, b) abort " {{{1 |
||||
let l:a = type(a:a) == type('') ? str2nr(a:a) : a:a |
||||
let l:b = type(a:b) == type('') ? str2nr(a:b) : a:b |
||||
return l:a == l:b ? 0 : l:a > l:b ? 1 : -1 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let s:sidedict = { |
||||
\ 'open' : ['open'], |
||||
\ 'mid' : ['mid'], |
||||
\ 'close' : ['close'], |
||||
\ 'both' : ['close', 'open'], |
||||
\ 'both_all' : ['close', 'mid', 'open'], |
||||
\ 'open_mid' : ['mid', 'open'], |
||||
\} |
||||
|
||||
function! matchup#loader#sidedict() abort |
||||
return s:sidedict |
||||
endfunction |
||||
|
||||
" in case the 'N' sort flag is not available (compatibility for 7.4.898) |
||||
let s:Nsort = has('patch-7.4.951') ? 'N' : 's:Nsort_func' |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,953 @@
@@ -0,0 +1,953 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
scriptencoding utf-8 |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#matchparen#init_module() " {{{1 |
||||
if !g:matchup_matchparen_enabled | return | endif |
||||
|
||||
call matchup#matchparen#enable() |
||||
|
||||
nnoremap <silent> <plug>(matchup-hi-surround) |
||||
\ :<c-u>call matchup#matchparen#highlight_surrounding()<cr> |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#matchparen#enable() " {{{1 |
||||
let g:matchup_matchparen_enabled = 1 |
||||
|
||||
if g:matchup_matchparen_deferred |
||||
\ && (!has('timers') || !exists('*timer_pause') |
||||
\ || has('nvim') && !has('nvim-0.2.1')) |
||||
let g:matchup_matchparen_deferred = 0 |
||||
echohl WarningMsg |
||||
echom "match-up's deferred highlighting feature is " |
||||
\ . 'not supported in your vim version' |
||||
echohl None |
||||
endif |
||||
|
||||
augroup matchup_matchparen |
||||
autocmd! |
||||
autocmd CursorMoved,CursorMovedI * |
||||
\ call s:matchparen.highlight_deferred() |
||||
autocmd WinEnter * call s:matchparen.highlight(1) |
||||
autocmd TextChanged,TextChangedI * |
||||
\ call s:matchparen.highlight_deferred() |
||||
if has('patch-8.0.1494') |
||||
autocmd TextChangedP * call s:matchparen.highlight_deferred() |
||||
endif |
||||
autocmd BufReadPost * call s:matchparen.transmute_reset() |
||||
autocmd WinLeave,BufLeave * call s:matchparen.clear() |
||||
autocmd InsertEnter,InsertChange * call s:matchparen.highlight(1, 1) |
||||
autocmd InsertLeave * call s:matchparen.highlight(1) |
||||
augroup END |
||||
|
||||
call s:ensure_match_popup() |
||||
|
||||
if has('vim_starting') |
||||
" prevent this from autoloading during timer callback at startup |
||||
if g:matchup_matchparen_deferred |
||||
call matchup#pos#val(0,0) |
||||
endif |
||||
|
||||
" prevent loading the delim module at vim startup |
||||
let w:last_changedtick = 2 |
||||
let w:last_cursor = [0,1,1,0,1] |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:pi_paren_sid() " {{{1 |
||||
if s:pi_paren_sid >= 0 |
||||
return s:pi_paren_sid |
||||
endif |
||||
|
||||
let s:pi_paren_sid = 0 |
||||
if get(g:, 'loaded_matchparen') |
||||
let l:pat = '\%#=1\V'.expand('$VIM').'\m.\+matchparen\.vim$' |
||||
if v:version >= 800 |
||||
" execute() was added in 7.4.2008 |
||||
" :filter was introduced in 7.4.2244 but I have not tested it there |
||||
let l:lines = split(execute("filter '".l:pat."' scriptnames"), '\n') |
||||
else |
||||
let l:lines = matchup#util#command('scriptnames') |
||||
call filter(l:lines, 'v:val =~# l:pat') |
||||
endif |
||||
let s:pi_paren_sid = matchstr(get(l:lines, 0), '\d\+\ze: ') |
||||
if !exists('*<SNR>'.s:pi_paren_sid.'_Highlight_Matching_Pair') |
||||
let s:pi_paren_sid = 0 |
||||
endif |
||||
endif |
||||
if s:pi_paren_sid |
||||
let s:pi_paren_fcn = function('<SNR>'.s:pi_paren_sid |
||||
\ .'_Highlight_Matching_Pair') |
||||
endif |
||||
return s:pi_paren_sid |
||||
endfunction |
||||
|
||||
let s:pi_paren_sid = -1 |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#matchparen#disable() " {{{1 |
||||
let g:matchup_matchparen_enabled = 0 |
||||
call s:matchparen.clear() |
||||
silent! autocmd! matchup_matchparen |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#matchparen#toggle(...) " {{{1 |
||||
let g:matchup_matchparen_enabled = a:0 > 0 |
||||
\ ? a:1 |
||||
\ : !g:matchup_matchparen_enabled |
||||
call matchup#matchparen#reload() |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#matchparen#reload() " {{{1 |
||||
if g:matchup_matchparen_enabled |
||||
call matchup#matchparen#enable() |
||||
call s:matchparen.highlight(1) |
||||
else |
||||
call matchup#matchparen#disable() |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#matchparen#update() " {{{1 |
||||
call s:matchparen.highlight(1) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let s:matchparen = {} |
||||
|
||||
function! s:matchparen.clear() abort dict " {{{1 |
||||
if exists('w:matchup_match_id_list') |
||||
for l:id in w:matchup_match_id_list |
||||
silent! call matchdelete(l:id) |
||||
endfor |
||||
unlet! w:matchup_match_id_list |
||||
endif |
||||
|
||||
if exists('t:match_popup') |
||||
call popup_hide(t:match_popup) |
||||
elseif has('nvim') |
||||
call s:close_floating_win() |
||||
endif |
||||
|
||||
if exists('w:matchup_oldstatus') |
||||
let &l:statusline = w:matchup_oldstatus |
||||
unlet w:matchup_oldstatus |
||||
if exists('#User#MatchupOffscreenLeave') |
||||
doautocmd <nomodeline> User MatchupOffscreenLeave |
||||
endif |
||||
endif |
||||
if exists('w:matchup_statusline') |
||||
unlet w:matchup_statusline |
||||
endif |
||||
|
||||
let w:matchup_need_clear = 0 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:timer_callback(win_id, timer_id) abort " {{{1 |
||||
if a:win_id != win_getid() |
||||
call timer_pause(a:timer_id, 1) |
||||
return |
||||
endif |
||||
|
||||
" if we timed out, do a highlight and pause the timer |
||||
let l:elapsed = 1000*s:reltimefloat(reltime(w:matchup_pulse_time)) |
||||
if l:elapsed >= s:show_delay |
||||
call timer_pause(a:timer_id, 1) |
||||
if exists('#TextYankPost') && !has('patch-8.1.0192') |
||||
" workaround crash with autocmd trigger during regex match (#3175) |
||||
let l:save_ei = &eventignore |
||||
try |
||||
set eventignore+=TextYankPost |
||||
call s:matchparen.highlight() |
||||
finally |
||||
let &eventignore = l:save_ei |
||||
endtry |
||||
else |
||||
call s:matchparen.highlight() |
||||
endif |
||||
elseif w:matchup_need_clear && exists('w:matchup_hi_time') |
||||
" if highlighting becomes too stale, clear it |
||||
let l:elapsed = 1000*s:reltimefloat(reltime(w:matchup_hi_time)) |
||||
if l:elapsed >= s:hide_delay |
||||
call s:matchparen.clear() |
||||
endif |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:matchparen.fade(level, pos, token) abort dict " {{{1 |
||||
"" |
||||
" fade feature: remove highlights after a certain time |
||||
" {level} |
||||
" = 0: prepare for possible loss of cursor support |
||||
" = 1: new highlights are coming (cancel prior fade) |
||||
" = 2: end of new highlights |
||||
" {pos} [lnum, column] of current match |
||||
" {token} in/out saves state between calls |
||||
" |
||||
" returns 1 if highlighting should be canceled |
||||
|
||||
if !g:matchup_matchparen_deferred || !exists('w:matchup_fade_timer') |
||||
if a:level <= 0 |
||||
call s:matchparen.clear() |
||||
endif |
||||
return 0 |
||||
endif |
||||
|
||||
" jumping between windows |
||||
if a:level == 0 && win_getid() != get(s:, 'save_win') |
||||
call timer_pause(w:matchup_fade_timer, 1) |
||||
if exists('w:matchup_fade_pos') |
||||
unlet w:matchup_fade_pos |
||||
endif |
||||
call s:matchparen.clear() |
||||
let s:save_win = win_getid() |
||||
endif |
||||
|
||||
" highlighting might be stale |
||||
if a:level == 0 |
||||
if exists('w:matchup_fade_pos') |
||||
let a:token.save_pos = w:matchup_fade_pos |
||||
unlet w:matchup_fade_pos |
||||
endif |
||||
if !w:matchup_need_clear |
||||
call timer_pause(w:matchup_fade_timer, 1) |
||||
endif |
||||
return 0 |
||||
endif |
||||
|
||||
" prepare for new highlighting |
||||
if a:level == 1 |
||||
" if token has no save_pos, cursor was previously off of a match |
||||
if !has_key(a:token, 'save_pos') || a:pos != a:token.save_pos |
||||
" clear immediately |
||||
call timer_pause(w:matchup_fade_timer, 1) |
||||
call s:matchparen.clear() |
||||
return 0 |
||||
endif |
||||
let w:matchup_fade_pos = a:token.save_pos |
||||
return 1 |
||||
endif |
||||
|
||||
" new highlighting is active |
||||
if a:level == 2 && a:pos != get(w:, 'matchup_fade_pos', []) |
||||
" init fade request |
||||
let w:matchup_fade_pos = a:pos |
||||
let w:matchup_fade_start = reltime() |
||||
call timer_pause(w:matchup_fade_timer, 0) |
||||
endif |
||||
|
||||
return 0 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:fade_timer_callback(win_id, timer_id) abort " {{{1 |
||||
if a:win_id != win_getid() |
||||
call timer_pause(a:timer_id, 1) |
||||
return |
||||
endif |
||||
|
||||
if !exists('w:matchup_fade_start') || !w:matchup_need_clear |
||||
call timer_pause(a:timer_id, 1) |
||||
return |
||||
endif |
||||
|
||||
let l:elapsed = 1000*s:reltimefloat(reltime(w:matchup_fade_start)) |
||||
if l:elapsed >= s:fade_time |
||||
call s:matchparen.clear() |
||||
call timer_pause(a:timer_id, 1) |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
" function! s:reltimefloat(time) {{{1 |
||||
if exists('*reltimefloat') |
||||
function! s:reltimefloat(time) |
||||
return reltimefloat(a:time) |
||||
endfunction |
||||
else |
||||
function! s:reltimefloat(time) |
||||
return str2float(reltimestr(a:time)) |
||||
endfunction |
||||
endif |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:matchparen.highlight_deferred() abort dict " {{{1 |
||||
if !get(b:, 'matchup_matchparen_deferred', |
||||
\ g:matchup_matchparen_deferred) |
||||
return s:matchparen.highlight() |
||||
endif |
||||
|
||||
if !exists('w:matchup_timer') |
||||
let s:show_delay = g:matchup_matchparen_deferred_show_delay |
||||
let s:hide_delay = g:matchup_matchparen_deferred_hide_delay |
||||
let w:matchup_timer = timer_start(s:show_delay, |
||||
\ function('s:timer_callback', [ win_getid() ]), |
||||
\ {'repeat': -1}) |
||||
if !exists('w:matchup_need_clear') |
||||
let w:matchup_need_clear = 0 |
||||
endif |
||||
let s:fade_time = g:matchup_matchparen_deferred_fade_time |
||||
if s:fade_time > 0 |
||||
let w:matchup_fade_timer = timer_start(s:fade_time, |
||||
\ function('s:fade_timer_callback', [ win_getid() ]), |
||||
\ {'repeat': -1}) |
||||
call timer_pause(w:matchup_fade_timer, 1) |
||||
endif |
||||
endif |
||||
|
||||
" keep the timer alive with a heartbeat |
||||
let w:matchup_pulse_time = reltime() |
||||
|
||||
" if the timer is paused, some time has passed |
||||
if timer_info(w:matchup_timer)[0].paused |
||||
" unpause the timer |
||||
call timer_pause(w:matchup_timer, 0) |
||||
|
||||
" set the hi time to the pulse time |
||||
let w:matchup_hi_time = w:matchup_pulse_time |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:matchparen.highlight(...) abort dict " {{{1 |
||||
if !g:matchup_matchparen_enabled | return | endif |
||||
|
||||
if has('vim_starting') | return | endif |
||||
|
||||
if !g:matchup_matchparen_pumvisible && pumvisible() | return | endif |
||||
|
||||
if !get(b:, 'matchup_matchparen_enabled', 1) |
||||
\ && get(b:, 'matchup_matchparen_fallback', 1) && s:pi_paren_sid() |
||||
return call(s:pi_paren_fcn, []) |
||||
endif |
||||
|
||||
if !get(b:, 'matchup_matchparen_enabled', 1) | return | endif |
||||
|
||||
let l:force_update = a:0 >= 1 ? a:1 : 0 |
||||
let l:changing_insert = a:0 >= 2 ? a:2 : 0 |
||||
let l:real_mode = l:changing_insert ? v:insertmode : mode() |
||||
|
||||
if !l:force_update |
||||
\ && exists('w:last_changedtick') && exists('w:last_cursor') |
||||
\ && matchup#pos#equal(w:last_cursor, matchup#pos#get_cursor()) |
||||
\ && w:last_changedtick == b:changedtick |
||||
return |
||||
endif |
||||
let w:last_changedtick = b:changedtick |
||||
let w:last_cursor = matchup#pos#get_cursor() |
||||
|
||||
call matchup#perf#tic('matchparen.highlight') |
||||
|
||||
" request eventual clearing of stale matches |
||||
let l:token = {} |
||||
call self.fade(0, [], l:token) |
||||
|
||||
let l:modes = g:matchup_matchparen_nomode |
||||
if get(g:, 'matchup_matchparen_novisual', 0) " deprecated option name |
||||
let l:modes .= "vV\<c-v>" |
||||
endif |
||||
if stridx(l:modes, l:real_mode) >= 0 |
||||
return |
||||
endif |
||||
|
||||
" don't get matches when inside a closed fold |
||||
if foldclosed(line('.')) > -1 |
||||
return |
||||
endif |
||||
|
||||
" give up when cursor is far into a very long line |
||||
if &synmaxcol && col('.') > &synmaxcol |
||||
return |
||||
endif |
||||
|
||||
" in insert mode, cursor is treated as being one behind |
||||
let l:insertmode = l:real_mode ==# 'i' |
||||
|
||||
" start the timeout period |
||||
let l:timeout = l:insertmode |
||||
\ ? get(b:, 'matchup_matchparen_insert_timeout', |
||||
\ g:matchup_matchparen_insert_timeout) |
||||
\ : get(b:, 'matchup_matchparen_timeout', |
||||
\ g:matchup_matchparen_timeout) |
||||
call matchup#perf#timeout_start(l:timeout) |
||||
|
||||
let l:current = matchup#delim#get_current('all', 'both_all', |
||||
\ { 'insertmode': l:insertmode, |
||||
\ 'stopline': g:matchup_matchparen_stopline, |
||||
\ 'highlighting': 1, }) |
||||
call matchup#perf#toc('matchparen.highlight', 'get_current') |
||||
if empty(l:current) |
||||
if get(b:, 'matchup_matchparen_deferred', |
||||
\ g:matchup_matchparen_deferred) |
||||
\ && get(b:, 'matchup_matchparen_hi_surround_always', |
||||
\ g:matchup_matchparen_hi_surround_always) |
||||
call s:highlight_surrounding(l:insertmode) |
||||
endif |
||||
return |
||||
endif |
||||
|
||||
let l:corrlist = matchup#delim#get_matching(l:current, |
||||
\ { 'stopline': g:matchup_matchparen_stopline, |
||||
\ 'highlighting': 1, }) |
||||
call matchup#perf#toc('matchparen.highlight', 'get_matching') |
||||
if empty(l:corrlist) | return | endif |
||||
|
||||
if g:matchup_transmute_enabled |
||||
if !exists('w:matchup_matchparen_context') |
||||
let w:matchup_matchparen_context = { |
||||
\ 'normal': { |
||||
\ 'current': {}, |
||||
\ 'corrlist': [], |
||||
\ }, |
||||
\ 'prior': {}, |
||||
\ 'counter': 0, |
||||
\} |
||||
endif |
||||
|
||||
let w:matchup_matchparen_context.counter += 1 |
||||
|
||||
if !l:insertmode |
||||
let w:matchup_matchparen_context.prior |
||||
\ = copy(w:matchup_matchparen_context.normal) |
||||
|
||||
let w:matchup_matchparen_context.normal.current = l:current |
||||
let w:matchup_matchparen_context.normal.corrlist = l:corrlist |
||||
endif |
||||
|
||||
" if transmuted, highlight again (will reset timeout) |
||||
if matchup#transmute#tick(l:insertmode) |
||||
" no force_update here because it would screw up prior |
||||
return s:matchparen.highlight(0, l:changing_insert) |
||||
endif |
||||
endif |
||||
|
||||
if !has_key(l:current, 'match_index') |
||||
\ || len(l:corrlist) <= (l:current.side ==# 'mid' ? 2 : 1) |
||||
\ && !g:matchup_matchparen_singleton |
||||
" TODO this doesn't catch every case, needs refactor |
||||
" TODO singleton doesn't work right for mids |
||||
return |
||||
endif |
||||
|
||||
" prepare for (possibly) new highlights |
||||
let l:pos = [l:current.lnum, l:current.cnum] |
||||
if self.fade(1, l:pos, l:token) |
||||
return |
||||
endif |
||||
|
||||
" store flag meaning highlighting is active |
||||
let w:matchup_need_clear = 1 |
||||
|
||||
" disable off-screen when scrolling with j/k |
||||
let l:scrolling = get(g:matchup_matchparen_offscreen, 'scrolloff', 0) |
||||
\ && winheight(0) > 2*&scrolloff |
||||
\ && (line('.') == line('w$')-&scrolloff |
||||
\ && line('$') != line('w$') |
||||
\ || line('.') == line('w0')+&scrolloff) |
||||
|
||||
" show off-screen matches |
||||
let l:method = get(g:matchup_matchparen_offscreen, 'method', '') |
||||
if !empty(l:method) && l:method !=# 'none' |
||||
\ && !l:current.skip && !l:scrolling |
||||
\ && winheight(0) > 0 |
||||
call s:do_offscreen(l:current, l:method) |
||||
endif |
||||
|
||||
" add highlighting matches |
||||
call s:add_matches(l:corrlist, l:current) |
||||
|
||||
" highlight the background between parentheses |
||||
if g:matchup_matchparen_hi_background >= 1 |
||||
call s:highlight_background(l:corrlist) |
||||
endif |
||||
|
||||
" new highlights done, request fade away |
||||
call self.fade(2, l:pos, l:token) |
||||
|
||||
call matchup#perf#toc('matchparen.highlight', 'end') |
||||
endfunction |
||||
|
||||
function s:matchparen.transmute_reset() abort dict |
||||
if g:matchup_transmute_enabled |
||||
call matchup#transmute#reset() |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:do_offscreen(current, method) " {{{1 |
||||
let l:offscreen = {} |
||||
|
||||
if !has_key(a:current, 'links') | return | endif |
||||
|
||||
" prefer to show close |
||||
if a:current.links.open.lnum < line('w0') |
||||
let l:offscreen = a:current.links.open |
||||
endif |
||||
if a:current.links.close.lnum > line('w$') |
||||
let l:offscreen = a:current.links.close |
||||
endif |
||||
|
||||
if empty(l:offscreen) | return | endif |
||||
|
||||
if a:method ==# 'status' |
||||
call s:do_offscreen_statusline(l:offscreen, 0) |
||||
elseif a:method ==# 'status_manual' |
||||
call s:do_offscreen_statusline(l:offscreen, 1) |
||||
elseif a:method ==# 'popup' && winheight(0) > 1 |
||||
if has('nvim') |
||||
call s:do_offscreen_popup_nvim(l:offscreen) |
||||
elseif exists('*popup_create') |
||||
call s:ensure_match_popup() |
||||
call s:do_offscreen_popup(l:offscreen) |
||||
endif |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:do_offscreen_statusline(offscreen, manual) " {{{1 |
||||
let l:opts = {} |
||||
if a:manual |
||||
let l:opts.compact = 1 |
||||
endif |
||||
let [l:sl, l:lnum] = matchup#matchparen#status_str(a:offscreen, l:opts) |
||||
if s:ensure_scroll_timer() && !a:manual |
||||
let l:sl .= '%{matchup#matchparen#scroll_update('.l:lnum.')}' |
||||
endif |
||||
|
||||
let w:matchup_statusline = l:sl |
||||
if !exists('w:matchup_oldstatus') |
||||
let w:matchup_oldstatus = &l:statusline |
||||
endif |
||||
if !a:manual |
||||
let &l:statusline = w:matchup_statusline |
||||
endif |
||||
|
||||
if exists('#User#MatchupOffscreenEnter') |
||||
doautocmd <nomodeline> User MatchupOffscreenEnter |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:ensure_match_popup() abort " {{{1 |
||||
if !exists('*popup_create') || exists('t:match_popup') |
||||
return |
||||
endif |
||||
|
||||
" create a popup and store its winid |
||||
let t:match_popup = popup_create('', { |
||||
\ 'hidden': v:true, |
||||
\}) |
||||
|
||||
if !has('patch-8.1.1406') |
||||
" in case 'hidden' in popup_create-usage is unimplemented |
||||
call popup_hide(t:match_popup) |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:do_offscreen_popup(offscreen) " {{{1 |
||||
" screen position of top-left corner of current window |
||||
let [l:row, l:col] = win_screenpos(winnr()) |
||||
let l:height = winheight(0) " height of current window |
||||
let l:adjust = matchup#quirks#status_adjust(a:offscreen) |
||||
let l:lnum = a:offscreen.lnum + l:adjust |
||||
let l:line = l:lnum < line('.') ? l:row : l:row + l:height - 1 |
||||
|
||||
" if popup would overlap with cursor |
||||
if l:line == winline() | return | endif |
||||
|
||||
call popup_move(t:match_popup, { |
||||
\ 'line': l:line, |
||||
\ 'col': l:col, |
||||
\ 'maxheight': 1, |
||||
\}) |
||||
|
||||
" set popup text |
||||
let l:text = '' |
||||
if &number || &relativenumber |
||||
let l:text = printf('%*S ', wincol()-virtcol('.')-1, l:lnum) |
||||
endif |
||||
let l:text .= getline(l:lnum) . ' ' |
||||
if l:adjust |
||||
let l:text .= '… ' . a:offscreen.match . ' ' |
||||
endif |
||||
call setbufline(winbufnr(t:match_popup), 1, l:text) |
||||
call popup_show(t:match_popup) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:do_offscreen_popup_nvim(offscreen) " {{{1 |
||||
if exists('*nvim_open_win') |
||||
" neovim floating window |
||||
call s:close_floating_win() |
||||
|
||||
let l:lnum = a:offscreen.lnum |
||||
let [l:row, l:anchor] = l:lnum < line('.') |
||||
\ ? [0, 'NW'] : [winheight(0), 'SW'] |
||||
if l:row == winline() | return | endif |
||||
|
||||
" Set default width and height for now. |
||||
let s:float_id = nvim_open_win(bufnr('%'), v:false, { |
||||
\ 'relative': 'win', |
||||
\ 'anchor': l:anchor, |
||||
\ 'row': l:row, |
||||
\ 'col': 0, |
||||
\ 'width': 42, |
||||
\ 'height': &previewheight, |
||||
\ 'focusable': v:false, |
||||
\}) |
||||
|
||||
if &relativenumber |
||||
call nvim_win_set_option(s:float_id, 'number', v:true) |
||||
call nvim_win_set_option(s:float_id, 'relativenumber', v:false) |
||||
endif |
||||
|
||||
call s:populate_floating_win(a:offscreen) |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:populate_floating_win(offscreen) " {{{1 |
||||
let l:adjust = matchup#quirks#status_adjust(a:offscreen) |
||||
let l:lnum = a:offscreen.lnum + l:adjust |
||||
let l:body = getline(l:lnum, a:offscreen.lnum) |
||||
let l:body_length = len(l:body) |
||||
let l:height = min([l:body_length, &previewheight]) |
||||
|
||||
if exists('*nvim_open_win') |
||||
" neovim floating win |
||||
let width = max(map(copy(l:body), 'strdisplaywidth(v:val)')) |
||||
let l:width += wincol()-virtcol('.') |
||||
call nvim_win_set_width(s:float_id, l:width + 1) |
||||
call nvim_win_set_height(s:float_id, l:height) |
||||
call nvim_win_set_cursor(s:float_id, [l:lnum, 0]) |
||||
call nvim_win_set_option(s:float_id, 'wrap', v:false) |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:close_floating_win() " {{{1 |
||||
if !exists('s:float_id') |
||||
return |
||||
endif |
||||
if win_id2win(s:float_id) > 0 |
||||
call nvim_win_close(s:float_id, 0) |
||||
endif |
||||
let s:float_id = 0 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! MatchupStatusOffscreen() " {{{1 |
||||
return substitute(get(w:, 'matchup_statusline', ''), |
||||
\ '%<\|%#\w*#', '', 'g') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#matchparen#highlight_surrounding() abort " {{{1 |
||||
call matchup#perf#timeout_start(500) |
||||
call s:highlight_surrounding() |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:highlight_surrounding(...) " {{{1 |
||||
let l:opts = { 'local': 0, 'matches': [] } |
||||
let l:delims = matchup#delim#get_surrounding('delim_all', 1, l:opts) |
||||
let l:open = l:delims[0] |
||||
if empty(l:open) | return | endif |
||||
|
||||
let l:corrlist = l:opts.matches |
||||
if empty(l:corrlist) | return | endif |
||||
|
||||
" store flag meaning highlighting is active |
||||
let w:matchup_need_clear = 1 |
||||
|
||||
" add highlighting matches |
||||
call s:add_matches(l:corrlist) |
||||
|
||||
" highlight the background between parentheses |
||||
if g:matchup_matchparen_hi_background >= 2 |
||||
call s:highlight_background(l:corrlist) |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:highlight_background(corrlist) " {{{1 |
||||
let [l:lo1, l:lo2] = [a:corrlist[0], a:corrlist[-1]] |
||||
|
||||
let l:inclusive = 1 |
||||
if l:inclusive |
||||
call s:add_background_matches_1( |
||||
\ l:lo1.lnum, |
||||
\ l:lo1.cnum, |
||||
\ l:lo2.lnum, |
||||
\ l:lo2.cnum + matchup#delim#end_offset(l:lo2)) |
||||
else |
||||
call s:add_background_matches_1( |
||||
\ l:lo1.lnum, |
||||
\ l:lo1.cnum + matchup#delim#end_offset(l:lo1) + 1, |
||||
\ l:lo2.lnum, |
||||
\ l:lo2.cnum - 1) |
||||
endif |
||||
endfunction |
||||
|
||||
"}}}1 |
||||
|
||||
function! s:format_gutter(lnum, ...) " {{{1 |
||||
let l:opts = a:0 ? a:1 : {} |
||||
let l:padding = wincol()-virtcol('.') |
||||
let l:sl = '' |
||||
|
||||
let l:direction = a:lnum < line('.') |
||||
if &number || &relativenumber |
||||
let l:nw = max([strlen(line('$')), &numberwidth-1]) |
||||
let l:linenr = a:lnum " distinct for relativenumber |
||||
|
||||
if &relativenumber |
||||
let l:linenr = abs(l:linenr-line('.')) |
||||
endif |
||||
|
||||
let l:sl = printf('%'.(l:nw).'s', l:linenr) |
||||
if l:direction && !get(l:opts, 'noshowdir', 0) |
||||
let l:sl = '%#Search#' . l:sl . '∆%#Normal#' |
||||
else |
||||
let l:sl = '%#CursorLineNr#' . l:sl . ' %#Normal#' |
||||
endif |
||||
let l:padding -= l:nw + 1 |
||||
endif |
||||
|
||||
if empty(l:sl) && l:direction && !get(l:opts, 'noshowdir', 0) |
||||
let l:sl = '%#Search#∆%#Normal#' |
||||
let l:padding -= 1 " OK if this is negative |
||||
if l:padding == -1 && indent(a:lnum) == 0 |
||||
let l:padding = 0 |
||||
endif |
||||
endif |
||||
|
||||
" possible fold column, up to &foldcolumn characters |
||||
let l:fdcstr = '' |
||||
if &foldcolumn |
||||
let l:fdc = max([1, &foldcolumn-1]) |
||||
let l:fdl = foldlevel(a:lnum) |
||||
let l:fdcstr = l:fdl <= l:fdc ? repeat('|', l:fdl) |
||||
\ : join(range(l:fdl-l:fdc+1, l:fdl), '') |
||||
let l:padding -= len(l:fdcstr) |
||||
let l:fdcstr = '%#FoldColumn#' . l:fdcstr . '%#Normal#' |
||||
elseif empty(l:sl) |
||||
let l:sl = '%#Normal#' |
||||
endif |
||||
|
||||
" add remaining padding (this handles rest of fdc and scl) |
||||
let l:sl = l:fdcstr . repeat(' ', l:padding) . l:sl |
||||
return l:sl |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#matchparen#status_str(offscreen, ...) abort " {{{1 |
||||
let l:opts = a:0 ? a:1 : {} |
||||
let l:adjust = matchup#quirks#status_adjust(a:offscreen) |
||||
let l:lnum = a:offscreen.lnum + l:adjust |
||||
let l:line = getline(l:lnum) |
||||
|
||||
let l:sl = '' |
||||
let l:trimming = 0 |
||||
if get(l:opts, 'compact', 0) |
||||
let l:trimming = 1 |
||||
else |
||||
let l:sl = s:format_gutter(l:lnum, l:opts) |
||||
endif |
||||
|
||||
if has_key(l:opts, 'width') |
||||
" TODO subtract the gutter from above |
||||
let l:room = l:opts.width |
||||
else |
||||
let l:room = min([300, winwidth(0)]) - (wincol()-virtcol('.')) |
||||
endif |
||||
let l:room -= l:adjust ? 3+strdisplaywidth(a:offscreen.match) : 0 |
||||
let l:lasthi = '' |
||||
for l:c in range(min([l:room, strlen(l:line)])) |
||||
if !l:adjust && a:offscreen.cnum <= l:c+1 && l:c+1 <= a:offscreen.cnum |
||||
\ - 1 + strlen(a:offscreen.match) |
||||
let l:wordish = a:offscreen.match !~? '^[[:punct:]]\{1,3\}$' |
||||
" TODO: we can't overlap groups, this might not be totally correct |
||||
let l:curhi = l:wordish ? 'MatchWord' : 'MatchParen' |
||||
elseif char2nr(l:line[l:c]) < 32 |
||||
let l:curhi = 'SpecialKey' |
||||
else |
||||
let l:curhi = synIDattr(synID(l:lnum, l:c+1, 1), 'name') |
||||
if empty(l:curhi) |
||||
let l:curhi = 'Normal' |
||||
endif |
||||
endif |
||||
let l:sl .= (l:curhi !=# l:lasthi ? '%#'.l:curhi.'#' : '') |
||||
if l:trimming && l:line[l:c] !~ '\s' |
||||
let l:trimming = 0 |
||||
endif |
||||
if l:trimming |
||||
elseif l:line[l:c] ==# "\t" |
||||
let l:sl .= repeat(' ', strdisplaywidth(strpart(l:line, 0, 1+l:c)) |
||||
\ - strdisplaywidth(strpart(l:line, 0, l:c))) |
||||
elseif char2nr(l:line[l:c]) < 32 |
||||
let l:sl .= strtrans(l:line[l:c]) |
||||
elseif l:line[l:c] == '%' |
||||
let l:sl .= '%%' |
||||
else |
||||
let l:sl .= l:line[l:c] |
||||
endif |
||||
let l:lasthi = l:curhi |
||||
endfor |
||||
let l:sl = substitute(l:sl, '\s\+$', '', '') . '%<%#Normal#' |
||||
if l:adjust |
||||
let l:sl .= '%#LineNr# … %#Normal#' |
||||
\ . '%#MatchParen#' . a:offscreen.match . '%#Normal#' |
||||
endif |
||||
|
||||
return [l:sl, l:lnum] |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:ensure_scroll_timer() " {{{1 |
||||
if has('timers') && exists('*timer_pause') |
||||
if !exists('s:scroll_timer') |
||||
let s:scroll_timer = timer_start(50, |
||||
\ 'matchup#matchparen#scroll_callback', |
||||
\ { 'repeat': -1 }) |
||||
call timer_pause(s:scroll_timer, 1) |
||||
endif |
||||
endif |
||||
|
||||
return exists('s:scroll_timer') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#matchparen#scroll_callback(tid) " {{{1 |
||||
call timer_pause(a:tid, 1) |
||||
call s:matchparen.highlight(1) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#matchparen#scroll_update(lnum) " {{{1 |
||||
if line('w0') <= a:lnum && a:lnum <= line('w$') |
||||
\ && exists('s:scroll_timer') |
||||
call timer_pause(s:scroll_timer, 0) |
||||
endif |
||||
return '' |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:add_matches(corrlist, ...) " {{{1 |
||||
if !exists('w:matchup_match_id_list') |
||||
let w:matchup_match_id_list = [] |
||||
endif |
||||
|
||||
" if MatchwordCur is undefined and MatchWord links to MatchParen |
||||
" (as default), behave like MatchWordCur is the same as MatchParenCur |
||||
" otherwise, MatchWordCur is the same as MatchWord |
||||
if a:0 |
||||
let l:mwc = hlexists('MatchWordCur') ? 'MatchWordCur' |
||||
\ : (synIDtrans(hlID('MatchWord')) == hlID('MatchParen') |
||||
\ ? 'MatchParenCur' : 'MatchWord') |
||||
endif |
||||
|
||||
for l:corr in a:corrlist |
||||
let l:wordish = l:corr.match !~? '^[[:punct:]]\{1,3\}$' |
||||
|
||||
if a:0 && l:corr.match_index == a:1.match_index |
||||
let l:group = l:wordish ? l:mwc : 'MatchParenCur' |
||||
else |
||||
let l:group = l:wordish ? 'MatchWord' : 'MatchParen' |
||||
endif |
||||
|
||||
if exists('*matchaddpos') |
||||
call add(w:matchup_match_id_list, matchaddpos(l:group, |
||||
\ [[l:corr.lnum, l:corr.cnum, strlen(l:corr.match)]], 0)) |
||||
else |
||||
call add(w:matchup_match_id_list, matchadd(l:group, |
||||
\ '\%'.(l:corr.lnum).'l\%'.(l:corr.cnum).'c' |
||||
\ . '.\+\%<'.(l:corr.cnum+strlen(l:corr.match)+1).'c', 0)) |
||||
endif |
||||
endfor |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:add_background_matches_1(line1, col1, line2, col2) " {{{1 |
||||
if a:line1 == a:line2 && a:col1 > a:col2 |
||||
return |
||||
endif |
||||
|
||||
let l:priority = -1 |
||||
|
||||
if a:line1 == a:line2 |
||||
let l:match = '\%'.(a:line1).'l\&' |
||||
\ . '\%'.(a:col1).'c.*\%'.(a:col2).'c.' |
||||
else |
||||
let l:match = '\%>'.(a:line1).'l\(.\+\|^$\)\%<'.(a:line2).'l' |
||||
\ . '\|\%'.(a:line1).'l\%>'.(a:col1-1).'c.\+' |
||||
\ . '\|\%'.(a:line2).'l.\+\%<'.(a:col2+1).'c.' |
||||
endif |
||||
|
||||
call add(w:matchup_match_id_list, |
||||
\ matchadd('MatchBackground', l:match, l:priority)) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:add_background_matches_2(line1, col1, line2, col2) " {{{1 |
||||
if a:line1 == a:line2 && a:col1 > a:col2 |
||||
return |
||||
endif |
||||
|
||||
let l:priority = -1 |
||||
|
||||
let l:curline = a:line1 |
||||
while l:curline <= a:line2 |
||||
let l:endline = min([l:curline+7, a:line2]) |
||||
let l:list = range(l:curline, l:endline) |
||||
if l:curline == a:line1 |
||||
let l:list[0] = [a:line1, a:col1, |
||||
\ l:curline == a:line2 ? (a:col2-a:col1+1) |
||||
\ : strlen(getline(a:line1))] |
||||
endif |
||||
if l:endline == a:line2 && l:curline != a:line2 |
||||
let l:list[-1] = [a:line2, 1, a:col2] |
||||
endif |
||||
|
||||
call add(w:matchup_match_id_list, |
||||
\ matchaddpos('MatchBackground', l:list, l:priority)) |
||||
let l:curline = l:endline+1 |
||||
endwhile |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
" {{{1 function! matchup#misc#reload() |
||||
if get(s:, 'reload_guard', 1) |
||||
function! matchup#misc#reload() abort |
||||
let s:reload_guard = 0 |
||||
|
||||
for l:file in glob(fnamemodify(s:file, ':h') . '/../**/*.vim', 0, 1) |
||||
execute 'source' l:file |
||||
endfor |
||||
|
||||
call matchup#init() |
||||
|
||||
unlet s:reload_guard |
||||
endfunction |
||||
endif |
||||
|
||||
" }}}1 |
||||
|
||||
let s:file = expand('<sfile>') |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,313 @@
@@ -0,0 +1,313 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
" TODO this can probably be simplified |
||||
function! matchup#motion#op(motion) abort |
||||
call matchup#motion_force() |
||||
let l:sid = matchup#motion_sid() |
||||
let s:v_operator = v:operator |
||||
execute 'normal' l:sid.'(wise)' . (v:count > 0 ? v:count : '') |
||||
\ . l:sid.'(matchup-'.a:motion.')' |
||||
unlet s:v_operator |
||||
endfunction |
||||
|
||||
function matchup#motion#getoper() |
||||
return get(s:, 'v_operator', '') |
||||
endfunction |
||||
|
||||
function! matchup#motion#find_matching_pair(visual, down) " {{{1 |
||||
let [l:count, l:count1] = [v:count, v:count1] |
||||
|
||||
let l:is_oper = !empty(get(s:, 'v_operator', '')) |
||||
|
||||
if a:visual && !l:is_oper |
||||
normal! gv |
||||
endif |
||||
|
||||
if a:down && l:count > g:matchup_motion_override_Npercent |
||||
" TODO: dv50% does not work properly |
||||
if a:visual && l:is_oper |
||||
normal! V |
||||
endif |
||||
exe 'normal!' l:count.'%' |
||||
return |
||||
endif |
||||
|
||||
" disable the timeout |
||||
call matchup#perf#timeout_start(0) |
||||
|
||||
" get a delim where the cursor is |
||||
let l:delim = matchup#delim#get_current('all', 'both_all') |
||||
if empty(l:delim) |
||||
" otherwise search forward |
||||
let l:delim = matchup#delim#get_next('all', 'both_all') |
||||
if empty(l:delim) | return | endif |
||||
endif |
||||
|
||||
" loop count number of times |
||||
for l:dummy in range(l:count1) |
||||
let l:matches = matchup#delim#get_matching(l:delim, 1) |
||||
if len(l:matches) <= (l:delim.side ==# 'mid' ? 2 : 1) | return | endif |
||||
if !has_key(l:delim, 'links') | return | endif |
||||
let l:delim = get(l:delim.links, a:down ? 'next' : 'prev', {}) |
||||
if empty(l:delim) | return | endif |
||||
endfor |
||||
|
||||
if a:visual && l:is_oper |
||||
normal! gv |
||||
endif |
||||
|
||||
let l:exclusive = l:is_oper && (g:v_motion_force ==# 'v') |
||||
let l:forward = ((a:down && l:delim.side !=# 'open') |
||||
\ || l:delim.side ==# 'close') |
||||
|
||||
" go to the end of the delimiter, if necessary |
||||
let l:column = l:delim.cnum |
||||
if g:matchup_motion_cursor_end && !l:is_oper && l:forward |
||||
let l:column = matchup#delim#jump_target(l:delim) |
||||
endif |
||||
|
||||
let l:start_pos = matchup#pos#get_cursor() |
||||
|
||||
normal! m` |
||||
|
||||
" column position of last character in match |
||||
let l:eom = l:delim.cnum + matchup#delim#end_offset(l:delim) |
||||
|
||||
if l:is_oper && l:forward |
||||
let l:column = l:exclusive ? (l:column - 1) : l:eom |
||||
endif |
||||
|
||||
if l:is_oper && l:exclusive |
||||
\ && matchup#pos#smaller(l:delim, l:start_pos) |
||||
normal! o |
||||
call matchup#pos#set_cursor(matchup#pos#prev(l:start_pos)) |
||||
normal! o |
||||
endif |
||||
|
||||
" special handling for d% |
||||
let [l:start_lnum, l:start_cnum] = l:start_pos[1:2] |
||||
if get(s:, 'v_operator', '') ==# 'd' && l:start_lnum != l:delim.lnum |
||||
\ && g:v_motion_force ==# '' |
||||
let l:tl = [l:start_lnum, l:start_cnum] |
||||
let [l:tl, l:br, l:swap] = l:tl[0] <= l:delim.lnum |
||||
\ ? [l:tl, [l:delim.lnum, l:eom], 0] |
||||
\ : [[l:delim.lnum, l:delim.cnum], l:tl, 1] |
||||
|
||||
if getline(l:tl[0]) =~# '^[ \t]*\%'.l:tl[1].'c' |
||||
\ && getline(l:br[0]) =~# '\%'.(l:br[1]+1).'c[ \t]*$' |
||||
if l:swap |
||||
normal! o |
||||
call matchup#pos#set_cursor(l:br[0], strlen(getline(l:br[0]))+1) |
||||
normal! o |
||||
let l:column = 1 |
||||
else |
||||
normal! o |
||||
call matchup#pos#set_cursor(l:tl[0], 1) |
||||
normal! o |
||||
let l:column = strlen(getline(l:br[0]))+1 |
||||
endif |
||||
endif |
||||
endif |
||||
|
||||
let l:lnum = l:delim.lnum |
||||
|
||||
" make adjustments for selection option 'exclusive |
||||
if l:forward && a:visual && &selection ==# 'exclusive' |
||||
let [l:lnum, l:column] = matchup#pos#next_eol(l:lnum, l:column)[1:2] |
||||
endif |
||||
if !l:forward && l:is_oper && &selection ==# 'exclusive' |
||||
normal! o |
||||
call matchup#pos#set_cursor(matchup#pos#next_eol( |
||||
\ matchup#pos#get_cursor())) |
||||
normal! o |
||||
endif |
||||
|
||||
call matchup#pos#set_cursor(l:lnum, l:column) |
||||
if stridx(&foldopen, 'percent') >= 0 |
||||
normal! zv |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#motion#find_unmatched(visual, down, ...) " {{{1 |
||||
call matchup#perf#tic('motion#find_unmatched') |
||||
|
||||
let l:opts = a:0 ? a:1 : {} |
||||
let l:count = v:count1 |
||||
|
||||
let l:is_oper = !empty(get(s:, 'v_operator', '')) |
||||
let l:exclusive = l:is_oper |
||||
\ && g:v_motion_force !=# 'v' && g:v_motion_force !=# "\<c-v>" |
||||
|
||||
if a:visual |
||||
normal! gv |
||||
endif |
||||
|
||||
" set the timeout fairly high by default |
||||
let l:timeout = get(l:opts, 'timeout', 750) |
||||
call matchup#perf#timeout_start(l:timeout) |
||||
|
||||
for l:tries in range(3) |
||||
let [l:open, l:close] = matchup#delim#get_surrounding('delim_all', |
||||
\ l:tries ? l:count : 1, |
||||
\ { 'check_skip': get(l:opts, '__where_impl__', 0) }) |
||||
|
||||
if empty(l:open) || empty(l:close) |
||||
call matchup#perf#toc('motion#find_unmatched', 'fail'.l:tries) |
||||
return |
||||
endif |
||||
|
||||
let l:delim = a:down ? l:close : l:open |
||||
|
||||
let l:save_pos = matchup#pos#get_cursor() |
||||
let l:new_pos = [l:delim.lnum, l:delim.cnum] |
||||
|
||||
" this is an exclusive motion, ]% |
||||
if l:delim.side ==# 'close' |
||||
if l:exclusive |
||||
let l:new_pos[1] -= 1 |
||||
else |
||||
let l:new_pos[1] += matchup#delim#end_offset(l:delim) |
||||
endif |
||||
endif |
||||
|
||||
" if the cursor didn't move, increment count |
||||
if matchup#pos#equal(l:save_pos, l:new_pos) |
||||
let l:count += 1 |
||||
elseif l:tries |
||||
break |
||||
endif |
||||
|
||||
if l:count <= 1 |
||||
break |
||||
endif |
||||
endfor |
||||
|
||||
if a:down && !l:is_oper |
||||
let l:new_pos[1] = matchup#delim#jump_target(l:delim) |
||||
endif |
||||
|
||||
" this is an exclusive motion, [% |
||||
if !a:down && l:exclusive |
||||
normal! o |
||||
call matchup#pos#set_cursor(matchup#pos#prev( |
||||
\ matchup#pos#get_cursor())) |
||||
normal! o |
||||
endif |
||||
|
||||
" handle selection option 'exclusive' going backwards |
||||
if !a:down && l:is_oper && &selection ==# 'exclusive' |
||||
normal! o |
||||
call matchup#pos#set_cursor(matchup#pos#next_eol( |
||||
\ matchup#pos#get_cursor())) |
||||
normal! o |
||||
endif |
||||
|
||||
" handle selection option 'exclusive' going forwards |
||||
if a:down && l:is_oper && &selection ==# 'exclusive' |
||||
let l:new_pos = matchup#pos#next_eol(l:new_pos)[1:2] |
||||
endif |
||||
|
||||
if get(l:opts, '__where_impl__', 0) |
||||
let l:opts.delim = l:delim |
||||
else |
||||
normal! m` |
||||
endif |
||||
call matchup#pos#set_cursor(l:new_pos) |
||||
|
||||
call matchup#perf#toc('motion#find_unmatched', 'done') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#motion#jump_inside(visual) " {{{1 |
||||
let l:count = v:count1 |
||||
|
||||
let l:save_pos = matchup#pos#get_cursor() |
||||
|
||||
call matchup#perf#timeout_start(750) |
||||
|
||||
if a:visual |
||||
normal! gv |
||||
endif |
||||
|
||||
for l:counter in range(l:count) |
||||
if l:counter |
||||
let l:delim = matchup#delim#get_next('all', 'open') |
||||
else |
||||
let l:delim = matchup#delim#get_current('all', 'open') |
||||
if empty(l:delim) |
||||
let l:delim = matchup#delim#get_next('all', 'open') |
||||
endif |
||||
endif |
||||
if empty(l:delim) |
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
return |
||||
endif |
||||
|
||||
let l:new_pos = [l:delim.lnum, l:delim.cnum] |
||||
let l:new_pos[1] += matchup#delim#end_offset(l:delim) |
||||
call matchup#pos#set_cursor(matchup#pos#next(l:new_pos)) |
||||
endfor |
||||
|
||||
call matchup#pos#set_cursor(l:save_pos) |
||||
|
||||
" convert to [~, lnum, cnum, ~] format |
||||
let l:new_pos = matchup#pos#next(l:new_pos) |
||||
|
||||
" this is an exclusive motion except when dealing with whitespace |
||||
let l:is_oper = !empty(get(s:, 'v_operator', '')) |
||||
if l:is_oper |
||||
\ && g:v_motion_force !=# 'v' && g:v_motion_force !=# "\<c-v>" |
||||
while matchup#util#in_whitespace(l:new_pos[1], l:new_pos[2]) |
||||
let l:new_pos = matchup#pos#next(l:new_pos) |
||||
endwhile |
||||
let l:new_pos = matchup#pos#prev(l:new_pos) |
||||
endif |
||||
|
||||
" jump ahead if inside indent |
||||
if !l:is_oper && matchup#util#in_indent(l:new_pos[1], l:new_pos[2]) |
||||
let l:new_pos[2] = 1 + strlen(matchstr( |
||||
\ getline(l:new_pos[1]), '^\s\+')) |
||||
endif |
||||
|
||||
" handle selection option 'exclusive' (motion only goes forwards) |
||||
if a:visual && &selection ==# 'exclusive' |
||||
let l:new_pos = matchup#pos#next_eol(l:new_pos) |
||||
endif |
||||
|
||||
normal! m` |
||||
call matchup#pos#set_cursor(l:new_pos) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#motion#insert_mode() " {{{1 |
||||
call matchup#perf#timeout_start(0) " disable the timeout |
||||
|
||||
let l:delim = matchup#delim#get_current( |
||||
\ 'all', 'both_all', {'insertmode': 1}) |
||||
if empty(l:delim) | return | endif |
||||
|
||||
let l:matches = matchup#delim#get_matching(l:delim, 1) |
||||
if len(l:matches) <= (l:delim.side ==# 'mid' ? 2 : 1) | return | endif |
||||
if !has_key(l:delim, 'links') | return | endif |
||||
let l:delim = get(l:delim.links, 'next', {}) |
||||
if empty(l:delim) | return | endif |
||||
|
||||
let l:new_pos = [l:delim.lnum, l:delim.cnum] |
||||
let l:new_pos[1] += matchup#delim#end_offset(l:delim) |
||||
call matchup#pos#set_cursor(matchup#pos#next_eol(l:new_pos)) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,117 @@
@@ -0,0 +1,117 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
let s:time_start = {} |
||||
let s:alpha = 2.0/(10+1) |
||||
|
||||
let g:matchup#perf#times = {} |
||||
|
||||
function! matchup#perf#tic(context) |
||||
let s:time_start[a:context] = reltime() |
||||
endfunction |
||||
|
||||
function! matchup#perf#toc(context, state) |
||||
let l:elapsed = s:reltimefloat(reltime(s:time_start[a:context])) |
||||
|
||||
let l:key = a:context.'#'.a:state |
||||
if has_key(g:matchup#perf#times, l:key) |
||||
if l:elapsed > g:matchup#perf#times[l:key].maximum |
||||
let g:matchup#perf#times[l:key].maximum = l:elapsed |
||||
endif |
||||
let g:matchup#perf#times[l:key].last = l:elapsed |
||||
let g:matchup#perf#times[l:key].emavg = s:alpha*l:elapsed |
||||
\ + (1-s:alpha)*g:matchup#perf#times[l:key].emavg |
||||
else |
||||
let g:matchup#perf#times[l:key] = { |
||||
\ 'maximum' : l:elapsed, |
||||
\ 'emavg' : l:elapsed, |
||||
\ 'last' : l:elapsed, |
||||
\} |
||||
endif |
||||
endfunction |
||||
|
||||
function! s:sort_by_last(a, b) |
||||
let l:a = g:matchup#perf#times[a:a].last |
||||
let l:b = g:matchup#perf#times[a:b].last |
||||
return l:a == l:b ? 0 : l:a > l:b ? 1 : -1 |
||||
endfunction |
||||
|
||||
function! matchup#perf#show_times() |
||||
let l:keys = keys(g:matchup#perf#times) |
||||
let l:contexts = uniq(sort(map(copy(l:keys), 'split(v:val, "#")[0]'))) |
||||
if empty(l:contexts) |
||||
echo 'no times' |
||||
return |
||||
end |
||||
|
||||
echohl Title |
||||
echo printf("%42s%11s%17s", 'average', 'last', 'maximum') |
||||
echohl None |
||||
for l:c in l:contexts |
||||
echohl Special |
||||
echo '['.l:c.']' |
||||
echohl None |
||||
let l:states = filter(copy(l:keys), 'v:val =~# "^\\V'.l:c.'#"') |
||||
call sort(l:states, 's:sort_by_last') |
||||
for l:s in l:states |
||||
echo printf(" %-25s%12.2gms%12.2gms%12.2gms", |
||||
\ join(split(l:s,'#')[1:],'#'), |
||||
\ 1000*g:matchup#perf#times[l:s].emavg, |
||||
\ 1000*g:matchup#perf#times[l:s].last, |
||||
\ 1000*g:matchup#perf#times[l:s].maximum) |
||||
endfor |
||||
endfor |
||||
endfunction |
||||
|
||||
command! MatchupShowTimes call matchup#perf#show_times() |
||||
command! MatchupClearTimes let g:matchup#perf#times = {} |
||||
|
||||
let s:timeout = 0 |
||||
let s:timeout_enabled = 0 |
||||
let s:timeout_pulse_time = reltime() |
||||
|
||||
function! matchup#perf#timeout() " {{{1 |
||||
return float2nr(s:timeout) |
||||
endfunction |
||||
|
||||
"}}}1 |
||||
function! matchup#perf#timeout_start(timeout) " {{{1 |
||||
let s:timeout = a:timeout |
||||
let s:timeout_enabled = (a:timeout == 0) ? 0 : 1 |
||||
let s:timeout_pulse_time = reltime() |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#perf#timeout_check() " {{{1 |
||||
if !s:timeout_enabled | return 0 | endif |
||||
let l:elapsed = 1000.0 * s:reltimefloat(reltime(s:timeout_pulse_time)) |
||||
let s:timeout -= l:elapsed |
||||
let s:timeout_pulse_time = reltime() |
||||
return s:timeout <= 0.0 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
" function! s:reltimefloat(time) {{{1 |
||||
if exists('*reltimefloat') |
||||
function! s:reltimefloat(time) |
||||
return reltimefloat(a:time) |
||||
endfunction |
||||
else |
||||
function! s:reltimefloat(time) |
||||
return str2float(reltimestr(a:time)) |
||||
endfunction |
||||
endif |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,143 @@
@@ -0,0 +1,143 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#pos#set_cursor(...) " {{{1 |
||||
call cursor(s:parse_args(a:000)) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
" function! matchup#pos#get_cursor() {{{1 |
||||
if exists('*getcurpos') |
||||
function! matchup#pos#get_cursor() |
||||
return getcurpos() |
||||
endfunction |
||||
else |
||||
function! matchup#pos#get_cursor() |
||||
return getpos('.') |
||||
endfunction |
||||
endif |
||||
|
||||
" }}}1 |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#get_cursor_line() " {{{1 |
||||
let l:pos = matchup#pos#get_cursor() |
||||
return l:pos[1] |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#pos#(...) abort " {{{1 |
||||
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000) |
||||
return [l:lnum, l:cnum] |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#val(...) " {{{1 |
||||
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000) |
||||
|
||||
return 100000*l:lnum + min([l:cnum, 90000]) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#next_eol(...) " {{{1 |
||||
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000) |
||||
|
||||
if l:cnum > strlen(getline(l:lnum)) |
||||
return [0, l:lnum+1, 1, 0] |
||||
endif |
||||
|
||||
let l:next = matchup#pos#next(l:lnum, l:cnum) |
||||
if l:next[1] > l:lnum |
||||
return [0, l:lnum, l:cnum+1, 0] |
||||
endif |
||||
return l:next |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#next(...) " {{{1 |
||||
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000) |
||||
|
||||
let l:line = getline(l:lnum) |
||||
let l:charlen = matchend(l:line[l:cnum-1:], '.') |
||||
if l:charlen >= 0 && l:cnum + l:charlen <= strlen(l:line) |
||||
return [0, l:lnum, l:cnum + l:charlen, 0] |
||||
else |
||||
return [0, l:lnum+1, 1, 0] |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#prev(...) " {{{1 |
||||
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000) |
||||
|
||||
if l:cnum > 1 |
||||
return [0, l:lnum, match(getline(l:lnum)[0:l:cnum-2], '.$') + 1, 0] |
||||
else |
||||
return [0, max([l:lnum-1, 1]), |
||||
\ max([strlen(getline(l:lnum-1)), 1]), 0] |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#larger(pos1, pos2) " {{{1 |
||||
return matchup#pos#val(a:pos1) > matchup#pos#val(a:pos2) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#equal(p1, p2) " {{{1 |
||||
let l:pos1 = s:parse_args(a:p1) |
||||
let l:pos2 = s:parse_args(a:p2) |
||||
return l:pos1[:1] == l:pos2[:1] |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#smaller(pos1, pos2) " {{{1 |
||||
return matchup#pos#val(a:pos1) < matchup#pos#val(a:pos2) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#pos#smaller_or_equal(pos1, pos2) " {{{1 |
||||
return matchup#pos#smaller(a:pos1, a:pos2) |
||||
\ || matchup#pos#equal(a:pos1, a:pos2) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:parse_args(args) " {{{1 |
||||
" |
||||
" The arguments should be in one of the following forms (when unpacked): |
||||
" |
||||
" [lnum, cnum] |
||||
" [bufnum, lnum, cnum, ...] |
||||
" {'lnum' : lnum, 'cnum' : cnum} |
||||
" |
||||
|
||||
if len(a:args) > 1 |
||||
return s:parse_args([a:args]) |
||||
elseif len(a:args) == 1 |
||||
if type(a:args[0]) == type({}) |
||||
return [get(a:args[0], 'lnum'), get(a:args[0], 'cnum')] |
||||
else |
||||
if len(a:args[0]) == 2 |
||||
return a:args[0] |
||||
else |
||||
return a:args[0][1:] |
||||
endif |
||||
endif |
||||
else |
||||
return a:args |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#quirks#isclike() abort " {{{1 |
||||
let l:ft = get(split(&filetype, '\.'), 0, '') |
||||
return index(s:clikeft, l:ft) > -1 |
||||
endfunction |
||||
|
||||
let s:clikeft = [ 'arduino', 'c', 'cpp', 'cuda', |
||||
\ 'go', 'javascript', 'ld', 'php' ] |
||||
|
||||
" }}}1 |
||||
|
||||
let s:adjust_max = 7 |
||||
|
||||
function! matchup#quirks#status_adjust(offscreen) abort " {{{1 |
||||
if a:offscreen.match ==# '{' && matchup#quirks#isclike() |
||||
let [l:a, l:b] = [indent(a:offscreen.lnum), |
||||
\ indent(a:offscreen.links.close.lnum)] |
||||
if strpart(getline(a:offscreen.lnum), |
||||
\ 0, a:offscreen.cnum-1) =~# '^\s*$' |
||||
let l:target = l:a |
||||
elseif l:a != l:b |
||||
let l:target = l:b |
||||
else |
||||
return 0 |
||||
endif |
||||
" go up to next line with same indent (up to s:adjust_max) |
||||
for l:adjust in range(-1, -s:adjust_max, -1) |
||||
let l:lnum = a:offscreen.lnum + l:adjust |
||||
if indent(l:lnum) == l:target |
||||
\ && getline(l:lnum) !~ '^\s*\%(#\|/\*\|//\)' |
||||
return l:adjust |
||||
endif |
||||
endfor |
||||
endif |
||||
|
||||
return 0 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:nbsl = '\v%(\\@<!%(\\\\)*)@<=\m' |
||||
let g:matchup#re#not_bslash = s:nbsl |
||||
|
||||
" 1 \1 \\1 \\\1 \\\\1 \\\\\1 |
||||
let g:matchup#re#backref = s:nbsl . '\\' . '\(\d\)' |
||||
|
||||
" \zs atom |
||||
let g:matchup#re#zs = s:nbsl . '\\zs' |
||||
|
||||
" \ze atom |
||||
let g:matchup#re#ze = s:nbsl . '\\ze' |
||||
|
||||
" \g{special}, \g{special:arg} |
||||
let g:matchup#re#gspec = s:nbsl . '\\g{\(\w\+\);\?\(.\{-}\)\?}' |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
scriptencoding utf-8 |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#surround#delimited(is_cap, op, type) " {{{1 |
||||
call matchup#perf#timeout_start(1000) |
||||
|
||||
let [l:open, l:close] = matchup#delim#get_surrounding( |
||||
\ a:type, v:count, { 'local': 0 }) |
||||
if empty(l:open) || empty(l:close) |
||||
return |
||||
endif |
||||
|
||||
if a:op ==# 'c' |
||||
let l:char = nr2char(getchar()) |
||||
if index(["\<esc>","\<c-c>"], l:char) >= 0 |
||||
return |
||||
endif |
||||
endif |
||||
let l:tpope = !empty(maparg('<plug>VSurround', 'x')) |
||||
|
||||
let [l:l1, l:c11, l:c12] = [l:open.lnum, l:open.cnum, |
||||
\ l:open.cnum + strlen(l:open.match) - 1] |
||||
let [l:l2, l:c21, l:c22] = [l:close.lnum, l:close.cnum, |
||||
\ l:close.cnum + strlen(l:close.match) - 1] |
||||
|
||||
if a:op ==# 'd' || a:op ==# 'c' |
||||
call matchup#pos#set_cursor(l1, c12+1) |
||||
|
||||
let [l:insl, l:insr] = ['', ''] |
||||
if a:op ==# 'c' && !l:tpope |
||||
let l:idx = index(s:pairtrans, l:char) |
||||
let l:insl = l:idx < 0 ? l:char : s:pairtrans[l:idx/2*2] |
||||
let l:insr = l:idx < 0 ? l:char : s:pairtrans[l:idx/2*2+1] |
||||
endif |
||||
|
||||
let l:line = getline(l:l2) |
||||
call setline(l:l2, strpart(l:line, 0, l:c21-1) |
||||
\ . l:insr . strpart(l:line, l:c22)) |
||||
let l:regtext = strpart(l:line, l:c21-1, l:c22-l:c21+1) |
||||
|
||||
let l:line = getline(l:l1) |
||||
call setline(l:l1, strpart(l:line, 0, l:c11-1) |
||||
\ . l:insl . strpart(l:line, l:c12)) |
||||
|
||||
call setreg(v:register, strpart(l:line, l:c11-1, l:c12-l:c11+1) |
||||
\ . ' ' . l:regtext) |
||||
|
||||
let l:epos = l:c21-1 - (l:l1 == l:l2 |
||||
\ ? (l:c12-l:c11+1-strlen(l:insl)-strlen(l:insr)) : 0) |
||||
call setpos("']", [0, l:l2, l:epos, 0]) |
||||
call setpos("'[", [0, l:l1, l:c11, 0]) |
||||
endif |
||||
|
||||
if a:op ==# 'd' || a:op ==# 'c' && empty(l:char) |
||||
silent! call repeat#set("\<plug>(matchup-ds%)", v:count) |
||||
elseif a:op ==# 'c' && l:tpope |
||||
normal! `[v`] |
||||
undojoin |
||||
execute "normal \<plug>VSurround".l:char |
||||
silent! call repeat#set("\<plug>(matchup-cs%)" |
||||
\ . matchstr(g:repeat_sequence, 'SSurroundRepeat\zs.\+'), |
||||
\ v:count) |
||||
endif |
||||
|
||||
call matchup#pos#set_cursor(l1, c11) |
||||
endfunction |
||||
|
||||
let s:pairtrans = split('()<>[]{}«»“”', '\ze') |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,296 @@
@@ -0,0 +1,296 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#text_obj#delimited(is_inner, visual, type) " {{{1 |
||||
let l:v_motion_force = matchup#motion_force() |
||||
|
||||
" get the current selection, move to the _start_ the of range |
||||
if a:visual |
||||
let l:selection = getpos("'<")[1:2] + getpos("'>")[1:2] |
||||
call matchup#pos#set_cursor(getpos("'<")) |
||||
endif |
||||
|
||||
" motion forcing |
||||
let l:forced = a:visual ? '' : l:v_motion_force |
||||
|
||||
" determine if operator is able to act line-wise (i.e., for inner) |
||||
let l:linewise_op = index(g:matchup_text_obj_linewise_operators, |
||||
\ v:operator) >= 0 |
||||
|
||||
if v:operator ==# 'g@' |
||||
let l:save_reg = v:register |
||||
let l:spec = matchlist(g:matchup_text_obj_linewise_operators, |
||||
\ '^g@\%(,\(.\+\)\)\?') |
||||
if !empty(l:spec) |
||||
if empty(l:spec[1]) |
||||
let l:linewise_op = 1 |
||||
else |
||||
execute 'let l:linewise_op =' l:spec[1] |
||||
endif |
||||
endif |
||||
elseif v:operator ==# ':' |
||||
\ && index(g:matchup_text_obj_linewise_operators, |
||||
\ visualmode()) >= 0 |
||||
let l:linewise_op = 1 |
||||
endif |
||||
|
||||
" set the timeout fairly high |
||||
call matchup#perf#timeout_start(725) |
||||
|
||||
" try up to six times |
||||
for [l:local, l:try_again] in (v:count == 1 |
||||
\ || v:count > g:matchup_delim_count_max) |
||||
\ ? a:is_inner ? [[0, 0], [0, 1], [0, 2], [0, 3]] |
||||
\ : [[0, 0], [0, 1], [0, 2]] |
||||
\ : a:is_inner ? [[1, 0], [0, 0], [1, 1], [0, 1], [1, 2], [0, 2]] |
||||
\ : [[1, 0], [0, 0], [1, 1], [0, 1]] |
||||
|
||||
let l:count = v:count1 + l:try_again |
||||
|
||||
" we use v:count1 on the first try and increment each successive time |
||||
" find the open-close block then narrow down to local after |
||||
let [l:open_, l:close_] = matchup#delim#get_surrounding( |
||||
\ a:type, l:count, { 'local': 0 }) |
||||
|
||||
if empty(l:open_) |
||||
if a:visual |
||||
normal! gv |
||||
else |
||||
" TODO: can this be simplified by making omaps <expr>? |
||||
" invalid text object, try to do nothing |
||||
" cause a drop into normal mode |
||||
call feedkeys("\<c-\>\<c-n>\<esc>", 'n') |
||||
|
||||
" and undo the text vim enters if necessary |
||||
call feedkeys(":call matchup#text_obj#undo(" |
||||
\ .undotree().seq_cur.")\<cr>:\<c-c>", 'n') |
||||
endif |
||||
return |
||||
endif |
||||
|
||||
if l:local |
||||
let [l:open, l:close] = matchup#delim#get_surround_nearest(l:open_) |
||||
if empty(l:open) |
||||
let [l:open, l:close] = [l:open_, l:open_.links.next] |
||||
endif |
||||
else |
||||
let [l:open, l:close] = [l:open_, l:open_.links.close] |
||||
endif |
||||
|
||||
" no way to specify an empty region so we need to use some tricks |
||||
let l:epos = [l:open.lnum, l:open.cnum] |
||||
let l:epos[1] += matchup#delim#end_offset(l:open) |
||||
if !a:visual && a:is_inner |
||||
\ && matchup#pos#equal(l:close, matchup#pos#next(l:epos)) |
||||
|
||||
" TODO: cpo-E |
||||
if v:operator ==# 'c' |
||||
" this is apparently the most reliable way to handle |
||||
" the 'c' operator, although it raises a TextChangedI |
||||
" and fills registers with a space (from targets.vim) |
||||
call matchup#pos#set_cursor(l:close) |
||||
silent! execute "normal! i \<esc>v" |
||||
elseif stridx('<>', v:operator) < 0 |
||||
let l:byte = line2byte(l:close.lnum) + l:close.cnum - 1 |
||||
call feedkeys(l:byte.'go', 'n') |
||||
endif |
||||
|
||||
return |
||||
endif |
||||
|
||||
let [l:l1, l:c1, l:l2, l:c2] = [l:open.lnum, l:open.cnum, |
||||
\ l:close.lnum, l:close.cnum] |
||||
|
||||
" whether the pair has at least one line in between them |
||||
let l:line_count = l:l2 - l:l1 + 1 |
||||
|
||||
" special case: if inner and the current selection coincides |
||||
" with the open and close positions, try for a second time |
||||
" this allows vi% in [[ ]] to work |
||||
if a:visual && a:is_inner && l:selection == [l:l1, l:c1, l:l2, l:c2] |
||||
continue |
||||
endif |
||||
|
||||
" adjust the borders of the selection |
||||
if a:is_inner |
||||
let l:c1 += matchup#delim#end_offset(l:open) |
||||
let [l:l1, l:c1] = matchup#pos#next(l:l1, l:c1)[1:2] |
||||
let l:sol = (l:c2 <= 1) |
||||
let [l:l2, l:c2] = matchup#pos#prev(l:l2, l:c2)[1:2] |
||||
|
||||
" don't select only indent at close |
||||
while matchup#util#in_indent(l:l2, l:c2) |
||||
let l:c2 = 1 |
||||
let [l:l2, l:c2] = matchup#pos#prev(l:l2, l:c2)[1:2] |
||||
let l:sol = 1 |
||||
endwhile |
||||
|
||||
" include the line break if we had wrapped around |
||||
if a:visual && l:sol |
||||
let l:c2 = strlen(getline(l:l2))+1 |
||||
endif |
||||
|
||||
if !a:visual |
||||
" otherwise adjust end pos |
||||
if l:sol |
||||
let [l:l2, l:c2] = matchup#pos#next(l:l2, l:c2)[1:2] |
||||
endif |
||||
|
||||
" toggle exclusive: difference between di% and dvi% |
||||
let l:inclusive = 0 |
||||
if !l:sol && matchup#pos#smaller_or_equal( |
||||
\ [l:l1, l:c1], [l:l2, l:c2]) |
||||
let l:inclusive = 1 |
||||
endif |
||||
if l:forced ==# 'v' |
||||
let l:inclusive = !l:inclusive |
||||
endif |
||||
|
||||
" sometimes operate in visual line motion (re-purpose force) |
||||
" cf src/normal.c:1824 |
||||
if empty(l:v_motion_force) |
||||
\ && l:c2 <= 1 && l:line_count > 1 && !l:inclusive |
||||
let l:l2 -= 1 |
||||
if l:c1 <= 1 || matchup#util#in_indent(l:l1, l:c1-1) |
||||
let l:forced = 'V' |
||||
let l:inclusive = 1 |
||||
else |
||||
" end_adjusted |
||||
let l:c2 = strlen(getline(l:l2)) + 1 |
||||
if l:c2 > 1 |
||||
let l:c2 -= 1 |
||||
let l:inclusive = 1 |
||||
endif |
||||
endif |
||||
endif |
||||
|
||||
if !l:inclusive |
||||
let [l:l2, l:c2] = matchup#pos#prev(l:l2, l:c2)[1:2] |
||||
endif |
||||
endif |
||||
|
||||
" check for the line-wise special case |
||||
if l:line_count > 2 && l:linewise_op && strlen(l:close.match) > 1 |
||||
if l:c1 != 1 |
||||
let l:l1 += 1 |
||||
let l:c1 = 1 |
||||
endif |
||||
let l:l2 = l:close.lnum - 1 |
||||
let l:c2 = strlen(getline(l:l2))+1 |
||||
endif |
||||
|
||||
" if this would be an empty selection.. |
||||
if !a:visual && (l:l2 < l:l1 || l:l1 == l:l2 && l:c1 > l:c2) |
||||
if v:operator ==# 'c' |
||||
call matchup#pos#set_cursor(l:l1, l:c1) |
||||
silent! execute "normal! i \<esc>v" |
||||
elseif stridx('<>', v:operator) < 0 |
||||
let l:byte = line2byte(l:l1) + l:c1 - 1 |
||||
call feedkeys(l:byte.'go', 'n') |
||||
endif |
||||
return |
||||
endif |
||||
else |
||||
let l:c2 += matchup#delim#end_offset(l:close) |
||||
|
||||
" special case for delete operator |
||||
if !a:visual && v:operator ==# 'd' |
||||
\ && strpart(getline(l:l2), l:c2) =~# '^\s*$' |
||||
\ && strpart(getline(l:l2), 0, l:c1-1) =~# '^\s*$' |
||||
let l:c1 = 1 |
||||
let l:c2 = strlen(getline(l:l2))+1 |
||||
endif |
||||
endif |
||||
|
||||
" in visual line mode, force new selection to not be smaller |
||||
" (only check line numbers) |
||||
if a:visual && visualmode() ==# 'V' |
||||
\ && (l:l1 > l:selection[0] || l:l2 < l:selection[2]) |
||||
continue |
||||
endif |
||||
|
||||
" in other visual modes, try again if we didn't reach a bigger range |
||||
if a:visual && visualmode() !=# 'V' |
||||
\ && !matchup#pos#equal(l:selection[0:1], l:selection[2:3]) |
||||
\ && (l:selection == [l:l1, l:c1, l:l2, l:c2] |
||||
\ || matchup#pos#larger([l:l1, l:c1], l:selection[0:1]) |
||||
\ || matchup#pos#larger(l:selection[2:3], [l:l2, l:c2])) |
||||
continue |
||||
endif |
||||
|
||||
break |
||||
endfor |
||||
|
||||
" set the proper visual mode for this selection |
||||
let l:select_mode = (v:operator ==# ':') |
||||
\ ? visualmode() |
||||
\ : (l:forced !=# '') |
||||
\ ? l:forced |
||||
\ : 'v' |
||||
|
||||
if &selection ==# 'exclusive' |
||||
let [l:l2, l:c2] = matchup#pos#next_eol(l:l2, l:c2)[1:2] |
||||
endif |
||||
|
||||
" apply selection |
||||
execute 'normal!' l:select_mode |
||||
normal! o |
||||
call matchup#pos#set_cursor(l:l1, l:c1) |
||||
normal! o |
||||
call matchup#pos#set_cursor(l:l2, l:c2) |
||||
if exists('l:save_reg') |
||||
execute 'normal! "' . l:save_reg |
||||
endif |
||||
endfunction |
||||
|
||||
function! matchup#text_obj#undo(seq) |
||||
if undotree().seq_cur > a:seq |
||||
silent! undo |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#text_obj#double_click() " {{{1 |
||||
let [l:open, l:close] = [{}, {}] |
||||
|
||||
call matchup#perf#timeout_start(0) |
||||
let l:delim = matchup#delim#get_current('all', 'both_all') |
||||
if !empty(l:delim) |
||||
let l:matches = matchup#delim#get_matching(l:delim, 1) |
||||
if len(l:matches) > 1 && has_key(l:delim, 'links') |
||||
let [l:open, l:close] = [l:delim.links.open, l:delim.links.close] |
||||
endif |
||||
endif |
||||
|
||||
if empty(l:open) || empty(l:close) |
||||
call feedkeys("\<2-LeftMouse>", 'nt') |
||||
return |
||||
endif |
||||
|
||||
let [l:lnum, l:cnum] = [l:close.lnum, l:close.cnum] |
||||
let l:cnum += matchup#delim#end_offset(l:close) |
||||
|
||||
if &selection ==# 'exclusive' |
||||
let [l:lnum, l:cnum] = matchup#pos#next_eol(l:lnum, l:cnum)[1:2] |
||||
endif |
||||
|
||||
call matchup#pos#set_cursor(l:open) |
||||
normal! v |
||||
call matchup#pos#set_cursor(l:lnum, l:cnum) |
||||
if l:delim.side ==# 'close' |
||||
normal! o |
||||
endif |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,146 @@
@@ -0,0 +1,146 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#transmute#init_module() " {{{1 |
||||
if !g:matchup_transmute_enabled | return | endif |
||||
|
||||
call matchup#transmute#enable() |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#transmute#enable() " {{{1 |
||||
" TODO: add insert mode map |
||||
" TODO: add g:matchup_transmute_auto |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#transmute#disable() " {{{1 |
||||
|
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#transmute#tick(insertmode) " {{{1 |
||||
if !g:matchup_transmute_enabled | return 0 | endif |
||||
|
||||
if a:insertmode |
||||
return 0 |
||||
endif |
||||
|
||||
if changenr() > get(w:, 'matchup_transmute_last_changenr', -1) |
||||
\ && !empty('w:matchup_matchparen_context.prior') |
||||
let w:matchup_transmute_last_changenr = changenr() |
||||
|
||||
return matchup#transmute#dochange( |
||||
\ w:matchup_matchparen_context.prior.corrlist, |
||||
\ w:matchup_matchparen_context.prior.current, |
||||
\ w:matchup_matchparen_context.normal.current) |
||||
endif |
||||
|
||||
return 0 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#transmute#reset() " {{{1 |
||||
if !g:matchup_transmute_enabled | return 0 | endif |
||||
let w:matchup_transmute_last_changenr = changenr() |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#transmute#dochange(list, pri, cur) " {{{1 |
||||
if empty(a:list) || empty(a:pri) || empty(a:cur) | return 0 | endif |
||||
|
||||
let l:cur = a:cur |
||||
|
||||
" check back one |
||||
if a:pri.class[0] != l:cur.class[0] |
||||
let l:cur = matchup#delim#get_current('all', a:pri.side, |
||||
\ {'insertmode': 1}) |
||||
if empty(l:cur) | return 0 | endif |
||||
endif |
||||
|
||||
" right now, only same-class changes are supported |
||||
if a:pri.class[0] != l:cur.class[0] |
||||
return 0 |
||||
endif |
||||
if a:pri.side =~# '^open\|close$' && a:pri.side isnot l:cur.side |
||||
return 0 |
||||
endif |
||||
if !matchup#pos#equal(a:pri, l:cur) |
||||
return 0 |
||||
endif |
||||
|
||||
let l:num_changes = 0 |
||||
|
||||
let l:delta = strdisplaywidth(l:cur.match) |
||||
\ - strdisplaywidth(a:pri.match) |
||||
|
||||
for l:i in range(len(a:list)) |
||||
if l:i == a:pri.match_index | continue | endif |
||||
|
||||
let l:corr = a:list[l:i] |
||||
let l:line = getline(l:corr.lnum) |
||||
|
||||
let l:column = l:corr.cnum |
||||
if l:corr.lnum == l:cur.lnum && l:i > a:pri.match_index |
||||
let l:column += l:delta |
||||
endif |
||||
|
||||
let l:re_anchored = '\%'.(l:column).'c' |
||||
\ . '\%('.(l:corr.regexone[l:corr.side]).'\)' |
||||
|
||||
let l:groups = copy(l:corr.groups) |
||||
for l:grp in keys(l:groups) |
||||
let l:count = len(split(l:re_anchored, |
||||
\ g:matchup#re#not_bslash.'\\'.l:grp))-1 |
||||
if l:count == 0 | continue | endif |
||||
|
||||
if l:cur.groups[l:grp] ==# l:groups[l:grp] |
||||
continue |
||||
endif |
||||
|
||||
for l:dummy in range(len(l:count)) |
||||
" create a pattern which isolates the old group text |
||||
let l:prevtext = s:qescape(l:groups[l:grp]) |
||||
let l:pattern = substitute(l:re_anchored, |
||||
\ g:matchup#re#not_bslash.'\\'.l:grp, |
||||
\ '\=''\zs\V'.l:prevtext.'\m\ze''', '') |
||||
let l:pattern = matchup#delim#fill_backrefs(l:pattern, |
||||
\ l:groups, 0) |
||||
let l:string = l:cur.groups[l:grp] |
||||
let l:line = substitute(l:line, l:pattern, |
||||
\ '\='''.s:qescape(l:string)."'", '') |
||||
endfor |
||||
|
||||
let l:groups[l:grp] = l:cur.groups[l:grp] |
||||
endfor |
||||
|
||||
if getline(l:corr.lnum) !=# l:line |
||||
if g:matchup_transmute_breakundo && l:num_changes == 0 |
||||
execute "normal! a\<c-g>u" |
||||
endif |
||||
call setline(l:corr.lnum, l:line) |
||||
let l:num_changes += 1 |
||||
endif |
||||
endfor |
||||
|
||||
return l:num_changes |
||||
endfunction |
||||
|
||||
function s:qescape(str) |
||||
return escape(substitute(a:str, "'", "''", 'g'), '\') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
" this file is loaded only from plugin/matchup.vim |
||||
|
||||
if !exists('g:loaded_matchup') |
||||
\ || !exists('g:loaded_matchit') |
||||
\ || !exists(":MatchDebug") |
||||
finish |
||||
endif |
||||
|
||||
unlet g:loaded_matchit |
||||
|
||||
delcommand MatchDebug |
||||
|
||||
silent! unmap % |
||||
silent! unmap [% |
||||
silent! unmap ]% |
||||
silent! unmap a% |
||||
silent! unmap g% |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,153 @@
@@ -0,0 +1,153 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
function! matchup#util#command(cmd) " {{{1 |
||||
let l:lines = '' |
||||
try |
||||
silent! redir => l:lines |
||||
silent! execute a:cmd |
||||
redir END |
||||
finally |
||||
return split(l:lines, '\n') |
||||
endtry |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#util#in_comment(...) " {{{1 |
||||
return call('matchup#util#in_syntax', ['^Comment$'] + a:000) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#in_string(...) " {{{1 |
||||
return call('matchup#util#in_syntax', ['^String$'] + a:000) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#in_comment_or_string(...) " {{{1 |
||||
return call('matchup#util#in_syntax', |
||||
\ ['^\%(String\|Comment\)$'] + a:000) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#in_syntax(name, ...) " {{{1 |
||||
" usage: matchup#util#in_syntax(name, [line, col]) |
||||
let l:pos = a:0 > 0 ? [a:1, a:2] : [line('.'), col('.')] |
||||
|
||||
" check syntax at position (same as matchit's s: method) |
||||
let l:syn = synIDattr(synID(l:pos[0], l:pos[1], 1), 'name') |
||||
return l:syn =~? a:name |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#in_whitespace(...) " {{{1 |
||||
let l:pos = a:0 > 0 ? [a:1, a:2] : [line('.'), col('.')] |
||||
return matchstr(getline(l:pos[0]), '\%'.l:pos[1].'c.') =~# '\s' |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#in_indent(...) " {{{1 |
||||
let l:pos = a:0 > 0 ? [a:1, a:2] : [line('.'), col('.')] |
||||
return l:pos[1] > 0 && getline(l:pos[0]) =~# '^\s*\%'.(l:pos[1]+1).'c' |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#util#uniq(list) " {{{1 |
||||
if exists('*uniq') | return uniq(a:list) | endif |
||||
if len(a:list) <= 1 | return a:list | endif |
||||
|
||||
let l:uniq = [a:list[0]] |
||||
for l:next in a:list[1:] |
||||
if l:uniq[-1] != l:next |
||||
call add(l:uniq, l:next) |
||||
endif |
||||
endfor |
||||
return l:uniq |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#uniq_unsorted(list) " {{{1 |
||||
if len(a:list) <= 1 | return a:list | endif |
||||
|
||||
let l:visited = [a:list[0]] |
||||
for l:index in reverse(range(1, len(a:list)-1)) |
||||
if index(l:visited, a:list[l:index]) >= 0 |
||||
call remove(a:list, l:index) |
||||
else |
||||
call add(l:visited, a:list[l:index]) |
||||
endif |
||||
endfor |
||||
return a:list |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#has_duplicate_str(list) " {{{1 |
||||
if len(a:list) <= 1 | return 0 | endif |
||||
let l:seen = {} |
||||
for l:elem in a:list |
||||
if has_key(l:seen, l:elem) |
||||
return 1 |
||||
endif |
||||
let l:seen[l:elem] = 1 |
||||
endfor |
||||
return 0 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#util#patch_match_words(from, to, ...) abort " {{{1 |
||||
if !exists('b:match_words') | return | endif |
||||
|
||||
" if extra argument is given, give diagnostic information |
||||
if a:0 |
||||
let l:first = stridx(b:match_words, a:from) |
||||
if l:first < 0 |
||||
echoerr 'match-up: patch_match_words:' a:from 'not found' |
||||
return |
||||
elseif stridx(b:match_words, a:from, l:first+1) > -1 |
||||
echoerr 'match-up: patch_match_words: multiple occurences of' a:from |
||||
return |
||||
endif |
||||
endif |
||||
|
||||
let b:match_words = substitute(b:match_words, |
||||
\ '\V'.escape(a:from, '\'), |
||||
\ escape(a:to, '\'), |
||||
\ '') |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#check_match_words(sha256) " {{{1 |
||||
if !exists('b:match_words') | return 0 | endif |
||||
return sha256(b:match_words) =~# '^'.a:sha256 |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! matchup#util#append_match_words(str) abort " {{{1 |
||||
if !exists('b:match_words') | return | endif |
||||
|
||||
if len(b:match_words) && b:match_words[-1] !=# ',' && a:str[0] !=# ',' |
||||
let b:match_words .= ',' |
||||
endif |
||||
let b:match_words .= a:str |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#util#matchpref(id, default) " {{{1 |
||||
return get(get(g:matchup_matchpref, &filetype, {}), a:id, a:default) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,156 @@
@@ -0,0 +1,156 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
scriptencoding utf8 |
||||
|
||||
let s:save_cpo = &cpo |
||||
set cpo&vim |
||||
|
||||
let s:curpos = [] |
||||
|
||||
function! matchup#where#get(timeout) abort " {{{1 |
||||
let l:save_view = winsaveview() |
||||
let l:trail = [] |
||||
|
||||
let l:prev = [matchup#pos#get_cursor_line(), 1] |
||||
call matchup#pos#set_cursor(l:prev) |
||||
for l:dummy in range(15) |
||||
" TODO make this into an api |
||||
" TODO replace with a faster version with searchpairpos/return value? |
||||
let l:opts_io = { |
||||
\ '__where_impl__': 1, |
||||
\ 'timeout': a:timeout, |
||||
\} |
||||
call matchup#motion#find_unmatched(0, 0, l:opts_io) |
||||
|
||||
if matchup#pos#get_cursor()[1:2] == l:prev |
||||
break |
||||
endif |
||||
|
||||
let l:prev = matchup#pos#get_cursor()[1:2] |
||||
call add(l:trail, l:prev + [l:opts_io.delim]) |
||||
endfor |
||||
|
||||
call winrestview(l:save_view) |
||||
return reverse(l:trail) |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! s:print_verbose() " {{{1 |
||||
echohl Title | echon 'match-up:' | echohl None |
||||
echon ' loading...' |
||||
let l:trail = matchup#where#get(500) |
||||
redraw! |
||||
if empty(l:trail) |
||||
echohl Title | echon 'match-up:' | echohl None |
||||
echon ' no context found' |
||||
return |
||||
endif |
||||
let l:last = -1 |
||||
for l:t in l:trail |
||||
let l:opts = { |
||||
\ 'noshowdir': 1, |
||||
\ 'width': &columns - 1, |
||||
\} |
||||
let [l:str, l:adj] = matchup#matchparen#status_str(l:t[2], l:opts) |
||||
if l:adj == l:last |
||||
continue |
||||
endif |
||||
if l:last != -1 |
||||
echon "\n" |
||||
endif |
||||
call s:EchoHLString(l:str) |
||||
let l:last = l:adj |
||||
endfor |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
function! s:print_short() " {{{1 |
||||
echohl Title | echon 'match-up:' | echohl None |
||||
echon ' loading...' |
||||
let l:trail = matchup#where#get(200) |
||||
redraw! |
||||
if empty(l:trail) |
||||
echohl Title | echon 'match-up:' | echohl None |
||||
echon ' no context found' |
||||
return |
||||
endif |
||||
" TODO len(trail) is not quite right here |
||||
let l:width = (&columns - 3*(len(l:trail)-1)) / len(l:trail) |
||||
let l:fullstr = '' |
||||
let l:prev = -1 |
||||
for l:t in l:trail |
||||
let l:opts = { |
||||
\ 'noshowdir': 1, |
||||
\ 'compact': l:prev != -1, |
||||
\ 'width': l:width, |
||||
\} |
||||
let [l:str, l:adj] = matchup#matchparen#status_str(l:t[2], l:opts) |
||||
if l:adj == l:prev |
||||
continue |
||||
endif |
||||
if l:prev != -1 |
||||
let l:fullstr .= ' %#Title#' . s:arrow() . '%#Normal# ' |
||||
endif |
||||
let l:fullstr .= l:str |
||||
let l:prev = l:adj |
||||
endfor |
||||
call matchup#perf#tic('where') |
||||
call s:EchoHLString(l:fullstr) |
||||
call matchup#perf#toc('where', 'echohlstring') |
||||
endfunction |
||||
|
||||
function! s:arrow() |
||||
if empty(g:matchup_where_separator) |
||||
return '▶' |
||||
endif |
||||
return g:matchup_where_separator |
||||
endfunction |
||||
|
||||
" }}}1 |
||||
|
||||
function! matchup#where#print(args) |
||||
let l:verbose = 0 |
||||
if a:args =~ '!' || len(a:args) >= 2 |
||||
\ || a:args =~ '?' && s:curpos == getcurpos() |
||||
let l:verbose = 1 |
||||
endif |
||||
let s:curpos = getcurpos() |
||||
|
||||
if l:verbose |
||||
call s:print_verbose() |
||||
else |
||||
call s:print_short() |
||||
endif |
||||
endfunction |
||||
|
||||
function! s:EchoHLString(str) |
||||
let l:str = '%<' . substitute(a:str, '%{[^}]\+}', '', 'g') |
||||
let l:pat = '\%(%\(<\)\|%#\(\w*\)#\)' |
||||
let l:components = split(l:str, l:pat.'\&') |
||||
call map(l:components, 'matchlist(v:val, "^".l:pat."\\(.*\\)")') |
||||
|
||||
for l:c in l:components |
||||
let l:m = matchlist(l:c, '^'.l:pat.'\(.*\)') |
||||
if empty(l:m) |
||||
let l:str = l:c |
||||
elseif !empty(l:m[1]) |
||||
let l:str = l:m[3] |
||||
echon l:m[2] |
||||
elseif !empty(l:m[2]) |
||||
let l:str = l:m[3] |
||||
execute 'echohl' l:m[2] |
||||
endif |
||||
echon l:str |
||||
endfor |
||||
echohl NONE |
||||
endfunction |
||||
|
||||
let &cpo = s:save_cpo |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
" vim match-up - even better matching |
||||
" |
||||
" Maintainer: Andy Massimino |
||||
" Email: a@normed.space |
||||
" |
||||
|
||||
if !get(g:, 'matchup_enabled', 1) || &cp |
||||
finish |
||||
endif |
||||
|
||||
if !get(g:, 'matchup_no_version_check', 0) |
||||
\ && !(v:version >= 704 || has('nvim-0.1.7')) |
||||
echoerr 'match-up does not support this version of vim' |
||||
finish |
||||
endif |
||||
|
||||
if !has('reltime') |
||||
echoerr 'match-up requires reltime()' |
||||
finish |
||||
endif |
||||
|
||||
if exists('g:loaded_matchup') |
||||
finish |
||||
endif |
||||
let g:loaded_matchup = 1 |
||||
|
||||
if exists('g:loaded_matchit') && exists(':MatchDebug') |
||||
runtime! autoload/matchup/unmatchit.vim |
||||
endif |
||||
let g:loaded_matchit = 1 |
||||
|
||||
" ensure pi_paren is loaded but deactivated |
||||
try |
||||
runtime plugin/matchparen.vim |
||||
au! matchparen |
||||
catch /^Vim\%((\a\+)\)\=:E216/ |
||||
unlet! g:loaded_matchparen |
||||
runtime plugin/matchparen.vim |
||||
silent! au! matchparen |
||||
let g:loaded_matchparen = 1 |
||||
endtry |
||||
command! NoMatchParen call matchup#matchparen#toggle(0) |
||||
command! DoMatchParen call matchup#matchparen#toggle(1) |
||||
|
||||
hi def link MatchParenCur MatchParen |
||||
hi def link MatchWord MatchParen |
||||
" hi def link MatchWordCur MatchParenCur |
||||
hi def link MatchBackground ColorColumn |
||||
|
||||
if get(g:, 'matchup_override_vimtex', 0) |
||||
let g:vimtex_matchparen_enabled = 0 |
||||
endif |
||||
|
||||
call matchup#init() |
||||
|
||||
" vim: fdm=marker sw=2 |
||||
|
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
|
||||
" rtp for testing files |
||||
|
||||
let s:path = expand('<sfile>:h') |
||||
let &rtp = s:path.'/rtp,' . &rtp |
||||
|
||||
runtime! ftdetect/matchuptest.vim |
||||
|
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
|
||||
foobar |
||||
|
||||
barfoo |
||||
|
||||
endfoobar |
||||
|
||||
" \<\(\(foo\)\(bar\)\):\3\2:end\1 |
||||
|
||||
" vim: set ft=matchuptest : |
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up |
||||
let s:path = simplify(expand('<sfile>:h').'/..') |
||||
let &rtp = s:path.',' . &rtp |
||||
let &rtp .= ','.s:path.'/after' |
||||
|
||||
" rtp for testing files |
||||
let &rtp = s:path.'/test/rtp,' . &rtp |
||||
|
||||
" load other plugins, if necessary |
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
|
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
if a:findstart |
||||
if exists('s:completer') | unlet s:completer | endif |
||||
|
||||
let l:pos = col('.') - 1 |
||||
let l:line = getline('.')[:l:pos-1] |
||||
for l:completer in s:completers |
||||
if !get(l:completer, 'enabled', 1) | continue | endif |
||||
|
||||
for l:pattern in l:completer.patterns |
||||
if l:line =~# l:pattern |
||||
let s:completer = l:completer |
||||
while l:pos > 0 |
||||
if l:line[l:pos - 1] =~# '{\|,\|\[\|\\' |
||||
\ || l:line[l:pos-2:l:pos-1] ==# ', ' |
||||
let s:completer.context = matchstr(l:line, '\S*$') |
||||
return l:pos |
||||
else |
||||
let l:pos -= 1 |
||||
endif |
||||
endwhile |
||||
return -2 |
||||
endif |
||||
endfor |
||||
endfor |
||||
return -3 |
||||
else |
||||
if !exists('s:completer') | return [] | endif |
||||
|
||||
return g:matchup_complete_close_braces && get(s:completer, 'inside_braces', 1) |
||||
\ ? s:close_braces(s:completer.complete(a:base)) |
||||
\ : s:completer.complete(a:base) |
||||
endif |
||||
|
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
|
||||
< highlight this | but not this > no cursor |
||||
|
||||
< mid this | not > no |
||||
|
||||
< end this | not > no |
||||
|
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
|
||||
if "(foo)" |
||||
|
||||
let x = "(foo)" |
||||
|
||||
endif |
||||
|
||||
( ) |
||||
|
||||
let x = ( "( )" ) |
||||
|
||||
let y = "(" |
||||
\ . ")" |
||||
|
||||
"(" |
||||
) |
||||
\ . ")" |
||||
|
||||
let z = ( '( ' ) . ' )' |
||||
|
||||
let a = " if endif " |
||||
*cpo-M* |
||||
M When excluded, "%" matching will take backslashes into |
||||
account. Thus in "( \( )" and "\( ( \)" the outer |
||||
parenthesis match. When included "%" ignores |
||||
backslashes, which is Vi compatible. |
||||
|
||||
let b = '\( \)' |
||||
let c = "\\( \\)" |
||||
|
||||
let d = "( \\( )" . "\\( " . '\( \)' . "\\)" |
||||
|
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
|
||||
function String() |
||||
|
||||
let output = filter(list, "matchstr(v:val, '^\s*\zsfoo\ze\\(bar\\|baz\\)')") |
||||
let output = filter(list, 'matchstr(v:val, ''^\s*\zsfoo\ze\(bar\|baz\)'')') |
||||
|
||||
endfunction |
||||
|
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
|
||||
\begin{equation} |
||||
\left\{ |
||||
\begin{aligned} |
||||
lhs1 &= rhs1 \\ |
||||
lhs2 &= rhs2 \\ |
||||
\end{aligned} |
||||
\right. |
||||
\end{equation} |
||||
|
||||
\left]a,b\right[ |
||||
\bigl]a,b\bigr] |
||||
\Bigl]a,b\Bigr] |
||||
\biggl]a,b\biggr] |
||||
\Biggl]a,b\Biggr] |
||||
|
||||
\left( \frac{a}{b} \middle| q \right) |
||||
|
||||
\begin{tabular}{@{} lr @{}} |
||||
\toprule |
||||
City & Population\\ |
||||
\midrule |
||||
Mexico City & 20,116,842\\ |
||||
Shanghai & 19,210,000\\ |
||||
Peking & 15,796,450\\ |
||||
Istanbul & 14,160,467\\ |
||||
\bottomrule |
||||
\end{tabular} |
||||
|
||||
\begin{itemize} |
||||
\item |
||||
... |
||||
\item |
||||
\end{itemize} |
||||
|
||||
\ifpdf |
||||
\DeclareGraphicsExtensions{.pdf,.jpg,.png} |
||||
\else |
||||
\DeclareGraphicsExtensions{.eps,.jpg,.png} |
||||
\fi |
||||
|
||||
\makeatletter |
||||
\makeatother |
||||
\begingroup ...\endgroup |
||||
|
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up (and commentary) |
||||
for s:loc in ['bundle', 'plugged'] |
||||
let &rtp = '~/.vim/'.s:loc.'/vim-matchup,' . &rtp |
||||
let &rtp .= ',~/.vim/'.s:loc.'/vim-matchup/after' |
||||
let &rtp = '~/.vim/'.s:loc.'/vim-commentary,' . &rtp |
||||
let &rtp .= ',~/.vim/'.s:loc.'/vim-commentary/after' |
||||
endfor |
||||
|
||||
" load other plugins, if necessary |
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
function! IsCommentaryOpFunc() |
||||
return &operatorfunc ==? matchstr(maparg('<Plug>Commentary', 'n'), |
||||
\ '\cset op\%(erator\)\?func=\zs.\{-\}\ze<cr>') |
||||
endfunction |
||||
|
||||
let g:matchup_text_obj_linewise_operators = ['d', 'y', |
||||
\ 'g@,IsCommentaryOpFunc()', 'V'] |
||||
|
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
function! s:test() |
||||
|
||||
let l:str = "hello" |
||||
|
||||
return l:str |
||||
|
||||
endfunction |
||||
|
||||
if condition |
||||
█call one() |
||||
call two() |
||||
endif |
||||
|
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up (and commentary) |
||||
for s:loc in ['bundle', 'plugged'] |
||||
let &rtp = '~/.vim/'.s:loc.'/vim-matchup,' . &rtp |
||||
let &rtp .= ',~/.vim/'.s:loc.'/vim-matchup/after' |
||||
let &rtp = '~/.vim/'.s:loc.'/vim-commentary,' . &rtp |
||||
let &rtp .= ',~/.vim/'.s:loc.'/vim-commentary/after' |
||||
endfor |
||||
|
||||
" load other plugins, if necessary |
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
let g:matchup_text_obj_linewise_operators = ['d', 'y', 'g@', ':'] |
||||
|
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
function! s:test() |
||||
|
||||
if l:x == 1 |
||||
if l:y == "hello andy" |
||||
echom "hello andy" " CURSOR |
||||
endif |
||||
call one() |
||||
else |
||||
call two() |
||||
elseif |
||||
call three() |
||||
endif |
||||
|
||||
let l:str = "hello" |
||||
|
||||
return l:str |
||||
|
||||
endfunction |
||||
|
||||
|
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
|
||||
function! Fcn() |
||||
" cursor 1 |
||||
if 0 |
||||
" cursor 2 |
||||
return |
||||
" cursor 3 |
||||
else |
||||
" cursor 4 |
||||
return |
||||
" cursor 5 |
||||
endif |
||||
" cursor 6 |
||||
endfunction |
||||
|
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
function! HtmlListHotfix() |
||||
call matchup#util#patch_match_words( |
||||
\ '<\@<=[ou]l\>[^>]*\%(>\|$\):<\@<=li\>:<\@<=/[ou]l>', |
||||
\ '') |
||||
endfunction |
||||
|
||||
let g:matchup_hotfix_html = 'HtmlListHotfix' |
||||
|
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
|
||||
let g:matchup_matchpref_html_nolists = 1 |
||||
|
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
|
||||
<ul class="btn-group"> |
||||
<li> |
||||
</li> |
||||
</ul> |
||||
|
@ -0,0 +1,402 @@
@@ -0,0 +1,402 @@
|
||||
{ |
||||
{ |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
a |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
} |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
a |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
} |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
a |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
{ |
||||
a |
||||
} |
||||
{ |
||||
a |
||||
b |
||||
b |
||||
b |
||||
b |
||||
b |
||||
b |
||||
b |
||||
b |
||||
{ |
||||
} |
||||
} |
||||
{ |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
a |
||||
} |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
class Example |
||||
def initialize |
||||
@text = 'for text' |
||||
@text2 = 'end text2' |
||||
@text3 = '( text )' |
||||
end |
||||
end |
||||
|
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
|
||||
function! SQLHotFix() |
||||
call matchup#util#patch_match_words( |
||||
\ '\%(\<create\s\+\%(or\s\+replace\s\+\)\?\)\?' |
||||
\ . '\%(function\|procedure\|event\)' |
||||
\ . ':\<returns\?\>', |
||||
\ '\%(\<create\s\+\%(or\s\+replace\s\+\)\?\)' |
||||
\ . '\%(function\|procedure\|event\)' |
||||
\ . ':\<returns\>' |
||||
\ . ':\<return\s\+\%(next\|query\)\>' |
||||
\ . ':\<return\>\ze\%(\s\+next\)\@!\%(.\|$\)' |
||||
\) |
||||
endfunction |
||||
|
||||
let g:matchup_hotfix_sql = 'SQLHotFix' |
||||
|
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
|
||||
<TooltipOverlay message="Remove"> |
||||
<Button onClick={deleteHandler} bsStyle="danger" baSize="xsmall"> |
||||
<i className="fa fa-remove text-danger-inverse" /> |
||||
</Button> |
||||
</TooltipOverlay> |
||||
|
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
|
||||
<tag class="something" attr="attr and class is nicely highlighted"> |
||||
item |
||||
</tag> |
||||
|
||||
<tag class="something" keyattr="attr and class has no highlight anymore"> |
||||
item |
||||
</tag> |
||||
|
||||
<ul class="something" keyattr="attr and class has no highlight anymore"> |
||||
<li class="something" keyattr="linebreaks">text</li> |
||||
</ul> |
||||
|
||||
<ul class="something" keyattr="attr and class has no highlight anymore"> |
||||
<li class="workaround" |
||||
keyattr="linebreaks">text</li> |
||||
</ul> |
||||
|
||||
<dl> |
||||
<dt class='list-item'>Question 1</dt> |
||||
</dl> |
||||
|
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
|
||||
<tag class="something" attr="attr and class is nicely highlighted"> |
||||
item |
||||
</tag> |
||||
|
||||
<tag class="something" keyattr="attr and class has no highlight anymore"> |
||||
item |
||||
</tag> |
||||
|
||||
<ul class="something" keyattr="attr and class has no highlight anymore"> |
||||
<li class="something" keyattr="linebreaks">text</li> |
||||
</ul> |
||||
|
||||
<ul class="something" keyattr="attr and class has no highlight anymore"> |
||||
<li class="workaround" |
||||
keyattr="linebreaks">text</li> |
||||
</ul> |
||||
|
||||
<dl> |
||||
<dt class='list-item'>Question 1</dt> |
||||
</dl> |
||||
|
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up |
||||
let s:path = simplify(expand('<sfile>:h').'/../../..') |
||||
let &rtp = s:path.',' . &rtp |
||||
let &rtp .= ','.s:path.'/after' |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
let g:matchup_matchpref = { |
||||
\ 'html': { 'tagnameonly': 1, }, |
||||
\ 'vue': { 'tagnameonly': 1, }, |
||||
\} |
||||
|
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up |
||||
let &rtp = '~/.vim/bundle/vim-matchup,' . &rtp |
||||
let &rtp .= ',~/.vim/bundle/vim-matchup/after' |
||||
|
||||
" load other plugins, if necessary |
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp |
||||
|
||||
set ignorecase " Case insensitive search |
||||
set hlsearch " Highlight search results |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
|
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
require 'yaml' |
||||
require 'aws-sdk' |
||||
|
||||
class Time |
||||
COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31].freeze |
||||
|
||||
class << self |
||||
def days_in_month(month, year) |
||||
if month == 2 && ::Date.gregorian_leap?(year) |
||||
29 |
||||
else |
||||
COMMON_YEAR_DAYS_IN_MONTH[month] |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
module LoremIpsum |
||||
class Lorem < Ipsum |
||||
def test |
||||
lorem_ipsum = Aws::Credentials.new(@config[:lorem_ipsum][:dolor_sit], @config[:amet][:consectetur]) |
||||
@adipiscing = @config[:elit][:sed] |
||||
@do = Aws::S3::Client.new(:region => @config[:eiusmod][:tempor], :credentials => lorem_ipsum) |
||||
@incididunt = Aws::S3::Bucket.new(@adipiscing , client: @do) |
||||
@ut = @config[:labore][:et] |
||||
@dolore = /#{@config[:magna]}/ |
||||
@aliqua = /#{@config[:ut]}/ |
||||
@enim = @config[:ad] || false |
||||
@minim = @config[:veniam].nil? ? :quis: @config[:nostrud].to_sym |
||||
@exercitation = @config[:ullamco] |
||||
@laboris = (@config[:nisi] || 0) * 60 |
||||
@ut = @config[:aliquip] || false |
||||
@ex = @config[:ea] || false |
||||
|
||||
dolor = {:region => @config[:ex][:ea], |
||||
:access_key_id => @config[:commodo][:consequat], |
||||
:secret_access_key => @config[:duis][:aute]} |
||||
@irure = Aws::S3::Client.new(dolor) |
||||
|
||||
@reprehenderit = @config[:in][:voluptate] |
||||
@velit = Aws::S3::Bucket.new(@esse, client: @cillum) |
||||
@dolore = @config[:eu][:fugiat] |
||||
@nulla = @config[:pariatur] |
||||
|
||||
@excepteur = @config[:velit][:esse] |
||||
@cillum = Aws::S3::Bucket.new(@dolore, client: @eu) |
||||
@fugiat = @config[:nulla][:pariatur] |
||||
|
||||
if (@config[:excepteur]) |
||||
sint(@config[:occaecat]) |
||||
elsif (@config[:cupidatat]) |
||||
non(@config[:proident]) |
||||
else |
||||
throw "sunt" |
||||
end |
||||
|
||||
@in = Aws::EMR::Client.new(culpa) |
||||
|
||||
@qui = @config[:officia][:deserunt] |
||||
|
||||
@mollit = @config[:anim] |
||||
|
||||
@id = @config[:est][:laborum] |
||||
end |
||||
end |
||||
end |
||||
|
||||
LoremIpsum::Lorem.test if __FILE__ == $0 |
||||
|
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
|
||||
function! s:InNumber() abort |
||||
let l:line = getline('.') |
||||
let l:col = col('.') - 1 |
||||
" virtcol for start of number |
||||
let l:start = l:col |
||||
" virtcol for last character in number |
||||
let l:end = l:col |
||||
if (l:line[l:col:] !~# '\d') |
||||
return |
||||
endif |
||||
if (l:line[l:col] !~# '\d') |
||||
" number in rest of line (not under cursor) |
||||
let l:curCol = l:col + 1 " current column in for loop |
||||
" while this might be confusing, it should work. Temporarily store the |
||||
" length of l:line into l:end. Use this for the break condition for the |
||||
" loop below. If th |
||||
let l:end = len(l:line) |
||||
" find the first number in rest of line |
||||
" for l:ch in l:line[l:curCol:] |
||||
while l:curCol < l:end |
||||
let l:ch = l:line[l:curCol] |
||||
if (l:ch =~# '\d') |
||||
if (l:start !=# l:col) |
||||
" l:start was not set yet, and current char is a number |
||||
let l:start = l:curCol |
||||
endif |
||||
else |
||||
if (l:start !=# l:col) |
||||
" l:start was changed, and current char is not a number; |
||||
" if this condition is never true, then l:start and l:end |
||||
" were both already set to the correct values |
||||
let l:end = l:curCol - 1 |
||||
break |
||||
endif |
||||
endif |
||||
endwhile |
||||
let l:curCol += 1 |
||||
else |
||||
" number is under cursor |
||||
" iterate backwards over all characters from 0 to l:curCol-1 in order to |
||||
" find l:start |
||||
let l:start = 0 |
||||
let l:curCol = l:col - 1 |
||||
" for l:ch in join(reverse(split(l:line[:l:curCol], '.\zs'))) |
||||
while (l:curCol >= 0) |
||||
let l:ch = l:line[l:curCol] |
||||
if (l:ch !~# '\d') |
||||
" current char is not a number; |
||||
" if this condition is never true, then l:start was set to the |
||||
" correct value anyway |
||||
let l:start = l:curCol + 1 |
||||
break |
||||
endif |
||||
let l:curCol -= 1 |
||||
endwhile |
||||
" iterate forwards over all characters from l:curCol+1 to $ in order to |
||||
" find l:end |
||||
let l:end = len(l:line) |
||||
let l:curCol = l:col + 1 |
||||
" for l:ch in l:line[l:curCol:] |
||||
while l:curCol < l:end |
||||
let l:ch = l:line[l:curCol] |
||||
if (l:ch !~# '\d') |
||||
" current char is not a number; |
||||
" if this condition is never true, then l:end was set to the |
||||
" correct value anyway |
||||
let l:end = l:curCol - 1 |
||||
break |
||||
endif |
||||
endwhile |
||||
endif |
||||
" finally, just select the appropriate region on the line |
||||
execute 'normal! '.l:start.'|v'.l:end.'|' |
||||
endfunction |
||||
|
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
return unless original_filename |
||||
|
||||
if model && model.read_attribute(mounted_as).present? |
||||
model.read_attribute(mounted_as) |
||||
else |
||||
"#{SecureRandom.hex(5)}.#{file.extension}" |
||||
end |
||||
end |
||||
|
||||
def store_dir |
||||
"u/#{model.user_id}/#{model.id}" |
||||
end |
||||
|
||||
def extension_whitelist |
||||
%w[jpg jpeg png] |
||||
end |
||||
|
||||
version :thumb do |
||||
process resize_to_fit: [150, 150] |
||||
end |
||||
end |
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
|
||||
const Sample = <Sample prop='highlight test'> |
||||
some body |
||||
</Sample>; |
||||
|
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up |
||||
let s:path = simplify(expand('<sfile>:h').'/../../..') |
||||
let &rtp = s:path.',' . &rtp |
||||
let &rtp .= ','.s:path.'/after' |
||||
|
||||
autocmd FileType * echo &ft | sleep 1 |
||||
|
||||
call plug#begin('~/.vim/plugged') |
||||
Plug 'mxw/vim-jsx' |
||||
Plug 'othree/yajs.vim' |
||||
Plug 'othree/es.next.syntax.vim' |
||||
call plug#end() |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
function! JsxHotfix() |
||||
echo 'JsxHotfix' |
||||
setlocal matchpairs=(:),{:},[:],<:> |
||||
let b:match_words = '<\@<=\([^/][^ \t>]*\)\g{hlend}[^>]*\%(/\@<!>\|$\):<\@<=/\1>' |
||||
endfunction |
||||
let g:matchup_hotfix = { 'javascript.jsx': 'JsxHotfix' } |
||||
|
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up |
||||
let s:path = simplify(expand('<sfile>:h').'/../../..') |
||||
let &rtp = s:path.',' . &rtp |
||||
let &rtp .= ','.s:path.'/after' |
||||
|
||||
autocmd FileType * echo &ft | sleep 1 |
||||
|
||||
call plug#begin('~/.vim/plugged') |
||||
Plug 'mxw/vim-jsx' |
||||
Plug 'othree/yajs.vim' |
||||
Plug 'othree/es.next.syntax.vim' |
||||
call plug#end() |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
function! JsxHotfix() |
||||
echo 'JsxHotfix' |
||||
setlocal matchpairs=(:),{:},[:],<:> |
||||
let b:match_words = '<\@<=\([^/][^ \t>]*\)\g{hlend}[^>]*\%(/\@<!>\|$\):<\@<=/\1>' |
||||
endfunction |
||||
autocmd FileType javascript.jsx let b:matchup_hotfix = 'JsxHotfix' |
||||
|
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up |
||||
let s:path = simplify(expand('<sfile>:h').'/../../..') |
||||
let &rtp = s:path.',' . &rtp |
||||
let &rtp .= ','.s:path.'/after' |
||||
|
||||
" rtp for testing files |
||||
let &rtp = s:path.'/test/rtp,' . &rtp |
||||
|
||||
" load other plugins, if necessary |
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
hi MatchParen ctermfg=blue ctermbg=NONE |
||||
let g:matchup_transmute_enabled = 1 |
||||
|
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
<variable>x</variable> |
||||
|
||||
<action>a ''</action> |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
<root> |
||||
<blue> |
||||
</blue> |
||||
<red> |
||||
</red> |
||||
|
||||
<green> |
||||
</green> |
||||
</root> |
||||
|
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
<window title="App" icon-name="app" resizable="false" window-position="1"> |
||||
<vbox> |
||||
<text justify="0"> |
||||
<label>" App not found TODO "</label> |
||||
</text> |
||||
|
||||
<checkbox use-underline="true"> |
||||
<label>"_Show this message at next start"</label> |
||||
<default>$CHECK_FZF</default> |
||||
<variable>CHECK_FZF</variable> |
||||
<action>awk $0~"^"N"="{$0=N"="V;f=1}{a[++n]=$0}END{if(!f)a[++n]=N"="V;++n;for(i=1;i!=n;i++)print a[i]>ARGV[ARGC-1]} N=CHECK_FZF V=\$CHECK_FZF /root/.apprc</action> |
||||
</checkbox> |
||||
|
||||
<text><label>""</label></text> |
||||
<hbox> |
||||
<text space-fill="true" space-expand="true"><label>""</label></text> |
||||
<button yes> |
||||
<action>yad --text="INSTALL FZF TODO"</action> |
||||
</button> |
||||
<button no> |
||||
<action>closewindow:CHECK_FZF_WINDOW</action> |
||||
</button> |
||||
<text space-fill="true" space-expand="true"><label>""</label></text> |
||||
</hbox> |
||||
</vbox> |
||||
<variable>CHECK_FZF_WINDOW</variable> |
||||
<action signal="key-press-event" condition="command_is_true([ $KEY_SYM = Escape ] && echo true )">closewindow:CHECK_FZF_WINDOW</action> |
||||
</window> |
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
source ../../bootstrap.vim |
||||
|
||||
call matchup#custom#define_motion('nox', '%', |
||||
\ 'matchup#custom#example_motion', { 'down': 1 }) |
||||
call matchup#custom#define_motion('nox', 'g%', |
||||
\ 'matchup#custom#example_motion', { 'down': 0 }) |
||||
|
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
# `%` jumps to fi |
||||
if test -z ""; then |
||||
echo "cursor_position" |
||||
else |
||||
true |
||||
fi |
||||
|
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
program ifElseIfElseProg |
||||
implicit none |
||||
|
||||
integer :: a = 100 |
||||
|
||||
if( a == 10 ) then |
||||
|
||||
a = a + 1 |
||||
#ifdef three_d |
||||
+ 3 |
||||
#endif |
||||
|
||||
else if( a == 20 ) |
||||
& then |
||||
print*, "Value of a is 20" |
||||
|
||||
else if( a == 30 ) then |
||||
|
||||
print*, "Value of a is 30" |
||||
|
||||
else |
||||
|
||||
print*, "None of the values is matching" |
||||
|
||||
end if |
||||
|
||||
print*, "exact value of a is ", a |
||||
|
||||
end program ifElseIfElseProg |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
function! Foo(var, func) |
||||
return a:func(a:var) |
||||
endfunction |
||||
|
||||
function! Foo(list, var) |
||||
return sort(a:list, s:function('a:var')) |
||||
endfunction |
||||
|
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
source ../../bootstrap.vim |
||||
|
||||
xmap u% <plug>(matchup-i%) |
||||
omap u% <plug>(matchup-i%) |
||||
|
||||
" optional, for use without patch 8.1.0648 |
||||
call call(matchup#motion_sid().'make_oldstyle_omaps', ['u%', 'i%']) |
||||
|
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
program matchup_parsing |
||||
real :: x = 1.0, y = 2.0, a |
||||
|
||||
|
||||
if (x < y) then |
||||
if (x == 0) stop |
||||
a = y / x |
||||
else |
||||
if (y == 0) stop ! matchup sees corresponding `if - end if` pairs from HERE |
||||
a = x / y |
||||
end if ! to HERE |
||||
|
||||
write(*, *) a |
||||
|
||||
end program |
||||
|
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD, |
||||
FunctionDecl *ToFD) { |
||||
if (Stmt *FromBody = FromFD->getBody()) { |
||||
if (ExpectedStmt ToBodyOrErr = import(FromBody)) |
||||
ToFD->setBody(*ToBodyOrErr); |
||||
else |
||||
return ToBodyOrErr.takeError(); |
||||
} |
||||
return Error::success(); |
||||
} |
||||
|
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
|
||||
function! CppTemplate() |
||||
call matchup#util#append_match_words( |
||||
\ '\%(\s\@<!<\|<\s\@!\)=\@!:\%(\s\@<!>\|>\s\@!\)=\@!') |
||||
endfunction |
||||
if !exists('g:matchup_hotfix') |
||||
let g:matchup_hotfix = {} |
||||
endif |
||||
let g:matchup_hotfix.cpp = 'CppTemplate' |
||||
set matchpairs-=<:> |
||||
|
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::conditional< |
||||
boost::is_signed<no_cvr_prefinal_t>::value, |
||||
boost::make_signed<no_cvr_prefinal_t>, |
||||
boost::type_identity<no_cvr_prefinal_t> |
||||
>::type no_cvr_prefinal_lazy_t; |
||||
|
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
|
||||
augroup nomatchparen |
||||
autocmd! |
||||
autocmd VimEnter * NoMatchParen |
||||
augroup END |
||||
|
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
function! AugroupHotfix() |
||||
call matchup#util#patch_match_words( |
||||
\ '\<aug\%[roup]\s\+\%(END\>\)\@!\S:', |
||||
\ '\<aug\%[roup]\s\+\%(END\>\)\@!\S\+:') |
||||
endfunction |
||||
|
||||
let g:matchup_hotfix_vim = 'AugroupHotfix' |
||||
|
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
function! AugroupHotfix() |
||||
call matchup#util#patch_match_words( |
||||
\ '\<aug\%[roup]\s\+\%(END\>\)\@!\S:', |
||||
\ '\<aug\%[roup]\s\+\%(END\>\)\@!\S\@=:') |
||||
endfunction |
||||
|
||||
let g:matchup_hotfix_vim = 'AugroupHotfix' |
||||
|
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
|
||||
<Flex justify="between" style={[tableStyle.mainWrapper, tableStyle.noData]}> |
||||
<FlexItem flex> |
||||
<ActivityIndicator animating size="large"/> |
||||
<Text style={tableStyle.noDataText}>数据加载中。。。</Text> |
||||
</FlexItem> |
||||
</Flex> |
||||
|
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
|
||||
<Flex> |
||||
<FlexItem flex> |
||||
</FlexItem> |
||||
</Flex> |
||||
|
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
|
||||
function! HTMLHotFix() |
||||
let b:match_words = '<:>,' . |
||||
\ '<\@<=[ou]l\>[^>]*\%(>\|$\):<\@<=li\>:<\@<=/[ou]l>,' . |
||||
\ '<\@<=dl\>[^>]*\%(>\|$\):<\@<=d[td]\>:<\@<=/dl>,' . |
||||
\ '<\@<=\([^/][^ \t>]*\)[^>]*\%(>\|$\):<\@<=/\1>' |
||||
|
||||
call matchup#util#patch_match_words( |
||||
\ '<\@<=\([^/][^ \t>]*\)[^>]*\%(>\|$\):<\@<=/\1>', |
||||
\ '<\@<=\([^/][^ \t>]*\)\%(/\@<!>\|$\|[ \t][^>]*\%(/\@<!>\|$\)\):<\@<=/\1>' |
||||
\) |
||||
|
||||
" call matchup#util#patch_match_words( |
||||
" \ '<\@<=\([^/][^ \t>]*\)[^>]*\%(>\|$\):<\@<=/\1>', |
||||
" \ '<\@<=\([^/][^ \t>]*\)\%(>\|$\|[ \t][^>]*\%(>\|$\)\):<\@<=/\1>' |
||||
" \) |
||||
|
||||
endfunction |
||||
|
||||
|
||||
let g:matchup_hotfix_html = 'HTMLHotFix' |
||||
|
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
|
||||
<div>hello world</div> |
||||
<div />hello world</div> |
||||
|
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
-- Converts Lua table to HTML output in table.html file |
||||
function tohtml(x) |
||||
ret = tohtml_table(x,1) |
||||
writefile("table.html", ret) |
||||
os.execute("table.html") |
||||
return(ret) |
||||
end |
||||
|
||||
-- Saves a string to file |
||||
function writefile(filename, value) |
||||
if (value) then |
||||
local file = io.open(filename,"w+") |
||||
file:write(value) |
||||
file:close() |
||||
end |
||||
end |
||||
|
||||
function tohtml_table(x, table_level) |
||||
local k, s, tcolor |
||||
local html_colors = { |
||||
"#339900","#33CC00","#669900","#666600","#FF3300", |
||||
"#FFCC00","#FFFF00","#CCFFCC","#CCCCFF","#CC66FF", |
||||
"#339900","#33CC00","#669900","#666600","#FF3300", |
||||
"#FFCC00","#FFFF00","#CCFFCC","#CCCCFF","#CC66FF" |
||||
} |
||||
local lineout = {} |
||||
local tablefound = false |
||||
if type(x) == "table" then |
||||
s = "" |
||||
k = 1 |
||||
local i, v = next(x) |
||||
while i do |
||||
if (type(v) == "table") then |
||||
if (table_level<10) then |
||||
lineout[k] = "<b>" .. flat(i) .. "</b>".. tohtml_table(v, table_level + 1) |
||||
else |
||||
lineout[k] = "<b>MAXIMUM LEVEL BREACHED</b>" |
||||
end |
||||
tablefound = true |
||||
else |
||||
lineout[k] = flat(i) .. "=" .. tohtml_table(v) |
||||
end |
||||
k = k + 1 |
||||
i, v = next(x, i) |
||||
end |
||||
|
||||
for k,line in ipairs(lineout) do |
||||
if (tablefound) then |
||||
s = s .. "<tr><td>" .. line .. "</td></tr>\n" |
||||
else |
||||
s = s .. "<td>" .. line .. "</td>\n" |
||||
end |
||||
end |
||||
if not (tablefound) then |
||||
s = "<table border='1' bgcolor='#FFFFCC' cellpadding='5' cellspacing='0'>" .. |
||||
"<tr>" .. s .. "</tr></table>\n" |
||||
else |
||||
tcolor = html_colors[table_level] |
||||
s = "<table border='3' bgcolor='"..tcolor.."' cellpadding='10' cellspacing='0'>" .. |
||||
s .. "</table>\n" |
||||
end |
||||
|
||||
return s |
||||
end |
||||
if type(x) == "function" then |
||||
return "FUNC" |
||||
end |
||||
if type(x) == "file" then |
||||
return "FILE" |
||||
end |
||||
|
||||
return tostring(x) |
||||
end |
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
for i in 0..5 |
||||
if i < 2 then |
||||
next |
||||
else |
||||
end |
||||
puts "Value of local variable is #{i}" |
||||
end |
||||
|
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up |
||||
let &rtp = '~/.vim/bundle/vim-matchup,' . &rtp |
||||
let &rtp .= ',~/.vim/bundle/vim-matchup/after' |
||||
|
||||
" rtp for testing files |
||||
let &rtp = '~/.vim/bundle/vim-matchup/test/rtp,' . &rtp |
||||
|
||||
" load other plugins, if necessary |
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
" match-up options go here |
||||
|
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
if l:x == 1 |
||||
call one() |
||||
else |
||||
call two() |
||||
elseif |
||||
call three() |
||||
endif |
||||
|
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
( |
||||
dib |
||||
dvib |
||||
dVib |
||||
) |
||||
---- |
||||
|
||||
{ |
||||
|
||||
{ |
||||
|
||||
a nested |
||||
block |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
( |
||||
|
||||
( |
||||
|
||||
another nested block |
||||
L |
||||
) |
||||
L |
||||
) |
||||
|
||||
( |
||||
|
||||
|
||||
|
||||
) |
||||
|
||||
( hello |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
) |
||||
|
||||
(vibd) |
||||
(dvib) |
||||
(dib) |
||||
() |
||||
|
||||
---- |
||||
( |
||||
something |
||||
|
||||
| ) |
||||
---- |
||||
|
||||
block = ( 1, |
||||
2, |
||||
3, ); |
||||
|
||||
( (( ) )) |
||||
|
||||
( |
||||
hello |
||||
|
||||
) | |
||||
|
||||
( |
||||
( empty |
||||
|
||||
|
||||
) |
||||
) |
||||
( |
||||
|
||||
bye ) |
||||
|
||||
{ { hello |
||||
|
||||
|
||||
} } | |
||||
|
||||
|
||||
---- |
||||
( ( (( )) ) ) |
||||
---- |
||||
|
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) |
||||
|
||||
|
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
function |
||||
return |
||||
|
||||
break |
||||
endwhile |
||||
|
||||
|
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
autocmd BufNewFile,BufRead *.matchuptest setlocal filetype=matchuptest |
||||
|
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
|
||||
" Only do this when not done yet for this buffer |
||||
if exists("b:did_ftplugin") |
||||
finish |
||||
endif |
||||
|
||||
" Don't load another plugin for this buffer |
||||
let b:did_ftplugin = 1 |
||||
|
||||
let s:cpo_save = &cpo |
||||
set cpo-=C |
||||
|
||||
" Let the matchit plugin know what items can be matched. |
||||
if exists("loaded_matchit") |
||||
let b:match_ignorecase = 0 |
||||
" let b:match_words = |
||||
" \ '\<fu\%[nction]\>:\<retu\%[rn]\>:\<endf\%[unction]\>,' . |
||||
" \ '\<\(wh\%[ile]\|for\)\>:\<brea\%[k]\>:\<con\%[tinue]\>:\<end\(w\%[hile]\|fo\%[r]\)\>,' . |
||||
" \ '\<if\>:\<el\%[seif]\>:\<en\%[dif]\>,' . |
||||
" \ '\<try\>:\<cat\%[ch]\>:\<fina\%[lly]\>:\<endt\%[ry]\>,' . |
||||
" \ '\<aug\%[roup]\s\+\%(END\>\)\@!\S:\<aug\%[roup]\s\+END\>,' . |
||||
" \ '(:)' |
||||
|
||||
" very tricky examples: |
||||
" bad: let b:match_words = '\(foo\)\(bar\):more\1:and\2:end\1\2' |
||||
" good: |
||||
let b:match_words = '\<\(\(foo\)\(bar\)\):\3\2:end\1' |
||||
let b:match_words .= ',\<baz\zebar\>:\<barbaz\>' |
||||
let b:match_words .= ',\<zab\zsrab\>:\<rabzab\>' |
||||
let b:match_words .= ',\<where\>:\<wh\zeen\>' |
||||
let b:match_words .= ',\%(end\)\@<!むめ:endむめも' |
||||
let b:match_words .= ',ぽ:も' |
||||
let b:match_words .= ',\\begin{\([^}]\+\)}:\\end{\1}' |
||||
let b:match_words .= ',one😀🐑one:two😐🐑two:three🙁🐑' |
||||
let b:match_words .= ',muopen:mumidone:mumidtwo:mumidthree:muclose' |
||||
let b:match_words .= ',op\ten:mi\td:cl\tose' |
||||
let b:match_words .= ',so👔me\zething:t\t👕t\zemid:e👖\te\zeend' |
||||
let b:match_words .= ',< highlight \(\w\+\)\g{hlend} | but not this >\ze no cursor:< mid \1\g{hlend} | not >\ze no:< end \1\g{hlend} | not >\ze no' |
||||
let b:match_words .= ',\\word{\(.\{-}\)}:\\endword{\1}' |
||||
|
||||
let b:match_skip = 'synIDattr(synID(line("."),col("."),1),"name") |
||||
\ =~? "comment\\|string\\|vimSynReg\\|vimSet"' |
||||
endif |
||||
|
||||
let &cpo = s:cpo_save |
||||
unlet s:cpo_save |
||||
|
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash |
||||
|
||||
VISUAL=${VISUAL:-vim} |
||||
|
||||
cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd |
||||
|
||||
dir='profile' |
||||
mkdir -vp "$dir" |
||||
|
||||
file="$dir/startup-$(date +%Y-%m-%d.%H:%M:%S)" |
||||
file1="$file-1.log" |
||||
file2="$file-2.log" |
||||
|
||||
"$VISUAL" -u vimrc-startup --startuptime "$file1" |
||||
|
||||
echo 'g:matchup_delim_start_plaintext=0' |
||||
grep matchup "$file1" |
||||
|
||||
export TEST_PLAIN=1 |
||||
"$VISUAL" -u vimrc-startup --startuptime "$file2" |
||||
|
||||
echo 'g:matchup_delim_start_plaintext=1' |
||||
grep matchup "$file2" |
||||
|
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
|
||||
for l:pattern in l:completer.patterns |
||||
if l:line =~# l:pattern |
||||
let s:completer = l:completer |
||||
while l:pos > 0 |
||||
if l:line[l:pos - 1] =~# '{\|,\|\[\|\\' |
||||
\ || l:line[l:pos-2:l:pos-1] ==# ', ' |
||||
let s:completer.context = matchstr(l:line, '\S*$') |
||||
return l:pos |
||||
else |
||||
let l:pos -= 1 |
||||
endif |
||||
endwhile |
||||
return -2 |
||||
endif |
||||
endfor |
||||
|
||||
|
||||
|
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<title>Title of the document</title> |
||||
</head> |
||||
|
||||
<body> |
||||
Content of the document...... |
||||
</body> |
||||
|
||||
</html> |
||||
|
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
|
||||
while 1 |
||||
if l:x == 1 |
||||
echo 'one' |
||||
else |
||||
echo 'two' |
||||
elseif |
||||
echo 'three' |
||||
endif |
||||
endwhile |
||||
|
||||
if l:x == 1 |
||||
echo 'one' |
||||
else |
||||
echo 'two' |
||||
elseif |
||||
echo 'three' |
||||
endif |
||||
|
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
|
||||
<sometag> |
||||
|
||||
</sometag> |
||||
|
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<title>Title of the document</title> |
||||
</head> |
||||
|
||||
<boody> |
||||
<budy> |
||||
|
||||
<body> |
||||
Content of the document...... |
||||
</body> |
||||
|
||||
</budy> |
||||
</boody> |
||||
|
||||
</html> |
||||
|
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
ぽ |
||||
|
||||
もぎ | |
||||
|
||||
ぽ |
||||
|
||||
も ぎ |
||||
|
||||
ぽ |
||||
むめ |
||||
|
||||
endむめも |
||||
|
||||
むめ |
||||
|
||||
ぽendむめも |
||||
|
||||
ぽむめ |
||||
|
||||
endむめも |
||||
|
||||
\begin{🍩🍩🍩} |
||||
|
||||
\end{🍩🍩🍩} |
||||
|
||||
one😀🐑one |
||||
two😐🐑two |
||||
three🙁🐑foo |
||||
|
||||
hi MatchParen cterm=strikethrough |
||||
|
||||
" vim: set ft=matchuptest : |
@ -0,0 +1,104 @@
@@ -0,0 +1,104 @@
|
||||
Given vim (Parentheses): |
||||
if l:x == 1 |
||||
call one() |
||||
elseif l:x == 2 |
||||
call two() |
||||
elseif l:x == 3 |
||||
call three() |
||||
elseif l:x == 4 |
||||
call four() |
||||
elseif l:x == 5 |
||||
call five() |
||||
elseif l:x == 6 |
||||
call six() |
||||
elseif l:x == 7 |
||||
call seven() |
||||
elseif l:x == 8 |
||||
call eight() |
||||
else |
||||
call none() |
||||
endif |
||||
|
||||
Do (Delete 3 inner %): |
||||
7gg |
||||
d3i% |
||||
|
||||
Expect vim (Verify): |
||||
if l:x == 1 |
||||
call one() |
||||
elseif l:x == 2 |
||||
call two() |
||||
elseif l:x == 3 |
||||
call three() |
||||
elseif l:x == 4 |
||||
call four() |
||||
elseif l:x == 5 |
||||
call five() |
||||
elseif l:x == 6 |
||||
call six() |
||||
elseif l:x == 7 |
||||
call seven() |
||||
elseif l:x == 8 |
||||
call eight() |
||||
else |
||||
call none() |
||||
endif |
||||
|
||||
Do (Delete 3 inner %, with blank first line): |
||||
ggO\<esc> |
||||
7gg |
||||
d3i% |
||||
|
||||
Expect vim (Verify): |
||||
|
||||
if l:x == 1 |
||||
call one() |
||||
elseif l:x == 2 |
||||
call two() |
||||
elseif l:x == 3 |
||||
call three() |
||||
elseif l:x == 4 |
||||
call four() |
||||
elseif l:x == 5 |
||||
call five() |
||||
elseif l:x == 6 |
||||
call six() |
||||
elseif l:x == 7 |
||||
call seven() |
||||
elseif l:x == 8 |
||||
call eight() |
||||
else |
||||
call none() |
||||
endif |
||||
|
||||
Do (Delete inner %): |
||||
7gg |
||||
di% |
||||
|
||||
Expect vim (Verify): |
||||
if l:x == 1 |
||||
call one() |
||||
elseif l:x == 2 |
||||
call two() |
||||
elseif l:x == 3 |
||||
elseif l:x == 4 |
||||
call four() |
||||
elseif l:x == 5 |
||||
call five() |
||||
elseif l:x == 6 |
||||
call six() |
||||
elseif l:x == 7 |
||||
call seven() |
||||
elseif l:x == 8 |
||||
call eight() |
||||
else |
||||
call none() |
||||
endif |
||||
|
||||
Do (Delete 1 inner %): |
||||
7gg |
||||
d1i% |
||||
|
||||
Expect vim (Verify): |
||||
if l:x == 1 |
||||
endif |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
set nocompatible |
||||
|
||||
" load match-up |
||||
let s:path = simplify(expand('<sfile>:h').'/../..') |
||||
let &rtp = s:path.',' . &rtp |
||||
let &rtp .= ',vader.vim' |
||||
let &rtp .= ','.s:path.'/after' |
||||
|
||||
" rtp for testing files |
||||
let &rtp = s:path.'/test/rtp,' . &rtp |
||||
|
||||
" load other plugins, if necessary |
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp |
||||
|
||||
if empty(globpath(&rtp, 'plugin/vader.vim')) |
||||
echoerr 'vader not found' |
||||
exit! |
||||
endif |
||||
|
||||
filetype plugin indent on |
||||
syntax enable |
||||
|
||||
set notimeout |
||||
|
||||
" match-up options go here |
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue