Browse Source

vim: plugins: matchin -> vim-matchup

Maxim Likhachev 5 years ago
parent
commit
b249ef2b4e
  1. 23
      etc/soft/nvim/+plugins/vim-matchup/LICENSE.md
  2. 780
      etc/soft/nvim/+plugins/vim-matchup/README.md
  3. 16
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/c_matchup.vim
  4. 25
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/cpp_matchup.vim
  5. 25
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/fortran_matchup.vim
  6. 44
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/html_matchup.vim
  7. 22
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/lua_matchup.vim
  8. 15
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ocaml_matchup.vim
  9. 25
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ruby_matchup.vim
  10. 117
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/tex_matchup.vim
  11. 27
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vim_matchup.vim
  12. 10
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vue_matchup.vim
  13. 22
      etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/xml_matchup.vim
  14. 0
      etc/soft/nvim/+plugins/vim-matchup/after/plugin/matchit.vim
  15. 362
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup.vim
  16. 152
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/custom.vim
  17. 918
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/delim.vim
  18. 721
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/loader.vim
  19. 953
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/matchparen.vim
  20. 27
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/misc.vim
  21. 313
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/motion.vim
  22. 117
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/perf.vim
  23. 143
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/pos.vim
  24. 52
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/quirks.vim
  25. 23
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/re.vim
  26. 83
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/surround.vim
  27. 296
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/text_obj.vim
  28. 146
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/transmute.vim
  29. 26
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/unmatchit.vim
  30. 153
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/util.vim
  31. 156
      etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/where.vim
  32. 1072
      etc/soft/nvim/+plugins/vim-matchup/doc/matchup.txt
  33. 57
      etc/soft/nvim/+plugins/vim-matchup/plugin/matchup.vim
  34. 8
      etc/soft/nvim/+plugins/vim-matchup/test/addrtp.vim
  35. 10
      etc/soft/nvim/+plugins/vim-matchup/test/augment.matchuptest
  36. 18
      etc/soft/nvim/+plugins/vim-matchup/test/bootstrap.vim
  37. 33
      etc/soft/nvim/+plugins/vim-matchup/test/forwhile.vim
  38. 7
      etc/soft/nvim/+plugins/vim-matchup/test/hlend.matchuptest
  39. 32
      etc/soft/nvim/+plugins/vim-matchup/test/issues/10/legacy.vim
  40. 8
      etc/soft/nvim/+plugins/vim-matchup/test/issues/10/string.vim
  41. 45
      etc/soft/nvim/+plugins/vim-matchup/test/issues/14/example.tex
  42. 25
      etc/soft/nvim/+plugins/vim-matchup/test/issues/15/enhance-vimrc
  43. 13
      etc/soft/nvim/+plugins/vim-matchup/test/issues/15/gc.vim
  44. 19
      etc/soft/nvim/+plugins/vim-matchup/test/issues/15/issue-vimrc
  45. 20
      etc/soft/nvim/+plugins/vim-matchup/test/issues/16/any.vim
  46. 15
      etc/soft/nvim/+plugins/vim-matchup/test/issues/16/blocks.vim
  47. 9
      etc/soft/nvim/+plugins/vim-matchup/test/issues/19/hotfix.vim
  48. 3
      etc/soft/nvim/+plugins/vim-matchup/test/issues/19/option.vim
  49. 6
      etc/soft/nvim/+plugins/vim-matchup/test/issues/19/test.html
  50. 402
      etc/soft/nvim/+plugins/vim-matchup/test/issues/21/Matchup_Problem_File.txt
  51. 9
      etc/soft/nvim/+plugins/vim-matchup/test/issues/26/example.rb
  52. 16
      etc/soft/nvim/+plugins/vim-matchup/test/issues/3/hotfix.vim
  53. 7
      etc/soft/nvim/+plugins/vim-matchup/test/issues/30/complex-hl.html
  54. 22
      etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.html
  55. 22
      etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.vue
  56. 16
      etc/soft/nvim/+plugins/vim-matchup/test/issues/30/minvimrc
  57. 17
      etc/soft/nvim/+plugins/vim-matchup/test/issues/33/minvimrc
  58. 69
      etc/soft/nvim/+plugins/vim-matchup/test/issues/33/test.rb
  59. 76
      etc/soft/nvim/+plugins/vim-matchup/test/issues/34/endvar.vim
  60. 21
      etc/soft/nvim/+plugins/vim-matchup/test/issues/36/image_uploader.rb
  61. 5
      etc/soft/nvim/+plugins/vim-matchup/test/issues/46/Sample.jsx
  62. 26
      etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc1
  63. 26
      etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc2
  64. 20
      etc/soft/nvim/+plugins/vim-matchup/test/issues/48/minvimrc
  65. 3
      etc/soft/nvim/+plugins/vim-matchup/test/issues/48/new.xml
  66. 10
      etc/soft/nvim/+plugins/vim-matchup/test/issues/48/simple.xml
  67. 28
      etc/soft/nvim/+plugins/vim-matchup/test/issues/48/vim-matchup-20181230.xml
  68. 7
      etc/soft/nvim/+plugins/vim-matchup/test/issues/49/example.vim
  69. 7
      etc/soft/nvim/+plugins/vim-matchup/test/issues/49/test.sh
  70. 29
      etc/soft/nvim/+plugins/vim-matchup/test/issues/51/test.f90
  71. 9
      etc/soft/nvim/+plugins/vim-matchup/test/issues/54/foo.vim
  72. 9
      etc/soft/nvim/+plugins/vim-matchup/test/issues/59/rebind.vim
  73. 16
      etc/soft/nvim/+plugins/vim-matchup/test/issues/63/test.f90
  74. 11
      etc/soft/nvim/+plugins/vim-matchup/test/issues/64/ast.cc
  75. 11
      etc/soft/nvim/+plugins/vim-matchup/test/issues/69/cpptemplate.vim
  76. 6
      etc/soft/nvim/+plugins/vim-matchup/test/issues/69/template.cpp
  77. 6
      etc/soft/nvim/+plugins/vim-matchup/test/issues/7/augroup.vim
  78. 9
      etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix.vim
  79. 9
      etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix2.vim
  80. 8
      etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex.html
  81. 6
      etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex2.html
  82. 22
      etc/soft/nvim/+plugins/vim-matchup/test/issues/8/hotfix.vim
  83. 4
      etc/soft/nvim/+plugins/vim-matchup/test/issues/8/slash.html
  84. 73
      etc/soft/nvim/+plugins/vim-matchup/test/lang/lua/tohtml.lua
  85. 8
      etc/soft/nvim/+plugins/vim-matchup/test/lang/ruby/next.rb
  86. 17
      etc/soft/nvim/+plugins/vim-matchup/test/minvimrc
  87. 9
      etc/soft/nvim/+plugins/vim-matchup/test/mwe.vim
  88. 106
      etc/soft/nvim/+plugins/vim-matchup/test/parens.txt
  89. 9
      etc/soft/nvim/+plugins/vim-matchup/test/parts.vim
  90. 2
      etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftdetect/matchuptest.vim
  91. 47
      etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftplugin/matchuptest.vim
  92. 24
      etc/soft/nvim/+plugins/vim-matchup/test/startup.sh
  93. 19
      etc/soft/nvim/+plugins/vim-matchup/test/tabs.vim
  94. 13
      etc/soft/nvim/+plugins/vim-matchup/test/test.html
  95. 19
      etc/soft/nvim/+plugins/vim-matchup/test/textobjV.vim
  96. 5
      etc/soft/nvim/+plugins/vim-matchup/test/transmute.html
  97. 19
      etc/soft/nvim/+plugins/vim-matchup/test/transmute2.html
  98. 32
      etc/soft/nvim/+plugins/vim-matchup/test/unicode.matchuptest
  99. 104
      etc/soft/nvim/+plugins/vim-matchup/test/vader/issue-66.vader
  100. 26
      etc/soft/nvim/+plugins/vim-matchup/test/vader/minvimrc
  101. Some files were not shown because too many files have changed in this diff Show More

23
etc/soft/nvim/+plugins/vim-matchup/LICENSE.md

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

780
etc/soft/nvim/+plugins/vim-matchup/README.md

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

16
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/c_matchup.vim

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

25
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/cpp_matchup.vim

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

25
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/fortran_matchup.vim

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

44
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/html_matchup.vim

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

22
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/lua_matchup.vim

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

15
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ocaml_matchup.vim

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

25
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ruby_matchup.vim

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

117
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/tex_matchup.vim

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

27
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vim_matchup.vim

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

10
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vue_matchup.vim

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

22
etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/xml_matchup.vim

@ -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
etc/soft/nvim/+plugins/vim-matchup/after/plugin/matchit.vim

362
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup.vim

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

152
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/custom.vim

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

918
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/delim.vim

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

721
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/loader.vim

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

953
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/matchparen.vim

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

27
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/misc.vim

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

313
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/motion.vim

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

117
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/perf.vim

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

143
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/pos.vim

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

52
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/quirks.vim

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

23
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/re.vim

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

83
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/surround.vim

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

296
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/text_obj.vim

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

146
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/transmute.vim

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

26
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/unmatchit.vim

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

153
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/util.vim

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

156
etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/where.vim

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

1072
etc/soft/nvim/+plugins/vim-matchup/doc/matchup.txt

File diff suppressed because it is too large Load Diff

57
etc/soft/nvim/+plugins/vim-matchup/plugin/matchup.vim

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

8
etc/soft/nvim/+plugins/vim-matchup/test/addrtp.vim

@ -0,0 +1,8 @@
" rtp for testing files
let s:path = expand('<sfile>:h')
let &rtp = s:path.'/rtp,' . &rtp
runtime! ftdetect/matchuptest.vim

10
etc/soft/nvim/+plugins/vim-matchup/test/augment.matchuptest

@ -0,0 +1,10 @@
foobar
barfoo
endfoobar
" \<\(\(foo\)\(bar\)\):\3\2:end\1
" vim: set ft=matchuptest :

18
etc/soft/nvim/+plugins/vim-matchup/test/bootstrap.vim

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

33
etc/soft/nvim/+plugins/vim-matchup/test/forwhile.vim

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

7
etc/soft/nvim/+plugins/vim-matchup/test/hlend.matchuptest

@ -0,0 +1,7 @@
< highlight this | but not this > no cursor
< mid this | not > no
< end this | not > no

32
etc/soft/nvim/+plugins/vim-matchup/test/issues/10/legacy.vim

@ -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 = "( \\( )" . "\\( " . '\( \)' . "\\)"

8
etc/soft/nvim/+plugins/vim-matchup/test/issues/10/string.vim

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

45
etc/soft/nvim/+plugins/vim-matchup/test/issues/14/example.tex

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

25
etc/soft/nvim/+plugins/vim-matchup/test/issues/15/enhance-vimrc

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

13
etc/soft/nvim/+plugins/vim-matchup/test/issues/15/gc.vim

@ -0,0 +1,13 @@
function! s:test()
let l:str = "hello"
return l:str
endfunction
if condition
call one()
call two()
endif

19
etc/soft/nvim/+plugins/vim-matchup/test/issues/15/issue-vimrc

@ -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@', ':']

20
etc/soft/nvim/+plugins/vim-matchup/test/issues/16/any.vim

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

15
etc/soft/nvim/+plugins/vim-matchup/test/issues/16/blocks.vim

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

9
etc/soft/nvim/+plugins/vim-matchup/test/issues/19/hotfix.vim

@ -0,0 +1,9 @@
function! HtmlListHotfix()
call matchup#util#patch_match_words(
\ '<\@<=[ou]l\>[^>]*\%(>\|$\):<\@<=li\>:<\@<=/[ou]l>',
\ '')
endfunction
let g:matchup_hotfix_html = 'HtmlListHotfix'

3
etc/soft/nvim/+plugins/vim-matchup/test/issues/19/option.vim

@ -0,0 +1,3 @@
let g:matchup_matchpref_html_nolists = 1

6
etc/soft/nvim/+plugins/vim-matchup/test/issues/19/test.html

@ -0,0 +1,6 @@
<ul class="btn-group">
<li>
</li>
</ul>

402
etc/soft/nvim/+plugins/vim-matchup/test/issues/21/Matchup_Problem_File.txt

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

9
etc/soft/nvim/+plugins/vim-matchup/test/issues/26/example.rb

@ -0,0 +1,9 @@
class Example
def initialize
@text = 'for text'
@text2 = 'end text2'
@text3 = '( text )'
end
end

16
etc/soft/nvim/+plugins/vim-matchup/test/issues/3/hotfix.vim

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

7
etc/soft/nvim/+plugins/vim-matchup/test/issues/30/complex-hl.html

@ -0,0 +1,7 @@
<TooltipOverlay message="Remove">
<Button onClick={deleteHandler} bsStyle="danger" baSize="xsmall">
<i className="fa fa-remove text-danger-inverse" />
</Button>
</TooltipOverlay>

22
etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.html

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

22
etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.vue

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

16
etc/soft/nvim/+plugins/vim-matchup/test/issues/30/minvimrc

@ -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, },
\}

17
etc/soft/nvim/+plugins/vim-matchup/test/issues/33/minvimrc

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

69
etc/soft/nvim/+plugins/vim-matchup/test/issues/33/test.rb

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

76
etc/soft/nvim/+plugins/vim-matchup/test/issues/34/endvar.vim

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

21
etc/soft/nvim/+plugins/vim-matchup/test/issues/36/image_uploader.rb

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

5
etc/soft/nvim/+plugins/vim-matchup/test/issues/46/Sample.jsx

@ -0,0 +1,5 @@
const Sample = <Sample prop='highlight test'>
some body
</Sample>;

26
etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc1

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

26
etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc2

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

20
etc/soft/nvim/+plugins/vim-matchup/test/issues/48/minvimrc

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

3
etc/soft/nvim/+plugins/vim-matchup/test/issues/48/new.xml

@ -0,0 +1,3 @@
<variable>x</variable>
<action>a ''</action>

10
etc/soft/nvim/+plugins/vim-matchup/test/issues/48/simple.xml

@ -0,0 +1,10 @@
<root>
<blue>
</blue>
<red>
</red>
<green>
</green>
</root>

28
etc/soft/nvim/+plugins/vim-matchup/test/issues/48/vim-matchup-20181230.xml

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

7
etc/soft/nvim/+plugins/vim-matchup/test/issues/49/example.vim

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

7
etc/soft/nvim/+plugins/vim-matchup/test/issues/49/test.sh

@ -0,0 +1,7 @@
# `%` jumps to fi
if test -z ""; then
echo "cursor_position"
else
true
fi

29
etc/soft/nvim/+plugins/vim-matchup/test/issues/51/test.f90

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

9
etc/soft/nvim/+plugins/vim-matchup/test/issues/54/foo.vim

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

9
etc/soft/nvim/+plugins/vim-matchup/test/issues/59/rebind.vim

@ -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%'])

16
etc/soft/nvim/+plugins/vim-matchup/test/issues/63/test.f90

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

11
etc/soft/nvim/+plugins/vim-matchup/test/issues/64/ast.cc

@ -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();
}

11
etc/soft/nvim/+plugins/vim-matchup/test/issues/69/cpptemplate.vim

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

6
etc/soft/nvim/+plugins/vim-matchup/test/issues/69/template.cpp

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

6
etc/soft/nvim/+plugins/vim-matchup/test/issues/7/augroup.vim

@ -0,0 +1,6 @@
augroup nomatchparen
autocmd!
autocmd VimEnter * NoMatchParen
augroup END

9
etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix.vim

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

9
etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix2.vim

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

8
etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex.html

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

6
etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex2.html

@ -0,0 +1,6 @@
<Flex>
<FlexItem flex>
</FlexItem>
</Flex>

22
etc/soft/nvim/+plugins/vim-matchup/test/issues/8/hotfix.vim

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

4
etc/soft/nvim/+plugins/vim-matchup/test/issues/8/slash.html

@ -0,0 +1,4 @@
<div>hello world</div>
<div />hello world</div>

73
etc/soft/nvim/+plugins/vim-matchup/test/lang/lua/tohtml.lua

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

8
etc/soft/nvim/+plugins/vim-matchup/test/lang/ruby/next.rb

@ -0,0 +1,8 @@
for i in 0..5
if i < 2 then
next
else
end
puts "Value of local variable is #{i}"
end

17
etc/soft/nvim/+plugins/vim-matchup/test/minvimrc

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

9
etc/soft/nvim/+plugins/vim-matchup/test/mwe.vim

@ -0,0 +1,9 @@
if l:x == 1
call one()
else
call two()
elseif
call three()
endif

106
etc/soft/nvim/+plugins/vim-matchup/test/parens.txt

@ -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
} } |
----
( ( (( )) ) )
----
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))

9
etc/soft/nvim/+plugins/vim-matchup/test/parts.vim

@ -0,0 +1,9 @@
function
return
break
endwhile

2
etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftdetect/matchuptest.vim

@ -0,0 +1,2 @@
autocmd BufNewFile,BufRead *.matchuptest setlocal filetype=matchuptest

47
etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftplugin/matchuptest.vim

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

24
etc/soft/nvim/+plugins/vim-matchup/test/startup.sh

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

19
etc/soft/nvim/+plugins/vim-matchup/test/tabs.vim

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

13
etc/soft/nvim/+plugins/vim-matchup/test/test.html

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

19
etc/soft/nvim/+plugins/vim-matchup/test/textobjV.vim

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

5
etc/soft/nvim/+plugins/vim-matchup/test/transmute.html

@ -0,0 +1,5 @@
<sometag>
</sometag>

19
etc/soft/nvim/+plugins/vim-matchup/test/transmute2.html

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

32
etc/soft/nvim/+plugins/vim-matchup/test/unicode.matchuptest

@ -0,0 +1,32 @@
もぎ |
も ぎ
むめ
endむめも
むめ
ぽendむめも
ぽむめ
endむめも
\begin{🍩🍩🍩}
\end{🍩🍩🍩}
one😀🐑one
two😐🐑two
three🙁🐑foo
hi MatchParen cterm=strikethrough
" vim: set ft=matchuptest :

104
etc/soft/nvim/+plugins/vim-matchup/test/vader/issue-66.vader

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

26
etc/soft/nvim/+plugins/vim-matchup/test/vader/minvimrc

@ -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…
Cancel
Save