From b249ef2b4e6ed3650b8450fb5f560536a2e7df42 Mon Sep 17 00:00:00 2001 From: Maxim Likhachev Date: Wed, 5 Feb 2020 14:39:32 +0300 Subject: [PATCH] vim: plugins: matchin -> vim-matchup --- etc/soft/nvim/+plugins/matchit/doc/matchit.txt | 406 -------- etc/soft/nvim/+plugins/matchit/plugin/matchit.vim | 812 --------------- etc/soft/nvim/+plugins/vim-matchup/LICENSE.md | 23 + etc/soft/nvim/+plugins/vim-matchup/README.md | 780 ++++++++++++++ .../vim-matchup/after/ftplugin/c_matchup.vim | 16 + .../vim-matchup/after/ftplugin/cpp_matchup.vim | 25 + .../vim-matchup/after/ftplugin/fortran_matchup.vim | 25 + .../vim-matchup/after/ftplugin/html_matchup.vim | 44 + .../vim-matchup/after/ftplugin/lua_matchup.vim | 22 + .../vim-matchup/after/ftplugin/ocaml_matchup.vim | 15 + .../vim-matchup/after/ftplugin/ruby_matchup.vim | 25 + .../vim-matchup/after/ftplugin/tex_matchup.vim | 117 +++ .../vim-matchup/after/ftplugin/vim_matchup.vim | 27 + .../vim-matchup/after/ftplugin/vue_matchup.vim | 10 + .../vim-matchup/after/ftplugin/xml_matchup.vim | 22 + .../+plugins/vim-matchup/after/plugin/matchit.vim | 0 .../nvim/+plugins/vim-matchup/autoload/matchup.vim | 362 +++++++ .../vim-matchup/autoload/matchup/custom.vim | 152 +++ .../vim-matchup/autoload/matchup/delim.vim | 918 +++++++++++++++++ .../vim-matchup/autoload/matchup/loader.vim | 721 +++++++++++++ .../vim-matchup/autoload/matchup/matchparen.vim | 953 +++++++++++++++++ .../+plugins/vim-matchup/autoload/matchup/misc.vim | 27 + .../vim-matchup/autoload/matchup/motion.vim | 313 ++++++ .../+plugins/vim-matchup/autoload/matchup/perf.vim | 117 +++ .../+plugins/vim-matchup/autoload/matchup/pos.vim | 143 +++ .../vim-matchup/autoload/matchup/quirks.vim | 52 + .../+plugins/vim-matchup/autoload/matchup/re.vim | 23 + .../vim-matchup/autoload/matchup/surround.vim | 83 ++ .../vim-matchup/autoload/matchup/text_obj.vim | 296 ++++++ .../vim-matchup/autoload/matchup/transmute.vim | 146 +++ .../vim-matchup/autoload/matchup/unmatchit.vim | 26 + .../+plugins/vim-matchup/autoload/matchup/util.vim | 153 +++ .../vim-matchup/autoload/matchup/where.vim | 156 +++ etc/soft/nvim/+plugins/vim-matchup/doc/matchup.txt | 1072 ++++++++++++++++++++ .../nvim/+plugins/vim-matchup/plugin/matchup.vim | 57 ++ etc/soft/nvim/+plugins/vim-matchup/test/addrtp.vim | 8 + .../+plugins/vim-matchup/test/augment.matchuptest | 10 + .../nvim/+plugins/vim-matchup/test/bootstrap.vim | 18 + .../nvim/+plugins/vim-matchup/test/forwhile.vim | 33 + .../+plugins/vim-matchup/test/hlend.matchuptest | 7 + .../+plugins/vim-matchup/test/issues/10/legacy.vim | 32 + .../+plugins/vim-matchup/test/issues/10/string.vim | 8 + .../vim-matchup/test/issues/14/example.tex | 45 + .../vim-matchup/test/issues/15/enhance-vimrc | 25 + .../+plugins/vim-matchup/test/issues/15/gc.vim | 13 + .../vim-matchup/test/issues/15/issue-vimrc | 19 + .../+plugins/vim-matchup/test/issues/16/any.vim | 20 + .../+plugins/vim-matchup/test/issues/16/blocks.vim | 15 + .../+plugins/vim-matchup/test/issues/19/hotfix.vim | 9 + .../+plugins/vim-matchup/test/issues/19/option.vim | 3 + .../+plugins/vim-matchup/test/issues/19/test.html | 6 + .../test/issues/21/Matchup_Problem_File.txt | 402 ++++++++ .../+plugins/vim-matchup/test/issues/26/example.rb | 9 + .../+plugins/vim-matchup/test/issues/3/hotfix.vim | 16 + .../vim-matchup/test/issues/30/complex-hl.html | 7 + .../vim-matchup/test/issues/30/example.html | 22 + .../vim-matchup/test/issues/30/example.vue | 22 + .../+plugins/vim-matchup/test/issues/30/minvimrc | 16 + .../+plugins/vim-matchup/test/issues/33/minvimrc | 17 + .../+plugins/vim-matchup/test/issues/33/test.rb | 69 ++ .../+plugins/vim-matchup/test/issues/34/endvar.vim | 76 ++ .../vim-matchup/test/issues/36/image_uploader.rb | 21 + .../+plugins/vim-matchup/test/issues/46/Sample.jsx | 5 + .../+plugins/vim-matchup/test/issues/46/minvimrc1 | 26 + .../+plugins/vim-matchup/test/issues/46/minvimrc2 | 26 + .../+plugins/vim-matchup/test/issues/48/minvimrc | 20 + .../+plugins/vim-matchup/test/issues/48/new.xml | 3 + .../+plugins/vim-matchup/test/issues/48/simple.xml | 10 + .../test/issues/48/vim-matchup-20181230.xml | 28 + .../vim-matchup/test/issues/49/example.vim | 7 + .../+plugins/vim-matchup/test/issues/49/test.sh | 7 + .../+plugins/vim-matchup/test/issues/51/test.f90 | 29 + .../+plugins/vim-matchup/test/issues/54/foo.vim | 9 + .../+plugins/vim-matchup/test/issues/59/rebind.vim | 9 + .../+plugins/vim-matchup/test/issues/63/test.f90 | 16 + .../+plugins/vim-matchup/test/issues/64/ast.cc | 11 + .../vim-matchup/test/issues/69/cpptemplate.vim | 11 + .../vim-matchup/test/issues/69/template.cpp | 6 + .../+plugins/vim-matchup/test/issues/7/augroup.vim | 6 + .../+plugins/vim-matchup/test/issues/7/hotfix.vim | 9 + .../+plugins/vim-matchup/test/issues/7/hotfix2.vim | 9 + .../+plugins/vim-matchup/test/issues/8/flex.html | 8 + .../+plugins/vim-matchup/test/issues/8/flex2.html | 6 + .../+plugins/vim-matchup/test/issues/8/hotfix.vim | 22 + .../+plugins/vim-matchup/test/issues/8/slash.html | 4 + .../+plugins/vim-matchup/test/lang/lua/tohtml.lua | 73 ++ .../+plugins/vim-matchup/test/lang/ruby/next.rb | 8 + etc/soft/nvim/+plugins/vim-matchup/test/minvimrc | 17 + etc/soft/nvim/+plugins/vim-matchup/test/mwe.vim | 9 + etc/soft/nvim/+plugins/vim-matchup/test/parens.txt | 106 ++ etc/soft/nvim/+plugins/vim-matchup/test/parts.vim | 9 + .../vim-matchup/test/rtp/ftdetect/matchuptest.vim | 2 + .../vim-matchup/test/rtp/ftplugin/matchuptest.vim | 47 + etc/soft/nvim/+plugins/vim-matchup/test/startup.sh | 24 + etc/soft/nvim/+plugins/vim-matchup/test/tabs.vim | 19 + etc/soft/nvim/+plugins/vim-matchup/test/test.html | 13 + .../nvim/+plugins/vim-matchup/test/textobjV.vim | 19 + .../nvim/+plugins/vim-matchup/test/transmute.html | 5 + .../nvim/+plugins/vim-matchup/test/transmute2.html | 19 + .../+plugins/vim-matchup/test/unicode.matchuptest | 32 + .../+plugins/vim-matchup/test/vader/issue-66.vader | 104 ++ .../nvim/+plugins/vim-matchup/test/vader/minvimrc | 26 + .../+plugins/vim-matchup/test/vader/motion.vader | 23 + .../vim-matchup/test/vader/motion_force.vader | 23 + .../+plugins/vim-matchup/test/vader/ruby.vader | 40 + etc/soft/nvim/+plugins/vim-matchup/test/vader/run | 5 + .../nvim/+plugins/vim-matchup/test/vader/syn.vader | 17 + .../+plugins/vim-matchup/test/vader/text_obj.vader | 40 + .../nvim/+plugins/vim-matchup/test/vimrc-startup | 14 + .../+plugins/vim-matchup/test/zsze.matchuptest | 14 + .../nvim/+plugins_disabled/matchit/doc/matchit.txt | 406 ++++++++ .../+plugins_disabled/matchit/plugin/matchit.vim | 812 +++++++++++++++ etc/soft/nvim/vimrc | 8 + 113 files changed, 10090 insertions(+), 1218 deletions(-) delete mode 100644 etc/soft/nvim/+plugins/matchit/doc/matchit.txt delete mode 100644 etc/soft/nvim/+plugins/matchit/plugin/matchit.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/LICENSE.md create mode 100644 etc/soft/nvim/+plugins/vim-matchup/README.md create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/c_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/cpp_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/fortran_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/html_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/lua_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ocaml_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ruby_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/tex_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vim_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vue_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/xml_matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/after/plugin/matchit.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/custom.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/delim.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/loader.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/matchparen.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/misc.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/motion.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/perf.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/pos.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/quirks.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/re.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/surround.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/text_obj.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/transmute.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/unmatchit.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/util.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/where.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/doc/matchup.txt create mode 100644 etc/soft/nvim/+plugins/vim-matchup/plugin/matchup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/addrtp.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/augment.matchuptest create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/bootstrap.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/forwhile.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/hlend.matchuptest create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/10/legacy.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/10/string.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/14/example.tex create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/15/enhance-vimrc create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/15/gc.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/15/issue-vimrc create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/16/any.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/16/blocks.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/19/hotfix.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/19/option.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/19/test.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/21/Matchup_Problem_File.txt create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/26/example.rb create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/3/hotfix.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/30/complex-hl.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.vue create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/30/minvimrc create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/33/minvimrc create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/33/test.rb create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/34/endvar.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/36/image_uploader.rb create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/46/Sample.jsx create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc1 create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc2 create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/48/minvimrc create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/48/new.xml create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/48/simple.xml create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/48/vim-matchup-20181230.xml create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/49/example.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/49/test.sh create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/51/test.f90 create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/54/foo.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/59/rebind.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/63/test.f90 create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/64/ast.cc create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/69/cpptemplate.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/69/template.cpp create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/7/augroup.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix2.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex2.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/8/hotfix.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/issues/8/slash.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/lang/lua/tohtml.lua create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/lang/ruby/next.rb create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/minvimrc create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/mwe.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/parens.txt create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/parts.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftdetect/matchuptest.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftplugin/matchuptest.vim create mode 100755 etc/soft/nvim/+plugins/vim-matchup/test/startup.sh create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/tabs.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/test.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/textobjV.vim create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/transmute.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/transmute2.html create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/unicode.matchuptest create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/vader/issue-66.vader create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/vader/minvimrc create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/vader/motion.vader create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/vader/motion_force.vader create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/vader/ruby.vader create mode 100755 etc/soft/nvim/+plugins/vim-matchup/test/vader/run create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/vader/syn.vader create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/vader/text_obj.vader create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/vimrc-startup create mode 100644 etc/soft/nvim/+plugins/vim-matchup/test/zsze.matchuptest create mode 100644 etc/soft/nvim/+plugins_disabled/matchit/doc/matchit.txt create mode 100644 etc/soft/nvim/+plugins_disabled/matchit/plugin/matchit.vim diff --git a/etc/soft/nvim/+plugins/matchit/doc/matchit.txt b/etc/soft/nvim/+plugins/matchit/doc/matchit.txt deleted file mode 100644 index 8a3a96e..0000000 --- a/etc/soft/nvim/+plugins/matchit/doc/matchit.txt +++ /dev/null @@ -1,406 +0,0 @@ -*matchit.txt* Extended "%" matching - -For instructions on installing this file, type - :help matchit-install -inside Vim. - -For Vim version 6.3. Last change: 2007 Aug 29 - - - VIM REFERENCE MANUAL by Benji Fisher - -*matchit* *matchit.vim* - -1. Extended matching with "%" |matchit-intro| -2. Activation |matchit-activate| -3. Configuration |matchit-configure| -4. Supporting a New Language |matchit-newlang| -5. Known Bugs and Limitations |matchit-bugs| - -The functionality mentioned here is a plugin, see |add-plugin|. -This plugin is only available if 'compatible' is not set. -You can avoid loading this plugin by setting the "loaded_matchit" variable -in your |vimrc| file: > - :let loaded_matchit = 1 - -{Vi does not have any of this} - -============================================================================== -1. Extended matching with "%" *matchit-intro* - - *matchit-%* -% Cycle forward through matching groups, such as "if", "else", "endif", - as specified by |b:match_words|. - - *g%* *v_g%* *o_g%* -g% Cycle backwards through matching groups, as specified by - |b:match_words|. For example, go from "if" to "endif" to "else". - - *[%* *v_[%* *o_[%* -[% Go to [count] previous unmatched group, as specified by - |b:match_words|. Similar to |[{|. - - *]%* *v_]%* *o_]%* -]% Go to [count] next unmatched group, as specified by - |b:match_words|. Similar to |]}|. - - *v_a%* -a% In Visual mode, select the matching group, as specified by - |b:match_words|, containing the cursor. Similar to |v_a[|. - A [count] is ignored, and only the first character of the closing - pattern is selected. - -In Vim, as in plain vi, the percent key, |%|, jumps the cursor from a brace, -bracket, or paren to its match. This can be configured with the 'matchpairs' -option. The matchit plugin extends this in several ways: - - You can match whole words, such as "if" and "endif", not just - single characters. You can also specify a |regular-expression|. - You can define groups with more than two words, such as "if", - "else", "endif". Banging on the "%" key will cycle from the "if" to - the first "else", the next "else", ..., the closing "endif", and back - to the opening "if". Nested structures are skipped. Using |g%| goes - in the reverse direction. - By default, words inside comments and strings are ignored, unless - the cursor is inside a comment or string when you type "%". If the - only thing you want to do is modify the behavior of "%" so that it - behaves this way, you do not have to define |b:match_words|, since the - script uses the 'matchpairs' option as well as this variable. - -See |matchit-details| for details on what the script does, and |b:match_words| -for how to specify matching patterns. - -MODES: *matchit-modes* *matchit-v_%* *matchit-o_%* - -Mostly, % and related motions (|g%| and |[%| and |]%|) work just like built-in -|motion| commands in |Operator-pending| and |Visual| modes. However, you -cannot make these motions |linewise| or |characterwise|, since the |:omap|s -that define them start with "v" in order to make the default behavior -inclusive. (See |o_v|.) In other words, "dV%" will not work. The -work-around is to go through Visual mode: "V%d" will work. - -LANGUAGES: *matchit-languages* - -Currently, the following languages are supported: Ada, ASP with VBS, Csh, -DTD, Entity, Essbase, Fortran, HTML, JSP (same as HTML), LaTeX, Lua, Pascal, -SGML, Shell, Tcsh, Vim, XML. Other languages may already have support via -the default |filetype-plugin|s in the standard vim distribution. - -To support a new language, see |matchit-newlang| below. - -DETAILS: *matchit-details* *matchit-parse* - -Here is an outline of what matchit.vim does each time you hit the "%" key. If -there are |backref|s in |b:match_words| then the first step is to produce a -version in which these back references have been eliminated; if there are no -|backref|s then this step is skipped. This step is called parsing. For -example, "\(foo\|bar\):end\1" is parsed to yield -"\(foo\|bar\):end\(foo\|bar\)". This can get tricky, especially if there are -nested groups. If debugging is turned on, the parsed version is saved as -|b:match_pat|. - - *matchit-choose* -Next, the script looks for a word on the current line that matches the pattern -just constructed. It includes the patterns from the 'matchpairs' option. -The goal is to do what you expect, which turns out to be a little complicated. -The script follows these rules: - - Insist on a match that ends on or after the cursor. - Prefer a match that includes the cursor position (that is, one that - starts on or before the cursor). - Prefer a match that starts as close to the cursor as possible. - If more than one pattern in |b:match_words| matches, choose the one - that is listed first. - -Examples: - - Suppose you > - :let b:match_words = '<:>,:' -< and hit "%" with the cursor on or before the "<" in "a is born". - The pattern '<' comes first, so it is preferred over '', which - also matches. If the cursor is on the "t", however, then '' is - preferred, because this matches a bit of text containing the cursor. - If the two groups of patterns were reversed then '<' would never be - preferred. - - Suppose you > - :let b:match_words = 'if:end if' -< (Note the space!) and hit "%" with the cursor at the end of "end if". - Then "if" matches, which is probably not what you want, but if the - cursor starts on the "end " then "end if" is chosen. (You can avoid - this problem by using a more complicated pattern.) - -If there is no match, the cursor does not move. (Before version 1.13 of the -script, it would fall back on the usual behavior of |%|). If debugging is -turned on, the matched bit of text is saved as |b:match_match| and the cursor -column of the start of the match is saved as |b:match_col|. - -Next, the script looks through |b:match_words| (original and parsed versions) -for the group and pattern that match. If debugging is turned on, the group is -saved as |b:match_ini| (the first pattern) and |b:match_tail| (the rest). If -there are |backref|s then, in addition, the matching pattern is saved as -|b:match_word| and a table of translations is saved as |b:match_table|. If -there are |backref|s, these are determined from the matching pattern and -|b:match_match| and substituted into each pattern in the matching group. - -The script decides whether to search forwards or backwards and chooses -arguments for the |searchpair()| function. Then, the cursor is moved to the -start of the match, and |searchpair()| is called. By default, matching -structures inside strings and comments are ignored. This can be changed by -setting |b:match_skip|. - -============================================================================== -2. Activation *matchit-activate* - -You can use this script as a plugin, by copying it to your plugin directory. -See |add-global-plugin| for instructions. You can also add a line to your -|vimrc| file, such as > - :source $VIMRUNTIME/macros/matchit.vim -or > - :runtime macros/matchit.vim -Either way, the script should start working the next time you start up Vim. - -(Earlier versions of the script did nothing unless a |buffer-variable| named -|b:match_words| was defined. Even earlier versions contained autocommands -that set this variable for various file types. Now, |b:match_words| is -defined in many of the default |filetype-plugin|s instead.) - -For a new language, you can add autocommands to the script or to your vimrc -file, but the recommended method is to add a line such as > - let b:match_words = '\:\' -to the |filetype-plugin| for your language. See |b:match_words| below for how -this variable is interpreted. - -TROUBLESHOOTING *matchit-troubleshoot* - -The script should work in most installations of Vim. It may not work if Vim -was compiled with a minimal feature set, for example if the |+syntax| option -was not enabled. If your Vim has support for syntax compiled in, but you do -not have |syntax| highlighting turned on, matchit.vim should work, but it may -fail to skip matching groups in comments and strings. If the |filetype| -mechanism is turned off, the |b:match_words| variable will probably not be -defined automatically. - -============================================================================== -3. Configuration *matchit-configure* - -There are several variables that govern the behavior of matchit.vim. Note -that these are variables local to the buffer, not options, so use |:let| to -define them, not |:set|. Some of these variables have values that matter; for -others, it only matters whether the variable has been defined. All of these -can be defined in the |filetype-plugin| or autocommand that defines -|b:match_words| or "on the fly." - -The main variable is |b:match_words|. It is described in the section below on -supporting a new language. - - *MatchError* *matchit-hl* *matchit-highlight* -MatchError is the highlight group for error messages from the script. By -default, it is linked to WarningMsg. If you do not want to be bothered by -error messages, you can define this to be something invisible. For example, -if you use the GUI version of Vim and your command line is normally white, you -can do > - :hi MatchError guifg=white guibg=white -< - *b:match_ignorecase* -If you > - :let b:match_ignorecase = 1 -then matchit.vim acts as if 'ignorecase' is set: for example, "end" and "END" -are equivalent. If you > - :let b:match_ignorecase = 0 -then matchit.vim treats "end" and "END" differently. (There will be no -b:match_infercase option unless someone requests it.) - - *b:match_debug* -Define b:match_debug if you want debugging information to be saved. See -|matchit-debug|, below. - - *b:match_skip* -If b:match_skip is defined, it is passed as the skip argument to -|searchpair()|. This controls when matching structures are skipped, or -ignored. By default, they are ignored inside comments and strings, as -determined by the |syntax| mechanism. (If syntax highlighting is turned off, -nothing is skipped.) You can set b:match_skip to a string, which evaluates to -a non-zero, numerical value if the match is to be skipped or zero if the match -should not be skipped. In addition, the following special values are -supported by matchit.vim: - 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 -(The "s" is meant to suggest "syntax", and the "r" is meant to suggest -"regular expression".) - -Examples: - - You can get the default behavior with > - :let b:match_skip = 's:comment\|string' -< - If you want to skip matching structures unless they are at the start - of the line (ignoring whitespace) then you can > - :let b:match_skip = 'R:^\s*' -< Do not do this if strings or comments can span several lines, since - the normal syntax checking will not be done if you set b:match_skip. - - In LaTeX, since "%" is used as the comment character, you can > - :let b:match_skip = 'r:%' -< Unfortunately, this will skip anything after "\%", an escaped "%". To - allow for this, and also "\\%" (an excaped backslash followed by the - comment character) you can > - :let b:match_skip = 'r:\(^\|[^\\]\)\(\\\\\)*%' -< - See the $VIMRUNTIME/ftplugin/vim.vim for an example that uses both - syntax and a regular expression. - -============================================================================== -4. Supporting a New Language *matchit-newlang* - *b:match_words* -In order for matchit.vim to support a new language, you must define a suitable -pattern for |b:match_words|. You may also want to set some of the -|matchit-configure| variables, as described above. If your language has a -complicated syntax, or many keywords, you will need to know something about -Vim's |regular-expression|s. - -The format for |b:match_words| is similar to that of the 'matchpairs' option: -it is a comma (,)-separated list of groups; each group is a colon(:)-separated -list of patterns (regular expressions). Commas and backslashes that are part -of a pattern should be escaped with backslashes ('\:' and '\,'). It is OK to -have only one group; the effect is undefined if a group has only one pattern. -A simple example is > - :let b:match_words = '\:\,' - \ . '\:\:\:\' -(In Vim regular expressions, |\<| and |\>| denote word boundaries. Thus "if" -matches the end of "endif" but "\" does not.) Then banging on the "%" -key will bounce the cursor between "if" and the matching "endif"; and from -"while" to any matching "continue" or "break", then to the matching "endwhile" -and back to the "while". It is almost always easier to use |literal-string|s -(single quotes) as above: '\' rather than "\\" and so on. - -Exception: If the ":" character does not appear in b:match_words, then it is -treated as an expression to be evaluated. For example, > - :let b:match_words = 'GetMatchWords()' -allows you to define a function. This can return a different string depending -on the current syntax, for example. - -Once you have defined the appropriate value of |b:match_words|, you will -probably want to have this set automatically each time you edit the -appropriate file type. The recommended way to do this is by adding the -definition to a |filetype-plugin| file. - -Tips: Be careful that your initial pattern does not match your final pattern. -See the example above for the use of word-boundary expressions. It is usually -better to use ".\{-}" (as many as necessary) instead of ".*" (as many as -possible). See |\{-|. For example, in the string "label", "<.*>" -matches the whole string whereas "<.\{-}>" and "<[^>]*>" match "" and -"". - - *matchit-spaces* *matchit-s:notend* -If "if" is to be paired with "end if" (Note the space!) then word boundaries -are not enough. Instead, define a regular expression s:notend that will match -anything but "end" and use it as follows: > - :let s:notend = '\%(\:\' -< *matchit-s:sol* -This is a simplified version of what is done for Ada. The s:notend is a -|script-variable|. Similarly, you may want to define a start-of-line regular -expression > - :let s:sol = '\%(^\|;\)\s*' -if keywords are only recognized after the start of a line or after a -semicolon (;), with optional white space. - - *matchit-backref* *matchit-\1* -In any group, the expressions |\1|, |\2|, ..., |\9| refer to parts of the -INITIAL pattern enclosed in |\(|escaped parentheses|\)|. These are referred -to as back references, or backrefs. For example, > - :let b:match_words = '\:\(h\)\1\>' -means that "bo" pairs with "ho" and "boo" pairs with "hoo" and so on. Note -that "\1" does not refer to the "\(h\)" in this example. If you have -"\(nested \(parentheses\)\) then "\d" refers to the d-th "\(" and everything -up to and including the matching "\)": in "\(nested\(parentheses\)\)", "\1" -refers to everything and "\2" refers to "\(parentheses\)". If you use a -variable such as |s:notend| or |s:sol| in the previous paragraph then remember -to count any "\(" patterns in this variable. You do not have to count groups -defined by |\%(\)|. - -It should be possible to resolve back references from any pattern in the -group. For example, > - :let b:match_words = '\(foo\)\(bar\):more\1:and\2:end\1\2' -would not work because "\2" cannot be determined from "morefoo" and "\1" -cannot be determined from "andbar". On the other hand, > - :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' -should work (and have the same effect as "foobar:barfoo:endfoobar"), although -this has not been thoroughly tested. - -You can use |zero-width| patterns such as |\@<=| and |\zs|. (The latter has -not been thouroughly tested in matchit.vim.) For example, if the keyword "if" -must occur at the start of the line, with optional white space, you might use -the pattern "\(^\s*\)\@<=if" so that the cursor will end on the "i" instead of -at the start of the line. For another example, if HTML had only one tag then -one could > - :let b:match_words = '<:>,<\@<=tag>:<\@<=/tag>' -so that "%" can bounce between matching "<" and ">" pairs or (starting on -"tag" or "/tag") between matching tags. Without the |\@<=|, the script would -bounce from "tag" to the "<" in "", and another "%" would not take you -back to where you started. - -DEBUGGING *matchit-debug* *:MatchDebug* - -If you are having trouble figuring out the appropriate definition of -|b:match_words| then you can take advantage of the same information I use when -debugging the script. This is especially true if you are not sure whether -your patterns or my script are at fault! To make this more convenient, I have -made the command :MatchDebug, which defines the variable |b:match_debug| and -creates a Matchit menu. This menu makes it convenient to check the values of -the variables described below. You will probably also want to read -|matchit-details| above. - -Defining the variable |b:match_debug| causes the script to set the following -variables, each time you hit the "%" key. Several of these are only defined -if |b:match_words| includes |backref|s. - - *b:match_pat* -The b:match_pat variable is set to |b:match_words| with |backref|s parsed. - *b:match_match* -The b:match_match variable is set to the bit of text that is recognized as a -match. - *b:match_col* -The b:match_col variable is set to the cursor column of the start of the -matching text. - *b:match_wholeBR* -The b:match_wholeBR variable is set to the comma-separated group of patterns -that matches, with |backref|s unparsed. - *b:match_iniBR* -The b:match_iniBR variable is set to the first pattern in |b:match_wholeBR|. - *b:match_ini* -The b:match_ini variable is set to the first pattern in |b:match_wholeBR|, -with |backref|s resolved from |b:match_match|. - *b:match_tail* -The b:match_tail variable is set to the remaining patterns in -|b:match_wholeBR|, with |backref|s resolved from |b:match_match|. - *b:match_word* -The b:match_word variable is set to the pattern from |b:match_wholeBR| that -matches |b:match_match|. - *b:match_table* -The back reference '\'.d refers to the same thing as '\'.b:match_table[d] in -|b:match_word|. - -============================================================================== -5. Known Bugs and Limitations *matchit-bugs* - -Just because I know about a bug does not mean that it is on my todo list. I -try to respond to reports of bugs that cause real problems. If it does not -cause serious problems, or if there is a work-around, a bug may sit there for -a while. Moral: if a bug (known or not) bothers you, let me know. - -The various |:vmap|s defined in the script (%, |g%|, |[%|, |]%|, |a%|) may -have undesired effects in Select mode |Select-mode-mapping|. At least, if you -want to replace the selection with any character in "ag%[]" there will be a -pause of |'updatetime'| first. - -It would be nice if "\0" were recognized as the entire pattern. That is, it -would be nice if "foo:\end\0" had the same effect as "\(foo\):\end\1". I may -try to implement this in a future version. (This is not so easy to arrange as -you might think!) - -============================================================================== -vim:tw=78:fo=tcq2: diff --git a/etc/soft/nvim/+plugins/matchit/plugin/matchit.vim b/etc/soft/nvim/+plugins/matchit/plugin/matchit.vim deleted file mode 100644 index e41cda9..0000000 --- a/etc/soft/nvim/+plugins/matchit/plugin/matchit.vim +++ /dev/null @@ -1,812 +0,0 @@ -" matchit.vim: (global plugin) Extended "%" matching -" Last Change: Fri Jan 25 10:00 AM 2008 EST -" Maintainer: Benji Fisher PhD -" Version: 1.13.2, for Vim 6.3+ -" URL: http://www.vim.org/script.php?script_id=39 - -" Documentation: -" The documentation is in a separate file, matchit.txt . - -" Credits: -" Vim editor by Bram Moolenaar (Thanks, Bram!) -" Original script and design by Raul Segura Acevedo -" Support for comments by Douglas Potts -" Support for back references and other improvements by Benji Fisher -" Support for many languages by Johannes Zellner -" Suggestions for improvement, bug reports, and support for additional -" languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark -" Collett, Stephen Wall, Dany St-Amant, Yuheng Xie, and Johannes Zellner. - -" Debugging: -" If you'd like to try the built-in debugging commands... -" :MatchDebug to activate debugging for the current buffer -" This saves the values of several key script variables as buffer-local -" variables. See the MatchDebug() function, below, for details. - -" TODO: I should think about multi-line patterns for b:match_words. -" This would require an option: how many lines to scan (default 1). -" This would be useful for Python, maybe also for *ML. -" TODO: Maybe I should add a menu so that people will actually use some of -" the features that I have implemented. -" TODO: Eliminate the MultiMatch function. Add yet another argument to -" Match_wrapper() instead. -" TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' -" TODO: Make backrefs safer by using '\V' (very no-magic). -" TODO: Add a level of indirection, so that custom % scripts can use my -" work but extend it. - -" allow user to prevent loading -" and prevent duplicate loading -if exists("loaded_matchit") || &cp - finish -endif -let loaded_matchit = 1 -let s:last_mps = "" -let s:last_words = ":" - -let s:save_cpo = &cpo -set cpo&vim - -nnoremap % :call Match_wrapper('',1,'n') -nnoremap g% :call Match_wrapper('',0,'n') -vnoremap % :call Match_wrapper('',1,'v') m'gv`` -vnoremap g% :call Match_wrapper('',0,'v') m'gv`` -onoremap % v:call Match_wrapper('',1,'o') -onoremap g% v:call Match_wrapper('',0,'o') - -" Analogues of [{ and ]} using matching patterns: -nnoremap [% :call MultiMatch("bW", "n") -nnoremap ]% :call MultiMatch("W", "n") -vmap [% [%m'gv`` -vmap ]% ]%m'gv`` -" vnoremap [% :call MultiMatch("bW", "v") m'gv`` -" vnoremap ]% :call MultiMatch("W", "v") m'gv`` -onoremap [% v:call MultiMatch("bW", "o") -onoremap ]% v:call MultiMatch("W", "o") - -" text object: -vmap a% [%v]% - -" Auto-complete mappings: (not yet "ready for prime time") -" TODO Read :help write-plugin for the "right" way to let the user -" specify a key binding. -" let g:match_auto = '' -" let g:match_autoCR = '' -" if exists("g:match_auto") -" execute "inoremap " . g:match_auto . ' x"=Autocomplete()Pls' -" endif -" if exists("g:match_autoCR") -" execute "inoremap " . g:match_autoCR . ' =Autocomplete()' -" endif -" if exists("g:match_gthhoh") -" execute "inoremap " . g:match_gthhoh . ' :call Gthhoh()' -" endif " gthhoh = "Get the heck out of here!" - -let s:notslash = '\\\@" - endif - " In s:CleanUp(), we may need to check whether the cursor moved forward. - let startline = line(".") - let startcol = col(".") - " Use default behavior if called with a count. - if v:count - exe "normal! " . v:count . "%" - return s:CleanUp(restore_options, a:mode, startline, startcol) - end - - " First step: if not already done, set the script variables - " s:do_BR flag for whether there are backrefs - " s:pat parsed version of b:match_words - " s:all regexp based on s:pat and the default groups - " - if !exists("b:match_words") || b:match_words == "" - let match_words = "" - " Allow b:match_words = "GetVimMatchWords()" . - elseif b:match_words =~ ":" - let match_words = b:match_words - else - execute "let match_words =" b:match_words - endif -" Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion! - if (match_words != s:last_words) || (&mps != s:last_mps) || - \ exists("b:match_debug") - let s:last_words = match_words - let s:last_mps = &mps - " The next several lines were here before - " BF started messing with this script. - " quote the special chars in 'matchpairs', replace [,:] with \| and then - " append the builtin pairs (/*, */, #if, #ifdef, #else, #elif, #endif) - " let default = substitute(escape(&mps, '[$^.*~\\/?]'), '[,:]\+', - " \ '\\|', 'g').'\|\/\*\|\*\/\|#if\>\|#ifdef\>\|#else\>\|#elif\>\|#endif\>' - let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . - \ '\/\*:\*\/,#if\%(def\)\=:#else\>:#elif\>:#endif\>' - " s:all = pattern with all the keywords - let match_words = match_words . (strlen(match_words) ? "," : "") . default - if match_words !~ s:notslash . '\\\d' - let s:do_BR = 0 - let s:pat = match_words - else - let s:do_BR = 1 - let s:pat = s:ParseWords(match_words) - endif - let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g') - let s:all = '\%(' . s:all . '\)' - " let s:all = '\%(' . substitute(s:all, '\\\ze[,:]', '', 'g') . '\)' - if exists("b:match_debug") - let b:match_pat = s:pat - endif - endif - - " Second step: set the following local variables: - " matchline = line on which the cursor started - " curcol = number of characters before match - " prefix = regexp for start of line to start of match - " suffix = regexp for end of match to end of line - " Require match to end on or after the cursor and prefer it to - " start on or before the cursor. - let matchline = getline(startline) - if a:word != '' - " word given - if a:word !~ s:all - echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE - return s:CleanUp(restore_options, a:mode, startline, startcol) - endif - let matchline = a:word - let curcol = 0 - let prefix = '^\%(' - let suffix = '\)$' - " Now the case when "word" is not given - else " Find the match that ends on or after the cursor and set curcol. - let regexp = s:Wholematch(matchline, s:all, startcol-1) - let curcol = match(matchline, regexp) - " If there is no match, give up. - if curcol == -1 - return s:CleanUp(restore_options, a:mode, startline, startcol) - endif - let endcol = matchend(matchline, regexp) - let suf = strlen(matchline) - endcol - let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(') - let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$') - endif - if exists("b:match_debug") - let b:match_match = matchstr(matchline, regexp) - let b:match_col = curcol+1 - endif - - " Third step: Find the group and single word that match, and the original - " (backref) versions of these. Then, resolve the backrefs. - " Set the following local variable: - " group = colon-separated list of patterns, one of which matches - " = ini:mid:fin or ini:fin - " - " Reconstruct the version with unresolved backrefs. - let patBR = substitute(match_words.',', - \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g') - let patBR = substitute(patBR, s:notslash.'\zs:\{2,}', ':', 'g') - " Now, set group and groupBR to the matching group: 'if:endif' or - " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns - " group . "," . groupBR, and we pick it apart. - let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR) - let i = matchend(group, s:notslash . ",") - let groupBR = strpart(group, i) - let group = strpart(group, 0, i-1) - " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix - if s:do_BR " Do the hard part: resolve those backrefs! - let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) - endif - if exists("b:match_debug") - let b:match_wholeBR = groupBR - let i = matchend(groupBR, s:notslash . ":") - let b:match_iniBR = strpart(groupBR, 0, i-1) - endif - - " Fourth step: Set the arguments for searchpair(). - let i = matchend(group, s:notslash . ":") - let j = matchend(group, '.*' . s:notslash . ":") - let ini = strpart(group, 0, i-1) - let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g') - let fin = strpart(group, j) - "Un-escape the remaining , and : characters. - let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') - let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') - let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') - " searchpair() requires that these patterns avoid \(\) groups. - let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g') - let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g') - let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g') - " Set mid. This is optimized for readability, not micro-efficiency! - if a:forward && matchline =~ prefix . fin . suffix - \ || !a:forward && matchline =~ prefix . ini . suffix - let mid = "" - endif - " Set flag. This is optimized for readability, not micro-efficiency! - if a:forward && matchline =~ prefix . fin . suffix - \ || !a:forward && matchline !~ prefix . ini . suffix - let flag = "bW" - else - let flag = "W" - endif - " Set skip. - if exists("b:match_skip") - let skip = b:match_skip - elseif exists("b:match_comment") " backwards compatibility and testing! - let skip = "r:" . b:match_comment - else - let skip = 's:comment\|string' - endif - let skip = s:ParseSkip(skip) - if exists("b:match_debug") - let b:match_ini = ini - let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin - endif - - " Fifth step: actually start moving the cursor and call searchpair(). - " Later, :execute restore_cursor to get to the original screen. - let restore_cursor = virtcol(".") . "|" - normal! g0 - let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor - normal! H - let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - execute restore_cursor - call cursor(0, curcol + 1) - " normal! 0 - " if curcol - " execute "normal!" . curcol . "l" - " endif - if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on")) - let skip = "0" - else - execute "if " . skip . "| let skip = '0' | endif" - endif - let sp_return = searchpair(ini, mid, fin, flag, skip) - let final_position = "call cursor(" . line(".") . "," . col(".") . ")" - " Restore cursor position and original screen. - execute restore_cursor - normal! m' - if sp_return > 0 - execute final_position - endif - return s:CleanUp(restore_options, a:mode, startline, startcol, mid.'\|'.fin) -endfun - -" Restore options and do some special handling for Operator-pending mode. -" The optional argument is the tail of the matching group. -fun! s:CleanUp(options, mode, startline, startcol, ...) - execute "set" a:options - " Open folds, if appropriate. - if a:mode != "o" - if &foldopen =~ "percent" - normal! zv - endif - " In Operator-pending mode, we want to include the whole match - " (for example, d%). - " This is only a problem if we end up moving in the forward direction. - elseif (a:startline < line(".")) || - \ (a:startline == line(".") && a:startcol < col(".")) - if a:0 - " Check whether the match is a single character. If not, move to the - " end of the match. - let matchline = getline(".") - let currcol = col(".") - let regexp = s:Wholematch(matchline, a:1, currcol-1) - let endcol = matchend(matchline, regexp) - if endcol > currcol " This is NOT off by one! - execute "normal!" . (endcol - currcol) . "l" - endif - endif " a:0 - endif " a:mode != "o" && etc. - return 0 -endfun - -" Example (simplified HTML patterns): if -" a:groupBR = '<\(\k\+\)>:' -" a:prefix = '^.\{3}\(' -" a:group = '<\(\k\+\)>:' -" a:suffix = '\).\{2}$' -" a:matchline = "12312" or "12312" -" then extract "tag" from a:matchline and return ":" . -fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline) - if a:matchline !~ a:prefix . - \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix - return a:group - endif - let i = matchend(a:groupBR, s:notslash . ':') - let ini = strpart(a:groupBR, 0, i-1) - let tailBR = strpart(a:groupBR, i) - let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix, - \ a:groupBR) - let i = matchend(word, s:notslash . ":") - let wordBR = strpart(word, i) - let word = strpart(word, 0, i-1) - " Now, a:matchline =~ a:prefix . word . a:suffix - if wordBR != ini - let table = s:Resolve(ini, wordBR, "table") - else - " let table = "----------" - let table = "" - let d = 0 - while d < 10 - if tailBR =~ s:notslash . '\\' . d - " let table[d] = d - let table = table . d - else - let table = table . "-" - endif - let d = d + 1 - endwhile - endif - let d = 9 - while d - if table[d] != "-" - let backref = substitute(a:matchline, a:prefix.word.a:suffix, - \ '\'.table[d], "") - " Are there any other characters that should be escaped? - let backref = escape(backref, '*,:') - execute s:Ref(ini, d, "start", "len") - let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len) - let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d, - \ escape(backref, '\\'), 'g') - endif - let d = d-1 - endwhile - if exists("b:match_debug") - if s:do_BR - let b:match_table = table - let b:match_word = word - else - let b:match_table = "" - let b:match_word = "" - endif - endif - return ini . ":" . tailBR -endfun - -" Input a comma-separated list of groups with backrefs, such as -" a:groups = '\(foo\):end\1,\(bar\):end\1' -" and return a comma-separated list of groups with backrefs replaced: -" return '\(foo\):end\(foo\),\(bar\):end\(bar\)' -fun! s:ParseWords(groups) - let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g') - let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g') - let parsed = "" - while groups =~ '[^,:]' - let i = matchend(groups, s:notslash . ':') - let j = matchend(groups, s:notslash . ',') - let ini = strpart(groups, 0, i-1) - let tail = strpart(groups, i, j-i-1) . ":" - let groups = strpart(groups, j) - let parsed = parsed . ini - let i = matchend(tail, s:notslash . ':') - while i != -1 - " In 'if:else:endif', ini='if' and word='else' and then word='endif'. - let word = strpart(tail, 0, i-1) - let tail = strpart(tail, i) - let i = matchend(tail, s:notslash . ':') - let parsed = parsed . ":" . s:Resolve(ini, word, "word") - endwhile " Now, tail has been used up. - let parsed = parsed . "," - endwhile " groups =~ '[^,:]' - let parsed = substitute(parsed, ',$', '', '') - return parsed -endfun - -" TODO I think this can be simplified and/or made more efficient. -" TODO What should I do if a:start is out of range? -" Return a regexp that matches all of a:string, such that -" matchstr(a:string, regexp) represents the match for a:pat that starts -" as close to a:start as possible, before being preferred to after, and -" ends after a:start . -" Usage: -" let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1) -" let i = match(getline("."), regexp) -" let j = matchend(getline("."), regexp) -" let match = matchstr(getline("."), regexp) -fun! s:Wholematch(string, pat, start) - let group = '\%(' . a:pat . '\)' - let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^') - let len = strlen(a:string) - let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$') - if a:string !~ prefix . group . suffix - let prefix = '' - endif - return prefix . group . suffix -endfun - -" No extra arguments: s:Ref(string, d) will -" find the d'th occurrence of '\(' and return it, along with everything up -" to and including the matching '\)'. -" One argument: s:Ref(string, d, "start") returns the index of the start -" of the d'th '\(' and any other argument returns the length of the group. -" Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be -" executed, having the effect of -" :let foo = s:Ref(string, d, "start") -" :let bar = s:Ref(string, d, "len") -fun! s:Ref(string, d, ...) - let len = strlen(a:string) - if a:d == 0 - let start = 0 - else - let cnt = a:d - let match = a:string - while cnt - let cnt = cnt - 1 - let index = matchend(match, s:notslash . '\\(') - if index == -1 - return "" - endif - let match = strpart(match, index) - endwhile - let start = len - strlen(match) - if a:0 == 1 && a:1 == "start" - return start - 2 - endif - let cnt = 1 - while cnt - let index = matchend(match, s:notslash . '\\(\|\\)') - 1 - if index == -2 - return "" - endif - " Increment if an open, decrement if a ')': - let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')' - " let cnt = stridx('0(', match[index]) + cnt - let match = strpart(match, index+1) - endwhile - let start = start - 2 - let len = len - start - strlen(match) - endif - if a:0 == 1 - return len - elseif a:0 == 2 - return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len - else - return strpart(a:string, start, len) - endif -endfun - -" Count the number of disjoint copies of pattern in string. -" If the pattern is a literal string and contains no '0' or '1' characters -" then s:Count(string, pattern, '0', '1') should be faster than -" s:Count(string, pattern). -fun! s:Count(string, pattern, ...) - let pat = escape(a:pattern, '\\') - if a:0 > 1 - let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g") - let foo = substitute(a:string, pat, a:2, "g") - let foo = substitute(foo, '[^' . a:2 . ']', "", "g") - return strlen(foo) - endif - let result = 0 - let foo = a:string - let index = matchend(foo, pat) - while index != -1 - let result = result + 1 - let foo = strpart(foo, index) - let index = matchend(foo, pat) - endwhile - return result -endfun - -" s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where -" word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first -" '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this -" indicates that all other instances of '\1' in target are to be replaced -" by '\3'. The hard part is dealing with nesting... -" Note that ":" is an illegal character for source and target, -" unless it is preceded by "\". -fun! s:Resolve(source, target, output) - let word = a:target - let i = matchend(word, s:notslash . '\\\d') - 1 - let table = "----------" - while i != -2 " There are back references to be replaced. - let d = word[i] - let backref = s:Ref(a:source, d) - " The idea is to replace '\d' with backref. Before we do this, - " replace any \(\) groups in backref with :1, :2, ... if they - " correspond to the first, second, ... group already inserted - " into backref. Later, replace :1 with \1 and so on. The group - " number w+b within backref corresponds to the group number - " s within a:source. - " w = number of '\(' in word before the current one - let w = s:Count( - \ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1') - let b = 1 " number of the current '\(' in backref - let s = d " number of the current '\(' in a:source - while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1') - \ && s < 10 - if table[s] == "-" - if w + b < 10 - " let table[s] = w + b - let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1) - endif - let b = b + 1 - let s = s + 1 - else - execute s:Ref(backref, b, "start", "len") - let ref = strpart(backref, start, len) - let backref = strpart(backref, 0, start) . ":". table[s] - \ . strpart(backref, start+len) - let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1') - endif - endwhile - let word = strpart(word, 0, i-1) . backref . strpart(word, i+1) - let i = matchend(word, s:notslash . '\\\d') - 1 - endwhile - let word = substitute(word, s:notslash . '\zs:', '\\', 'g') - if a:output == "table" - return table - elseif a:output == "word" - return word - else - return table . word - endif -endfun - -" Assume a:comma = ",". Then the format for a:patterns and a:1 is -" a:patterns = ",,..." -" a:1 = ",,..." -" If is the first pattern that matches a:string then return -" if no optional arguments are given; return , if a:1 is given. -fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...) - let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma) - let i = matchend(tail, s:notslash . a:comma) - if a:0 - let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma) - let j = matchend(alttail, s:notslash . a:comma) - endif - let current = strpart(tail, 0, i-1) - if a:branch == "" - let currpat = current - else - let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') - endif - while a:string !~ a:prefix . currpat . a:suffix - let tail = strpart(tail, i) - let i = matchend(tail, s:notslash . a:comma) - if i == -1 - return -1 - endif - let current = strpart(tail, 0, i-1) - if a:branch == "" - let currpat = current - else - let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') - endif - if a:0 - let alttail = strpart(alttail, j) - let j = matchend(alttail, s:notslash . a:comma) - endif - endwhile - if a:0 - let current = current . a:comma . strpart(alttail, 0, j-1) - endif - return current -endfun - -" Call this function to turn on debugging information. Every time the main -" script is run, buffer variables will be saved. These can be used directly -" or viewed using the menu items below. -if !exists(":MatchDebug") - command! -nargs=0 MatchDebug call s:Match_debug() -endif - -fun! s:Match_debug() - let b:match_debug = 1 " Save debugging information. - " pat = all of b:match_words with backrefs parsed - amenu &Matchit.&pat :echo b:match_pat - " match = bit of text that is recognized as a match - amenu &Matchit.&match :echo b:match_match - " curcol = cursor column of the start of the matching text - amenu &Matchit.&curcol :echo b:match_col - " wholeBR = matching group, original version - amenu &Matchit.wh&oleBR :echo b:match_wholeBR - " iniBR = 'if' piece, original version - amenu &Matchit.ini&BR :echo b:match_iniBR - " ini = 'if' piece, with all backrefs resolved from match - amenu &Matchit.&ini :echo b:match_ini - " tail = 'else\|endif' piece, with all backrefs resolved from match - amenu &Matchit.&tail :echo b:match_tail - " fin = 'endif' piece, with all backrefs resolved from match - amenu &Matchit.&word :echo b:match_word - " '\'.d in ini refers to the same thing as '\'.table[d] in word. - amenu &Matchit.t&able :echo '0:' . b:match_table . ':9' -endfun - -" Jump to the nearest unmatched "(" or "if" or "" if a:spflag == "bW" -" or the nearest unmatched "" or "endif" or ")" if a:spflag == "W". -" Return a "mark" for the original position, so that -" let m = MultiMatch("bW", "n") ... execute m -" will return to the original position. If there is a problem, do not -" move the cursor and return "", unless a count is given, in which case -" go up or down as many levels as possible and again return "". -" TODO This relies on the same patterns as % matching. It might be a good -" idea to give it its own matching patterns. -fun! s:MultiMatch(spflag, mode) - if !exists("b:match_words") || b:match_words == "" - return "" - end - let restore_options = (&ic ? "" : "no") . "ignorecase" - if exists("b:match_ignorecase") - let &ignorecase = b:match_ignorecase - endif - let startline = line(".") - let startcol = col(".") - - " First step: if not already done, set the script variables - " s:do_BR flag for whether there are backrefs - " s:pat parsed version of b:match_words - " s:all regexp based on s:pat and the default groups - " This part is copied and slightly modified from s:Match_wrapper(). - let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . - \ '\/\*:\*\/,#if\%(def\)\=:#else\>:#elif\>:#endif\>' - " Allow b:match_words = "GetVimMatchWords()" . - if b:match_words =~ ":" - let match_words = b:match_words - else - execute "let match_words =" b:match_words - endif - if (match_words != s:last_words) || (&mps != s:last_mps) || - \ exists("b:match_debug") - let s:last_words = match_words - let s:last_mps = &mps - if match_words !~ s:notslash . '\\\d' - let s:do_BR = 0 - let s:pat = match_words - else - let s:do_BR = 1 - let s:pat = s:ParseWords(match_words) - endif - let s:all = '\%(' . substitute(s:pat . (strlen(s:pat)?",":"") . default, - \ '[,:]\+','\\|','g') . '\)' - if exists("b:match_debug") - let b:match_pat = s:pat - endif - endif - - " Second step: figure out the patterns for searchpair() - " and save the screen, cursor position, and 'ignorecase'. - " - TODO: A lot of this is copied from s:Match_wrapper(). - " - maybe even more functionality should be split off - " - into separate functions! - let cdefault = (s:pat =~ '[^,]$' ? "," : "") . default - let open = substitute(s:pat . cdefault, - \ s:notslash . '\zs:.\{-}' . s:notslash . ',', '\\),\\(', 'g') - let open = '\(' . substitute(open, s:notslash . '\zs:.*$', '\\)', '') - let close = substitute(s:pat . cdefault, - \ s:notslash . '\zs,.\{-}' . s:notslash . ':', '\\),\\(', 'g') - let close = substitute(close, '^.\{-}' . s:notslash . ':', '\\(', '') . '\)' - if exists("b:match_skip") - let skip = b:match_skip - elseif exists("b:match_comment") " backwards compatibility and testing! - let skip = "r:" . b:match_comment - else - let skip = 's:comment\|string' - endif - let skip = s:ParseSkip(skip) - " let restore_cursor = line(".") . "G" . virtcol(".") . "|" - " normal! H - " let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - let restore_cursor = virtcol(".") . "|" - normal! g0 - let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor - normal! H - let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - execute restore_cursor - - " Third step: call searchpair(). - " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'. - let openpat = substitute(open, '\(\\\@" or ... -" and return "endif" or "endwhile" or "" or ... . -" For now, this uses b:match_words and the same script variables -" as s:Match_wrapper() . Later, it may get its own patterns, -" either from a buffer variable or passed as arguments. -" fun! s:Autocomplete() -" echo "autocomplete not yet implemented :-(" -" if !exists("b:match_words") || b:match_words == "" -" return "" -" end -" let startpos = s:MultiMatch("bW") -" -" if startpos == "" -" return "" -" endif -" " - TODO: figure out whether 'if' or '' matched, and construct -" " - the appropriate closing. -" let matchline = getline(".") -" let curcol = col(".") - 1 -" " - TODO: Change the s:all argument if there is a new set of match pats. -" let regexp = s:Wholematch(matchline, s:all, curcol) -" let suf = strlen(matchline) - matchend(matchline, regexp) -" let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(') -" let suffix = (suf ? '\).\{' . suf . '}$' : '\)$') -" " Reconstruct the version with unresolved backrefs. -" let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g') -" let patBR = substitute(patBR, ':\{2,}', ':', "g") -" " Now, set group and groupBR to the matching group: 'if:endif' or -" " 'while:endwhile' or whatever. -" let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR) -" let i = matchend(group, s:notslash . ",") -" let groupBR = strpart(group, i) -" let group = strpart(group, 0, i-1) -" " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix -" if s:do_BR -" let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) -" endif -" " let g:group = group -" -" " - TODO: Construct the closing from group. -" let fake = "end" . expand("") -" execute startpos -" return fake -" endfun - -" Close all open structures. "Get the heck out of here!" -" fun! s:Gthhoh() -" let close = s:Autocomplete() -" while strlen(close) -" put=close -" let close = s:Autocomplete() -" endwhile -" endfun - -" Parse special strings as typical skip arguments for searchpair(): -" 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 -fun! s:ParseSkip(str) - let skip = a:str - if skip[1] == ":" - if skip[0] == "s" - let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" . - \ strpart(skip,2) . "'" - elseif skip[0] == "S" - let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" . - \ strpart(skip,2) . "'" - elseif skip[0] == "r" - let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'" - elseif skip[0] == "R" - let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'" - endif - endif - return skip -endfun - -let &cpo = s:save_cpo - -" vim:sts=2:sw=2: diff --git a/etc/soft/nvim/+plugins/vim-matchup/LICENSE.md b/etc/soft/nvim/+plugins/vim-matchup/LICENSE.md new file mode 100644 index 0000000..9bfab03 --- /dev/null +++ b/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. diff --git a/etc/soft/nvim/+plugins/vim-matchup/README.md b/etc/soft/nvim/+plugins/vim-matchup/README.md new file mode 100644 index 0000000..05ffbb4 --- /dev/null +++ b/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. + +and in this corner... + +## Screenshot + + + +## 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 (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 (std-I) I + xnoremap (std-A) A + xmap I mode()==''?'(std-I)':(v:count?'':'1').'i' + xmap A mode()==''?'(std-A)':(v:count?'':'1').'a' + for l:v in ['', 'v', 'V', ''] + execute 'omap ' l:v.'I%' "(v:count?'':'1').'".l:v."i%'" + execute 'omap ' 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! + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/c_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/c_matchup.vim new file mode 100644 index 0000000..64fb6fe --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/cpp_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/cpp_matchup.vim new file mode 100644 index 0000000..4d4f2cf --- /dev/null +++ b/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\@!\)=\@!') + if stridx(&matchpairs, '<:>') + setlocal matchpairs-=<:> + endif +endif + +let &cpo = s:save_cpo + +" vim: fdm=marker sw=2 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/fortran_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/fortran_matchup.vim new file mode 100644 index 0000000..56b4129 --- /dev/null +++ b/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('\') +call matchup#util#patch_match_words('\\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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/html_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/html_matchup.vim new file mode 100644 index 0000000..87e7651 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/lua_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/lua_matchup.vim new file mode 100644 index 0000000..ad20a0a --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ocaml_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ocaml_matchup.vim new file mode 100644 index 0000000..5bd2d4f --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ruby_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/ruby_matchup.vim new file mode 100644 index 0000000..6aeab49 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/tex_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/tex_matchup.vim new file mode 100644 index 0000000..2f0c3d8 --- /dev/null +++ b/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%(\\@\|\\[|{}]\|.\)' + 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' + + " 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:\\\@ % + silent! xunmap % + silent! ounmap % + + " 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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vim_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vim_matchup.vim new file mode 100644 index 0000000..8254d1a --- /dev/null +++ b/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( + \ '\\)\@!\S:', + \ '\\)\@!\S:' + \) + +let &cpo = s:save_cpo + +" vim: fdm=marker sw=2 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vue_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/vue_matchup.vim new file mode 100644 index 0000000..ca47401 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/xml_matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/after/ftplugin/xml_matchup.vim new file mode 100644 index 0000000..41b6d2b --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/after/plugin/matchit.vim b/etc/soft/nvim/+plugins/vim-matchup/after/plugin/matchit.vim new file mode 100644 index 0000000..e69de29 diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup.vim new file mode 100644 index 0000000..2ddadba --- /dev/null +++ b/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', ''] + call s:map('onore', ' (matchup-o_'.l:opforce.')', + \ 'force('''.l:opforce.''')') + endfor + endif + + if get(g:, 'matchup_motion_enabled', 0) + for l:opforce in ['', 'v', 'V', ''] + call s:map('o', l:opforce.'%', + \ '(matchup-o_'.l:opforce.')(matchup-%)') + call s:map('o', l:opforce.'g%', + \ '(matchup-o_'.l:opforce.')(matchup-g%)') + call s:map('o', l:opforce.']%', + \ '(matchup-o_'.l:opforce.')(matchup-]%)') + call s:map('o', l:opforce.'[%', + \ '(matchup-o_'.l:opforce.')(matchup-[%)') + call s:map('o', l:opforce.'z%', + \ '(matchup-o_'.l:opforce.')(matchup-z%)') + endfor + endif + + if get(g:, 'matchup_text_obj_enabled', 0) + for l:opforce in ['', 'v', 'V', ''] + call s:map('o', l:opforce.'i%', + \ '(matchup-o_'.l:opforce.')(matchup-i%)') + call s:map('o', l:opforce.'a%', + \ '(matchup-o_'.l:opforce.')(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', ''] + silent! execute 'omap' l:opforce.a:lhs + \ '(matchup-o_'.l:opforce.')(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 ' 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', '%', '(matchup-%)' ) + call s:map('n', 'g%', '(matchup-g%)') + + call s:map('x', '%', '(matchup-%)' ) + call s:map('x', 'g%', '(matchup-g%)') + + call s:map('n', ']%', '(matchup-]%)') + call s:map('n', '[%', '(matchup-[%)') + + call s:map('x', ']%', '(matchup-]%)') + call s:map('x', '[%', '(matchup-[%)') + + call s:map('n', 'z%', '(matchup-z%)') + call s:map('x', 'z%', '(matchup-z%)') + + if !s:old_style_ops + call s:map('o', '%', '(matchup-%)') + call s:map('o', 'g%', '(matchup-g%)') + call s:map('o', ']%', '(matchup-]%)') + call s:map('o', '[%', '(matchup-[%)') + call s:map('o', 'z%', '(matchup-z%)') + endif + + call s:map('i', '%', '(matchup-c_g%)') + endif + + if get(g:, 'matchup_text_obj_enabled', 0) + call s:map('x', 'i%', '(matchup-i%)') + call s:map('x', 'a%', '(matchup-a%)') + + if !s:old_style_ops + call s:map('o', 'i%', '(matchup-i%)') + call s:map('o', 'a%', '(matchup-a%)') + endif + endif + + if get(g:, 'matchup_mouse_enabled', 1) + call s:map('n', '<2-LeftMouse>', '(matchup-double-click)') + endif + + if get(g:, 'matchup_surround_enabled', 0) + call s:map('n', 'ds%', '(matchup-ds%)') + call s:map('n', 'cs%', '(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 (wise) + \ empty(g:v_motion_force) ? 'v' : g:v_motion_force + + " the basic motions % and g% + nnoremap (matchup-%) + \ :call matchup#motion#find_matching_pair(0, 1) + nnoremap (matchup-g%) + \ :call matchup#motion#find_matching_pair(0, 0) + + " visual and operator-pending + xnoremap (matchup-%) + \ :call matchup#motion#find_matching_pair(1, 1) + xmap (matchup-%) (matchup-%) + onoremap (matchup-%) + \ :call matchup#motion#op('%') + + xnoremap (matchup-g%) + \ :call matchup#motion#find_matching_pair(1, 0) + xmap (matchup-g%) (matchup-g%) + onoremap (matchup-g%) + \ :call matchup#motion#op('g%') + + " ]% and [% + nnoremap (matchup-]%) + \ :call matchup#motion#find_unmatched(0, 1) + nnoremap (matchup-[%) + \ :call matchup#motion#find_unmatched(0, 0) + + xnoremap (matchup-]%) + \ :call matchup#motion#find_unmatched(1, 1) + xnoremap (matchup-[%) + \ :call matchup#motion#find_unmatched(1, 0) + xmap (matchup-]%) (matchup-]%) + xmap (matchup-[%) (matchup-[%) + onoremap (matchup-]%) + \ :call matchup#motion#op(']%') + onoremap (matchup-[%) + \ :call matchup#motion#op('[%') + + " jump inside z% + nnoremap (matchup-z%) + \ :call matchup#motion#jump_inside(0) + + xnoremap (matchup-z%) + \ :call matchup#motion#jump_inside(1) + xmap (matchup-z%) (matchup-z%) + onoremap (matchup-z%) + \ :call matchup#motion#op('z%') + + inoremap (matchup-c_g%) + \ :call matchup#motion#insert_mode() + + call matchup#perf#toc('loading_module', 'motion') +endfunction + +" TODO redo this +function! s:snr() + return str2nr(matchstr(expand(''), '\zs\d\+\ze_snr$')) +endfunction +let s:sid = printf("\%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 (matchup-' + let l:p2 = l:map . ') :call matchup#text_obj#' . l:name + let l:p3 = empty(l:opt) ? ')' : ', ''' . l:opt . ''')' + 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 (matchup-double-click) + \ :call matchup#text_obj#double_click() + + 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 (matchup-reload) :MatchupReload + 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 (matchup-' + let l:p2 = l:map . ') :call matchup#surround#' . l:name + let l:p3 = empty(l:opt) ? ')' : ', ''' . l:opt . ''')' + 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('' . ) +endfunction + +" }}}1 + +let &cpo = s:save_cpo + +" vim: fdm=marker sw=2 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/custom.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/custom.vim new file mode 100644 index 0000000..7dda34f --- /dev/null +++ b/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 (matchup-custom-'.a:keys.')' + \ ':call matchup#custom#wrap(0, '.l:k.')' + execute 'nmap' a:keys '(matchup-custom-'.a:keys.')' + endif + + if a:modes =~# '[xo]' + let l:sid = substitute(matchup#motion_sid(), "\", '', '') + execute 'xnoremap ' l:sid.'(matchup-custom-'.l:k.')' + \ ':call matchup#custom#wrap(1, '.l:k.')' + endif + + if a:modes =~# 'x' + execute 'xmap (matchup-custom-'.a:keys.')' + \ l:sid.'(matchup-custom-'.l:k.')' + execute 'xmap ' a:keys '(matchup-custom-'.a:keys.')' + endif + + if a:modes =~# 'o' + execute 'onoremap (matchup-custom-'.a:keys.')' + \ ':call matchup#motion#op(' + \ . string('custom-'.l:k).')' + if !call(matchup#motion_sid().'make_oldstyle_omaps', + \ [a:keys, 'custom-'.a:keys]) + execute 'omap' a:keys '(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! \" + 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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/delim.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/delim.vim new file mode 100644 index 0000000..942e5e7 --- /dev/null +++ b/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\", 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 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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/loader.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/loader.vim new file mode 100644 index 0000000..2a63c2f --- /dev/null +++ b/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 = '\(\\\@ 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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/matchparen.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/matchparen.vim new file mode 100644 index 0000000..a87e76b --- /dev/null +++ b/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 (matchup-hi-surround) + \ :call matchup#matchparen#highlight_surrounding() +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('*'.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(''.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 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\" + 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 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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/misc.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/misc.vim new file mode 100644 index 0000000..b4194bc --- /dev/null +++ b/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('') + +" vim: fdm=marker sw=2 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/motion.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/motion.vim new file mode 100644 index 0000000..682e1e0 --- /dev/null +++ b/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 !=# "\" + + 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 !=# "\" + 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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/perf.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/perf.vim new file mode 100644 index 0000000..b9a736f --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/pos.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/pos.vim new file mode 100644 index 0000000..e26a38b --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/quirks.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/quirks.vim new file mode 100644 index 0000000..f37e9f6 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/re.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/re.vim new file mode 100644 index 0000000..cf3ec12 --- /dev/null +++ b/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%(\\@","\"], l:char) >= 0 + return + endif + endif + let l:tpope = !empty(maparg('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("\(matchup-ds%)", v:count) + elseif a:op ==# 'c' && l:tpope + normal! `[v`] + undojoin + execute "normal \VSurround".l:char + silent! call repeat#set("\(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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/text_obj.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/text_obj.vim new file mode 100644 index 0000000..5e26640 --- /dev/null +++ b/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 ? + " invalid text object, try to do nothing + " cause a drop into normal mode + call feedkeys("\\\", 'n') + + " and undo the text vim enters if necessary + call feedkeys(":call matchup#text_obj#undo(" + \ .undotree().seq_cur.")\:\", '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 \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 \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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/transmute.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/transmute.vim new file mode 100644 index 0000000..3f75ca1 --- /dev/null +++ b/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\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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/unmatchit.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/unmatchit.vim new file mode 100644 index 0000000..15a1d12 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/util.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/util.vim new file mode 100644 index 0000000..ee95f06 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/where.vim b/etc/soft/nvim/+plugins/vim-matchup/autoload/matchup/where.vim new file mode 100644 index 0000000..9a65f9b --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/doc/matchup.txt b/etc/soft/nvim/+plugins/vim-matchup/doc/matchup.txt new file mode 100644 index 0000000..09a8165 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/doc/matchup.txt @@ -0,0 +1,1072 @@ +*matchup.txt* modern matching words +*matchup* *match-up* + +Author: Andy Massimino +Web: https://github.com/andymass/vim-matchup +Script ID: 5624 +License: 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. + +}}} + +============================================================================== +CONTENTS *matchup-contents* + + Introduction |matchup-introduction| + Feature overview |matchup-overview| + Usage |matchup-usage| + Default mappings |matchup-default-mappings| + Customizing mappings |matchup-custom-mappings| + Features |matchup-features| + Commands |matchup-commands| + Options |matchup-options| + File type options |matchup-file-types| + FAQ |matchup-faq| + Interoperability |matchup-interoperability| + Acknowledgments |matchup-acknowledgments| + Development |matchup-development| + +============================================================================== +INTRODUCTION *matchup-introduction* + +|match-up| is a plugin that lets you visualize, navigate, and operate on +matching sets of text. It is a replacement for the venerable vim plugin +|matchit|. match-up aims to replicate 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' symbols such as `()`, `{}`, and `[]`. + +------------------------------------------------------------------------------ +Feature overview~ + *matchup-overview* + +This plugin: + +- Extends vim's |%| (see |matchup-%|) motion to language-specific words instead of + just single characters. The words depend on the specific |filetype| plugin + (|ftplugin|). The following built-in vim filetype 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 +< +- Highlights symbols and words under the cursor along with their matches. + +- Display off-screen matches in the |status-line|. + +- Adds motions |g%|, |[%|, |]%|, and |z%|. + +- Provides analogous text objects |i%| and |a%|. + +============================================================================== +USAGE *matchup-usage* + +------------------------------------------------------------------------------ +Default mappings~ + *matchup-default-mappings* + +For customization, see |matchup-custom-mappings|. + + *matchup-%* +% When on a recognized word, go forwards to its next + matching word. If at a close word, cycle back to the + corresponding open word. If the cursor is not on a + word, seek forwards to one and then jump to its match. + This is an |inclusive| motion. + + *matchup-N%* +{count}% If {count} is less than 6, go forwards {count} times. + Otherwise, go to {count} percentage in the file (|N%|). + See |g:matchup_motion_override_Npercent|. + + *g%* +g% When on a recognized word, go backwards to [count]th + previous matching word. If at an open word, cycle + around to the corresponding open word. If the cursor + is not on a word, seek forwards to one and then jump + to its match. + + *[%* +[% 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 (|matchup-feat-exclusive|). + + *]%* +]% Go to [count]th next outer close word. Allows + navigation to the end of blocks surrounding the + cursor. This is similar to vim's built-in |])| and |]}| + and is an |exclusive| motion (|matchup-feat-exclusive|). + + *z%* +z% Go to inside [count]th nearest block. This is an + |exclusive| motion when used with operators, + except it eats white-space. For example, where `█` is + the cursor position, > + + █ call somefunction( param1, param2) +< + `dz%` produces > + + param1, param2) +< + *v_a%* *a%* +a% Select an |any-block|. + This closely matches vim's built-in |ab|. + + *v_Na%* *Na%* +{count}a% Select an |open-to-close-block|. + When {count} is greater than 1, select the {count}th + surrounding open-to-close block. + + *v_i%* *i%* +i% Select the inside of an |any-block|. + This closely matches vim's built-in |ib|. + See also |matchup-feat-linewise|. + + *v_Ni%* *Ni%* +{count}i% Select the inside of an |open-to-close-block|. + When {count} is greater than 1, select the inside of + the {count}th surrounding open-to-close block. + + *ds%* +{count}ds% Delete {count}th surrounding matching words. This + only works for open and close words. + Requires |g:matchup_surround_enabled| = 1. + + *cs%* +{count}cs% Change {count}th surrounding matching words. This + only works for open and close words. If vim-surround + is installed, you can type replacements according to + that plugin's rules. Otherwise, match-up will give + you the opportunity to type a single character. Some + simple replacement pairs are supported. + Requires |g:matchup_surround_enabled| = 1. + +------------------------------------------------------------------------------ +Customizing mappings~ + *matchup-custom-mappings* + +|match-up| provides a number of default mappings. Each right-hand side is +provided as a -mapping (see |using-|). For any given map, the +default mapping will only be created if it does not already exist. This means +that if a user defines a custom mapping, e.g., with > + + nmap % (matchup-z%) +< +the corresponding default left-hand side will not be mapped. + + -------------------------------------------------------------------------~ + LHS RHS Mode Module + -------------------------------------------------------------------------~ + % |(matchup-%)| nx motion + g% |(matchup-g%)| nx motion + [% |(matchup-[%)| nx motion + ]% |(matchup-]%)| nx motion + z% |(matchup-z%)| nx motion + a% |(matchup-%)| x text_obj + i% |(matchup-%)| x text_obj + ds% |(matchup-ds%)| n surround + cs% |(matchup-cs%)| n surround + (none) |(matchup-hi-surround)| n matchparen + -------------------------------------------------------------------------~ + Operator pending maps~ + -------------------------------------------------------------------------~ + % |(matchup-%)| o motion + ... And so on for g%, [%, ]%, z%, a%, i% ... + +Key: (n) normal, (x) visual, (o) operator-pending (|omap-info|). + +Note: Prior to vim 8.1.0648, in order to support motion forcing (see |o_v|, |o_V|, +|o_CTRL-V|) for each operator-pending map, match-up made four maps corresponding +to each motion type: + + -------------------------------------------------------------------------~ + Obsolete operator pending maps~ + -------------------------------------------------------------------------~ + % |(matchup-o_)||(matchup-%)| o motion + v% |(matchup-o_v)||(matchup-%)| o motion + V% |(matchup-o_V)||(matchup-%)| o motion + % |(matchup-o_)||(matchup-%)| o motion + ... And so on for g%, [%, ]%, z%, a%, i% ... + +This meant, for example, `d2v%` would work (meaning delete 2 matches forward, +exclusively), but `dv2%` would not work as you would expect (the behavior is +undefined). After vim version 8.1.0648, this limitation of operator-pending +mapping was lifted and match-up is able to use simplified mappings. + +------------------------------------------------------------------------------ +Features~ + *matchup-features* + +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 +of examples: > + + if l:x == 1 + call one() + elseif l:x == 2 + call two() + else + call three() + endif +< + *any-block* *open-to-close-block* + +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++: > + + #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. + +See |matchup-feat-exclusive| and |matchup-feat-linewise| for some examples and +important special cases. + +Highlighting matches~ + +To disable match highlighting at |startup|, use > + + let g:matchup_matchparen_enabled = 0 +> +in your vimrc. See |matchup-opts-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. + +Display matches off screen~ + +If an open or close match which would have been highlighted is on a line +positioned outside of the current window, the match is shown in the status +line (the default). If both the open and close match are off-screen, the +close match is preferred. +See |g:matchup_matchparen_offscreen| for configuration. + + *(matchup-hi-surround)* +Highlight surrounding~ + +To highlight the surrounding delimiters until the cursor moves, use a map such +as the following > + + nmap (matchup-hi-surround) +< +There is no default map for this feature. + +Parallel transmutation~ + +In insert mode, after changing text inside a word, matching words will be +changed in parallel. As an example, > + +
+    text
+  
+< +Changing `pre` to `div` and leaving insert mode will produce: > + +
+ text +
+< +Note: this currently only works for match words which define a backref +relation like `\1`. A wider set of transmutations are planned. + +Parallel transmutation requires the matchparen module to be enabled. + + *matchup-feat-exclusive* +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, > + + if █x | continue | endif +< +pressing `d]%` will produce (cursor on the `e`) > + + if endif +< +To include the close word, use either `dv]%` or `vd]%`. This is also +compatible with vim's `dv])` and `dv]}`. + +Operators over backward exclusive motions will instead exclude the position +the cursor was on before the operator was invoked. For example, in > + + if █x | continue | endif +< +pressing `d[%` will produce > + + █x | continue | endif +< +This is compatible with vim's `d[(` and `d[{`. + + *d%* *dg%* + +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. > + + █( + + ) +< +To operate character-wise in this situation, use `dv%` or `vd%`. This is vim +compatible with the built-in `d%` on items in 'matchpairs'. + + *matchup-feat-linewise* +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 > + + if condition + █call one() + call two() + endif +< +pressing `di%` will produce > + + 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, > + + 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, > + + if condition + █call one() + call two() + endif +< +pressing `da%` will delete all four lines and leave no white-space. This is +compatible with vim's `da(`, `dab`, etc. + +------------------------------------------------------------------------------ +Commands~ + *matchup-commands* + + *:NoMatchParen* *matchup-:NoMatchParen* +:NoMatchParen Disable matching after the plugin was loaded. + *:DoMatchParen* *matchup-:DoMatchParen* +:DoMatchParen Enable matching again. + + *:MatchupShowTimes* +:MatchupShowTimes Display performance data, useful for debugging slow + matching. Shows last, average, and maximum times. + *:MatchupClearTimes* +:MatchupClearTimes Reset performance counters to zero. + + *:MatchupWhereAmI* +:MatchupWhereAmI? Echos your position in code by finding successive matching + words, like doing `[%` repeatedly. Example: +> + 1310 do_pending_operator( … { ⯈ if ((finish_op || VIsual_active) && oap- … { +< + Running this command twice in the same position will give + more verbose output. + +:MatchupWhereAmI?? Be more verbose about your position in code by displaying + several lines. Example: +> + 1310 do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank) … { + 1349 if ((finish_op || VIsual_active) && oap->op_type != OP_NOP) … { +< + *:MatchupReload* +:MatchupReload Reload the plugin, mostly for debugging. Note that + this does not reload 'matchpairs' or `b:match_word`. + +------------------------------------------------------------------------------ +Options~ + *matchup-options* + +*g:matchup_enabled* + + Set to 0 to disable the plugin entirely. + + Default: 1 + +*g:matchup_mappings_enabled* all mappings +|g:matchup_matchparen_enabled| match highlighting +*g:matchup_mouse_enabled* double click to select matches +*g:matchup_motion_enabled* |matchup-%|, |%|, |[%|, |]%| +*g:matchup_text_obj_enabled* |a%|, |i%| + + Set to 0 to disable a particular module or feature. + + Defaults: 1 + +*g:matchup_transmute_enabled* + + Set to 1 to enable the experimental transmute feature (|matchup-transmute|). + + Default: 0 + +*g:matchup_delim_stopline* + + Configures 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). + + Default: 1500 + +*g:matchup_delim_noskips* + + This option controls whether matching is done within strings and comments. + By default, it is set to 0 which means all valid matches are made within + strings and comments. If set to 1, symbols like `()` will still be matched + but words like `for` and `end` will not. If set to 2, nothing will be + matched within strings and comments. > + + let g:matchup_delim_noskips = 1 + let g:matchup_delim_noskips = 2 +< + Default: 0 (matching enabled within strings and comments) + +*g:matchup_delim_start_plaintext* + + When enabled (the default), the plugin will be loaded for all buffers, + including ones without a file type set. This allows matching to be done in + new buffers and plain text files but adds a small start-up cost to vim. + + Default: 1 + +Variables~ + +*b:match_words* +*b:match_skip* +*b:match_ignorecase* + + match-up understands these variables originally from matchit. 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. + + *matchup-opts-matchparen* +Module matchparen~ + +*g:matchup_matchparen_enabled* + + This option will disable match highlighting at |startup|, e.g., 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. + + Default: 1 + + You can also enable and disable highlighting for specific buffers using the + variable |b:matchup_matchparen_enabled|. + + Customizing the highlighting colors~ + + match-up uses the |MatchParen| highlighting group by default, which can be + configured. For example, > + + :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: > + + 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. > + + :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. > + + :hi MatchParenCur cterm=underline gui=underline + :hi MatchWordCur cterm=underline gui=underline +< +*b:matchup_matchparen_enabled* + + Set to 0 to disable highlighting on a per-buffer basis (there is no command + for this). By default, when disabling highlighting for a particular buffer, + the standard plugin |pi_paren| will still be used for that buffer. + + Default: undefined (equivalent to 1) + +*b:matchup_matchparen_fallback* + + If highlighting is disabled on a particular buffer, match-up will fall back + to the vim standard plugin |pi_paren|, which will highlight 'matchpairs' such + as `()`, `[]`, & `{}`. To disable this, set this option to 0. + + Default: undefined (equivalent to 1) + + A common usage of these options is to automatically disable matchparen for + particular file types: > + + augroup matchup_matchparen_disable_ft + autocmd! + autocmd FileType tex let [b:matchup_matchparen_fallback, + \ b:matchup_matchparen_enabled] = [0, 0] + augroup END +< +*g:matchup_matchparen_singleton* + + Whether or not to highlight recognized words even if there is no match. + + Default: 0 + +*g:matchup_matchparen_offscreen* + + Dictionary controlling the behavior with off-screen matches. 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). + + `'popup'`: Use a popup window (requires at least vim 8.1.1406) or + a floating window (in neovim) to show the off-screen match. + + 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 + + Default: `{'method': 'status'}` + +*g:matchup_matchparen_stopline* + + The number of lines to search in either direction while highlighting + matches. Set this conservatively since high values may cause performance + issues. + + Default: 400 + +*g:matchup_matchparen_timeout* +*g:matchup_matchparen_insert_timeout* + + Adjust the timeouts in milliseconds for highlighting. + + Defaults: `g:matchparen_timeout`, `g:matchparen_insert_timeout` + (300, 60 respectively) + +*b:matchup_matchparen_timeout* +*b:matchup_matchparen_insert_timeout* + + Buffer local versions of the above. + +*g:matchup_matchparen_deferred* + + 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. + + 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. + +*g:matchup_matchparen_deferred_show_delay* + + Delay, in milliseconds, between when the cursor moves and when we start + checking if the cursor is on a match. Applies to both making highlights and + clearing them for deferred highlighting. + + Note: these delays cannot be changed dynamically and should be configured + before the plugin loads (e.g., in your vimrc). + + Default: 50 + +*g:matchup_matchparen_deferred_hide_delay* + + If the cursor has not stopped moving, assume highlight is stale after this + many milliseconds. Stale highlights are hidden. + + Note: this option cannot be changed dynamically. + + Default: 700 + +*g:matchup_matchparen_deferred_fade_time* *matchup-fading* + + When set to {time} in milliseconds, the deferred highlighting behavior + is changed in two ways: + 1. Highlighting of matches is preserved for at least {time} even when + the cursor is moved away. + 2. If the cursor stays on the same match for longer than {time}, + highlighting is cleared. + The effect is that highlighting occurs momentarily and then disappears, + regardless of where the cursor is. It is possible that fading takes + longer than {time}, if vim is busy doing other things. + + This value should be greater than the deferred show delay. + Note: this option cannot be changed dynamically. + + Example: > + + let g:matchup_matchparen_deferred = 1 + let g:matchup_matchparen_deferred_fade_time = 450 +< + Default: 0 (fading disabled) + +*g:matchup_matchparen_pumvisible* + + If set to 1, matches will be made even when the |popupmenu-completion| is + visible. If you use an auto-complete plugin which interacts badly with + matching, set this option to 0. + + Default: 1 + +*g:matchup_matchparen_nomode* + + When not empty, match highlighting will be disabled in the specified modes, + where each mode is a single character like in the |mode()| function. E.g., to + disable highlighting in insert mode, +> + let g:matchup_matchparen_nomode = 'i' +< + and in visual modes, +> + let g:matchup_matchparen_nomode = "vV\" +< + Note: In visual modes, this takes effect only after moving the cursor. + + Default: '' + +*g:matchup_matchparen_hi_surround_always* + + Always highlight the surrounding words, if possible. This is like + |(matchup-hi-surround)| but is updated each time the cursor moves. + This requires deferred matching (|g:matchup_matchparen_deferred| = 1). + + Default: 0 + +*g:matchup_matchparen_hi_background* + + Highlight buffer background between matches. This uses the `MatchBackground` + highlighting group and is linked to `ColorColumn` by default but can be + configured with > + + :hi MatchBackground guibg=grey ctermbg=grey +< + Default: 0 + +Module motion~ + +*g:matchup_motion_override_Npercent* + + In vim, {count}% goes to the {count} percentage in the file (see |N%|). + match-up overrides this motion for small {count} (by default, anything less + than 7). For example, to allow {count}% for {count} up to 11, > + let g:matchup_motion_override_Npercent = 11 +< + To disable this feature, and restore vim's default {count}%, > + let g:matchup_motion_override_Npercent = 0 +< +*g:matchup_motion_cursor_end* + + 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. Set to 0 to disable. + Note: this has no effect on operators: `d%` will delete |inclusive| of the + ending word (this is compatible with matchit). + + Default: 1 + +*g:matchup_delim_count_fail* + + When disabled (default), giving an invalid count to the |[%| and |]%| motions + and the text objects |i%| and |a%| will cause the motion or operation to fail. + When enabled, they will move as far as possible. + Note: targeting high counts when this option is enabled can become slow + because many positions need to be tried before giving up. + + Default: 0 + +Module text_obj~ + +*g:matchup_text_obj_linewise_operators* + + Modifies the set of operators which may operate line-wise with |i%| + (see |matchup-feat-linewise|). + + You may use 'v', 'V', and "\" (i.e., an actual CTRL-V character) to the + specify the corresponding visual mode. + + You can also specify custom plugin operators with 'g@' and optionally, an + expression separated by a comma. For example, to make |commentary|'s |gc| + mapping work likewise when used in the operator `gci%`, > + + function! IsCommentaryOpFunc() + return &operatorfunc ==? matchstr(maparg('Commentary', 'n'), + \ '\c\w\+\ze()\|set op\%(erator\)\?func=\zs.\{-\}\ze') + endfunction + + let g:matchup_text_obj_linewise_operators = ['d', 'y', + \ 'g@,IsCommentaryOpFunc()'] +< + Default: `['d', 'y']` + +Module surround~ + +*g:matchup_surround_enabled* + + Enables the surround module which provides maps |ds%| and |cs%|. + + Default: 0 + +------------------------------------------------------------------------------ +File type options~ + *matchup-file-types* + + *matchup-latex* +LaTeX~ + + By default, match-up is disabled for tex files when the plugin |vimtex| is + detected. To enable match-up for tex files, use the following in your vimrc: > + + let g:matchup_override_vimtex = 1 +< + This will replace vimtex's built-in highlighting and `%` map. + + Note: matching may be computationally intensive for complex LaTeX documents. + If you experience slowdowns, consider using the following option: > + + let g:matchup_matchparen_deferred = 1 +< +Match preferences~ *g:matchup_matchpref* + + A limited number of common preferences are available which affect how + matching is done for a particular filetype. They may be set through the + `matchup_matchpref` dictionary: > + + let g:matchup_matchpref[&filetype].option_name = 1 +< +HTML + +*g:matchup_matchpref.html.nolists* + + When set to 1, this option disables matching and navigation between groups + of list items in HTML documents such as the following > + +
    +
  • One
  • +
  • Two
  • +
+< + By default, `%` will navigate from `
    ` to `
  • ` to `
  • ` to `
`. + + Default: 0 + +*g:matchup_matchpref.html.tagnameonly* + + When set to 1, only the tag name will be highlighted, not the rest of the + tag, e.g., the "a" in > + + Link +< + This works for xml, html, and some other html-based types. + + Default: 0 + +Customization~ + +*g:matchup_hotfix[&filetype]* *matchup-hotfix* + + For each file type, this option can be set to the string name of a function + which will be called when loading files, prior to checking |b:match_words| + and |b:match_skip|. This option can be used to quickly customize matching for + particular file types: > + + function! VimHotfix() + " customization + endfunction + let g:matchup_hotfix['vim'] = 'VimHotfix' + +*b:matchup_hotfix* + + This is an alternative buffer-local name for adding customization. + +*matchup#util#patch_match_words* *matchup-patch* +> + call matchup#util#patch_match_words(before, after) +< + This function replaces the literal string `before` contained in |b:match_words| + with the literal string `after`. When placed in an autocommand or in the file + `after/ftplugin/{&filetype}.vim`, it can be used to customize the matching + regular expressions for a particular file type. + +*matchup#util#append_match_words* *matchup-append* +> + call matchup#util#append_match_words(str) +< + Adds a set of patterns to |b:match_words|, adding a comma if necessary. + +============================================================================== +FAQ *matchup-faq* + +Q match-up doesn't work + +A 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. + +Q Why does jumping not work for construct X in language Y? + +A Please open a new issue + +Q Highlighting is not correct for construct X + +A 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 a specific as possible. + +Q I'm having performance problems + +A 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: + + - Update to a recent version of vim. Newer versions are faster, more + extensively tested, and better supported by match-up. + + - Try deferred highlighting, which delays highlighting until the cursor is + stationary to improve cursor movement performance. + |g:matchup_matchparen_deferred| + + - Lower the highlighting timeouts. If highlighting takes longer than the + timeout, highlighting will not be attempted again until the cursor moves. + |g:matchup_matchparen_timeout|, |g:matchup_matchparen_insert_timeout| + + If are having any other performance issues, please open a new issue and + report the output of `:MatchupShowTimes`. + +Q Why is there a weird entry on the status line? + +A 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 > + + let g:matchup_matchparen_offscreen = {} +< +Q Matching does not work when lines are too far apart. + +A The number of search lines is limited for performance reasons. You may + increase the limits with the following options: > + + let g:matchup_delim_stopline = 1500 " generally + let g:matchup_matchparen_stopline = 400 " for match highlighting only +< +Q The maps `1i%` and `1a%` are difficult to press. + +A You may use the following maps `I%` and `A%` for convenience: > + + function! s:matchup_convenience_maps() + xnoremap (std-I) I + xnoremap (std-A) A + xmap I mode()==''?'(std-I)':(v:count?'':'1').'i' + xmap A mode()==''?'(std-A)':(v:count?'':'1').'a' + for l:v in ['', 'v', 'V', ''] + execute 'omap ' l:v.'I%' "(v:count?'':'1').'".l:v."i%'" + execute 'omap ' 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. + +Q How can I contribute? + +A 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 *matchup-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 > + + 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. + +Matchit~ + +matchit.vim should not be loaded. If it is loaded, it must be loaded after +match-up (in this case, matchit.vim will be disabled). Note that some plugins, +such as vim-sensible, load matchit.vim so these must 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. + +Other plugins~ + +match-up does not currently provide support for auto-completion. The +following plugins may be useful 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 + +There is basic support for deleting and changing surroundings, but you may +prefer to use one of the following: + +- |vim-surround| https://github.com/tpope/vim-surround +- |vim-sandwich| https://github.com/machakann/vim-sandwich + +============================================================================== +ACKNOWLEDGMENTS *matchup-acknowledgments* + +Origins~ + +|match-up| was originally based on Karl Yngve Lervåg's |vimtex|. The concept +and style of this plugin and its development are heavily influenced by vimtex. + +[vimtex]: https://github.com/lervag/vimtex + +Other inspirations~ + +- |matchit| +- |matchparen| +- |MatchTag| https://github.com/gregsexton/MatchTag +- |MatchTagAlways| https://github.com/Valloric/MatchTagAlways + +============================================================================== +DEVELOPMENT *matchup-development* + +Development is tracked at https://github.com/andymass/vim-matchup. + +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 first +(ISSUE_TEMPLATE.md). 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. + +============================================================================== + vim:tw=78:ts=8:ft=help:norl:fen:fdl=0:fdm=marker diff --git a/etc/soft/nvim/+plugins/vim-matchup/plugin/matchup.vim b/etc/soft/nvim/+plugins/vim-matchup/plugin/matchup.vim new file mode 100644 index 0000000..009e38d --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/addrtp.vim b/etc/soft/nvim/+plugins/vim-matchup/test/addrtp.vim new file mode 100644 index 0000000..0943fbd --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/addrtp.vim @@ -0,0 +1,8 @@ + +" rtp for testing files + +let s:path = expand(':h') +let &rtp = s:path.'/rtp,' . &rtp + +runtime! ftdetect/matchuptest.vim + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/augment.matchuptest b/etc/soft/nvim/+plugins/vim-matchup/test/augment.matchuptest new file mode 100644 index 0000000..af4e4b3 --- /dev/null +++ b/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 : diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/bootstrap.vim b/etc/soft/nvim/+plugins/vim-matchup/test/bootstrap.vim new file mode 100644 index 0000000..32fb017 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/bootstrap.vim @@ -0,0 +1,18 @@ +set nocompatible + +" load match-up +let s:path = simplify(expand(':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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/forwhile.vim b/etc/soft/nvim/+plugins/vim-matchup/test/forwhile.vim new file mode 100644 index 0000000..a11e132 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/hlend.matchuptest b/etc/soft/nvim/+plugins/vim-matchup/test/hlend.matchuptest new file mode 100644 index 0000000..29adcba --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/10/legacy.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/10/legacy.vim new file mode 100644 index 0000000..6c371ba --- /dev/null +++ b/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 = "( \\( )" . "\\( " . '\( \)' . "\\)" + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/10/string.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/10/string.vim new file mode 100644 index 0000000..9d21130 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/14/example.tex b/etc/soft/nvim/+plugins/vim-matchup/test/issues/14/example.tex new file mode 100644 index 0000000..6215c71 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/15/enhance-vimrc b/etc/soft/nvim/+plugins/vim-matchup/test/issues/15/enhance-vimrc new file mode 100644 index 0000000..067a8ac --- /dev/null +++ b/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('Commentary', 'n'), + \ '\cset op\%(erator\)\?func=\zs.\{-\}\ze') +endfunction + +let g:matchup_text_obj_linewise_operators = ['d', 'y', + \ 'g@,IsCommentaryOpFunc()', 'V'] + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/15/gc.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/15/gc.vim new file mode 100644 index 0000000..787fcc3 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/15/issue-vimrc b/etc/soft/nvim/+plugins/vim-matchup/test/issues/15/issue-vimrc new file mode 100644 index 0000000..9b189d4 --- /dev/null +++ b/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@', ':'] + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/16/any.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/16/any.vim new file mode 100644 index 0000000..81b7e76 --- /dev/null +++ b/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 + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/16/blocks.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/16/blocks.vim new file mode 100644 index 0000000..e2daf65 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/19/hotfix.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/19/hotfix.vim new file mode 100644 index 0000000..a0a9812 --- /dev/null +++ b/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' + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/19/option.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/19/option.vim new file mode 100644 index 0000000..0243e7a --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/19/option.vim @@ -0,0 +1,3 @@ + +let g:matchup_matchpref_html_nolists = 1 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/19/test.html b/etc/soft/nvim/+plugins/vim-matchup/test/issues/19/test.html new file mode 100644 index 0000000..2c240c3 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/19/test.html @@ -0,0 +1,6 @@ + +
    +
  • +
  • +
+ diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/21/Matchup_Problem_File.txt b/etc/soft/nvim/+plugins/vim-matchup/test/issues/21/Matchup_Problem_File.txt new file mode 100644 index 0000000..15a3d57 --- /dev/null +++ b/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 + } + { + } + } + } +} diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/26/example.rb b/etc/soft/nvim/+plugins/vim-matchup/test/issues/26/example.rb new file mode 100644 index 0000000..4045778 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/3/hotfix.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/3/hotfix.vim new file mode 100644 index 0000000..e0c0ddf --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/3/hotfix.vim @@ -0,0 +1,16 @@ + +function! SQLHotFix() + call matchup#util#patch_match_words( + \ '\%(\', + \ '\%(\' + \ . ':\' + \ . ':\\ze\%(\s\+next\)\@!\%(.\|$\)' + \) +endfunction + +let g:matchup_hotfix_sql = 'SQLHotFix' + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/complex-hl.html b/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/complex-hl.html new file mode 100644 index 0000000..01617af --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/complex-hl.html @@ -0,0 +1,7 @@ + + + + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.html b/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.html new file mode 100644 index 0000000..908da7c --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.html @@ -0,0 +1,22 @@ + + + item + + + + item + + +
    +
  • text
  • +
+ +
    +
  • text
  • +
+ +
+
Question 1
+
+ diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.vue b/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.vue new file mode 100644 index 0000000..908da7c --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/example.vue @@ -0,0 +1,22 @@ + + + item + + + + item + + +
    +
  • text
  • +
+ +
    +
  • text
  • +
+ +
+
Question 1
+
+ diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/minvimrc b/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/minvimrc new file mode 100644 index 0000000..8d26c8d --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/30/minvimrc @@ -0,0 +1,16 @@ +set nocompatible + +" load match-up +let s:path = simplify(expand(':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, }, + \} + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/33/minvimrc b/etc/soft/nvim/+plugins/vim-matchup/test/issues/33/minvimrc new file mode 100644 index 0000000..b3f579f --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/33/test.rb b/etc/soft/nvim/+plugins/vim-matchup/test/issues/33/test.rb new file mode 100644 index 0000000..bdcc96d --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/34/endvar.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/34/endvar.vim new file mode 100644 index 0000000..3317bab --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/36/image_uploader.rb b/etc/soft/nvim/+plugins/vim-matchup/test/issues/36/image_uploader.rb new file mode 100644 index 0000000..64bd79f --- /dev/null +++ b/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 diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/Sample.jsx b/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/Sample.jsx new file mode 100644 index 0000000..cf82673 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/Sample.jsx @@ -0,0 +1,5 @@ + +const Sample = + some body +; + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc1 b/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc1 new file mode 100644 index 0000000..1ef19d7 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc1 @@ -0,0 +1,26 @@ +set nocompatible + +" load match-up +let s:path = simplify(expand(':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' } + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc2 b/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc2 new file mode 100644 index 0000000..2481959 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/46/minvimrc2 @@ -0,0 +1,26 @@ +set nocompatible + +" load match-up +let s:path = simplify(expand(':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' + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/minvimrc b/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/minvimrc new file mode 100644 index 0000000..686602b --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/minvimrc @@ -0,0 +1,20 @@ +set nocompatible + +" load match-up +let s:path = simplify(expand(':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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/new.xml b/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/new.xml new file mode 100644 index 0000000..8e1775a --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/new.xml @@ -0,0 +1,3 @@ + x + + a '' diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/simple.xml b/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/simple.xml new file mode 100644 index 0000000..39c2d74 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/simple.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/vim-matchup-20181230.xml b/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/vim-matchup-20181230.xml new file mode 100644 index 0000000..75d3380 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/48/vim-matchup-20181230.xml @@ -0,0 +1,28 @@ + + + + + + + + + $CHECK_FZF + CHECK_FZF + 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 + + + + + + + + + + + CHECK_FZF_WINDOW + closewindow:CHECK_FZF_WINDOW + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/49/example.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/49/example.vim new file mode 100644 index 0000000..f88b0d2 --- /dev/null +++ b/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 }) + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/49/test.sh b/etc/soft/nvim/+plugins/vim-matchup/test/issues/49/test.sh new file mode 100644 index 0000000..63bf97a --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/51/test.f90 b/etc/soft/nvim/+plugins/vim-matchup/test/issues/51/test.f90 new file mode 100644 index 0000000..4650486 --- /dev/null +++ b/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 diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/54/foo.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/54/foo.vim new file mode 100644 index 0000000..e55ca50 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/59/rebind.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/59/rebind.vim new file mode 100644 index 0000000..fdb9be9 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/59/rebind.vim @@ -0,0 +1,9 @@ + +source ../../bootstrap.vim + +xmap u% (matchup-i%) +omap u% (matchup-i%) + +" optional, for use without patch 8.1.0648 +call call(matchup#motion_sid().'make_oldstyle_omaps', ['u%', 'i%']) + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/63/test.f90 b/etc/soft/nvim/+plugins/vim-matchup/test/issues/63/test.f90 new file mode 100644 index 0000000..d536de0 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/64/ast.cc b/etc/soft/nvim/+plugins/vim-matchup/test/issues/64/ast.cc new file mode 100644 index 0000000..dc87df8 --- /dev/null +++ b/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(); +} + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/69/cpptemplate.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/69/cpptemplate.vim new file mode 100644 index 0000000..93a7657 --- /dev/null +++ b/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\@!\)=\@!') +endfunction +if !exists('g:matchup_hotfix') + let g:matchup_hotfix = {} +endif +let g:matchup_hotfix.cpp = 'CppTemplate' +set matchpairs-=<:> + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/69/template.cpp b/etc/soft/nvim/+plugins/vim-matchup/test/issues/69/template.cpp new file mode 100644 index 0000000..c60adb2 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/69/template.cpp @@ -0,0 +1,6 @@ + typedef BOOST_DEDUCED_TYPENAME boost::conditional< + boost::is_signed::value, + boost::make_signed, + boost::type_identity + >::type no_cvr_prefinal_lazy_t; + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/augroup.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/augroup.vim new file mode 100644 index 0000000..8d43218 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/augroup.vim @@ -0,0 +1,6 @@ + +augroup nomatchparen + autocmd! + autocmd VimEnter * NoMatchParen +augroup END + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix.vim new file mode 100644 index 0000000..c30a6d4 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix.vim @@ -0,0 +1,9 @@ + +function! AugroupHotfix() + call matchup#util#patch_match_words( + \ '\\)\@!\S:', + \ '\\)\@!\S\+:') +endfunction + +let g:matchup_hotfix_vim = 'AugroupHotfix' + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix2.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix2.vim new file mode 100644 index 0000000..3a48e23 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/7/hotfix2.vim @@ -0,0 +1,9 @@ + +function! AugroupHotfix() + call matchup#util#patch_match_words( + \ '\\)\@!\S:', + \ '\\)\@!\S\@=:') +endfunction + +let g:matchup_hotfix_vim = 'AugroupHotfix' + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex.html b/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex.html new file mode 100644 index 0000000..99a1bf8 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex.html @@ -0,0 +1,8 @@ + + + + + 数据加载中。。。 + + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex2.html b/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex2.html new file mode 100644 index 0000000..ef133c3 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/flex2.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/hotfix.vim b/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/hotfix.vim new file mode 100644 index 0000000..59982e2 --- /dev/null +++ b/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' + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/slash.html b/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/slash.html new file mode 100644 index 0000000..cc0d7f2 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/issues/8/slash.html @@ -0,0 +1,4 @@ + +
hello world
+
hello world
+ diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/lang/lua/tohtml.lua b/etc/soft/nvim/+plugins/vim-matchup/test/lang/lua/tohtml.lua new file mode 100644 index 0000000..6c9603d --- /dev/null +++ b/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] = "" .. flat(i) .. "".. tohtml_table(v, table_level + 1) + else + lineout[k] = "MAXIMUM LEVEL BREACHED" + 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 .. "" .. line .. "\n" + else + s = s .. "" .. line .. "\n" + end + end + if not (tablefound) then + s = "" .. + "" .. s .. "
\n" + else + tcolor = html_colors[table_level] + s = "" .. + s .. "
\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 diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/lang/ruby/next.rb b/etc/soft/nvim/+plugins/vim-matchup/test/lang/ruby/next.rb new file mode 100644 index 0000000..e08dd68 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/minvimrc b/etc/soft/nvim/+plugins/vim-matchup/test/minvimrc new file mode 100644 index 0000000..c75313c --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/mwe.vim b/etc/soft/nvim/+plugins/vim-matchup/test/mwe.vim new file mode 100644 index 0000000..6e0e593 --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/parens.txt b/etc/soft/nvim/+plugins/vim-matchup/test/parens.txt new file mode 100644 index 0000000..70ebdbd --- /dev/null +++ b/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 + + + } } | + + +---- + ( ( (( )) ) ) +---- + +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/parts.vim b/etc/soft/nvim/+plugins/vim-matchup/test/parts.vim new file mode 100644 index 0000000..8676348 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/parts.vim @@ -0,0 +1,9 @@ + + +function + return + + break +endwhile + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftdetect/matchuptest.vim b/etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftdetect/matchuptest.vim new file mode 100644 index 0000000..a87d497 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftdetect/matchuptest.vim @@ -0,0 +1,2 @@ +autocmd BufNewFile,BufRead *.matchuptest setlocal filetype=matchuptest + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftplugin/matchuptest.vim b/etc/soft/nvim/+plugins/vim-matchup/test/rtp/ftplugin/matchuptest.vim new file mode 100644 index 0000000..abfc456 --- /dev/null +++ b/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 = + " \ '\:\:\,' . + " \ '\<\(wh\%[ile]\|for\)\>:\:\:\,' . + " \ '\:\:\,' . + " \ '\:\:\:\,' . + " \ '\\)\@!\S:\,' . + " \ '(:)' + + " 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 .= ',\:\' + let b:match_words .= ',\:\' + let b:match_words .= ',\:\' + let b:match_words .= ',\%(end\)\@\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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/startup.sh b/etc/soft/nvim/+plugins/vim-matchup/test/startup.sh new file mode 100755 index 0000000..c8f0cbb --- /dev/null +++ b/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" + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/tabs.vim b/etc/soft/nvim/+plugins/vim-matchup/test/tabs.vim new file mode 100644 index 0000000..e88c879 --- /dev/null +++ b/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 + + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/test.html b/etc/soft/nvim/+plugins/vim-matchup/test/test.html new file mode 100644 index 0000000..b8ca0e9 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/test.html @@ -0,0 +1,13 @@ + + + + +Title of the document + + + +Content of the document...... + + + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/textobjV.vim b/etc/soft/nvim/+plugins/vim-matchup/test/textobjV.vim new file mode 100644 index 0000000..c1e9a7e --- /dev/null +++ b/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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/transmute.html b/etc/soft/nvim/+plugins/vim-matchup/test/transmute.html new file mode 100644 index 0000000..52c67cc --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/transmute.html @@ -0,0 +1,5 @@ + + + + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/transmute2.html b/etc/soft/nvim/+plugins/vim-matchup/test/transmute2.html new file mode 100644 index 0000000..9a9ac2e --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/transmute2.html @@ -0,0 +1,19 @@ + + + + +Title of the document + + + + + + +Content of the document...... + + + + + + + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/unicode.matchuptest b/etc/soft/nvim/+plugins/vim-matchup/test/unicode.matchuptest new file mode 100644 index 0000000..42910b0 --- /dev/null +++ b/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 : diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vader/issue-66.vader b/etc/soft/nvim/+plugins/vim-matchup/test/vader/issue-66.vader new file mode 100644 index 0000000..233e275 --- /dev/null +++ b/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\ + 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 diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vader/minvimrc b/etc/soft/nvim/+plugins/vim-matchup/test/vader/minvimrc new file mode 100644 index 0000000..39b5fd8 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/vader/minvimrc @@ -0,0 +1,26 @@ +set nocompatible + +" load match-up +let s:path = simplify(expand(':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 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vader/motion.vader b/etc/soft/nvim/+plugins/vim-matchup/test/vader/motion.vader new file mode 100644 index 0000000..28ab18e --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/vader/motion.vader @@ -0,0 +1,23 @@ +Given vim (Nesting): + + if + if + if + + endif + endif + endif + +Before (Cursor): + normal! 5gg + +Do (Move [%): + [% +Then (Verify line): + Assert line('.') == 4 + +Do (Move [% twice): + [%[% +Then (Verify line): + Assert line('.') == 3 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vader/motion_force.vader b/etc/soft/nvim/+plugins/vim-matchup/test/vader/motion_force.vader new file mode 100644 index 0000000..20d85fc --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/vader/motion_force.vader @@ -0,0 +1,23 @@ +Given (Single-line parentheses): + (hello world)| + +Before (): + normal! gg0f( + +Do (Delete %): + d% +Expect (Verify): + | +Do (Delete v%): + dv% +Expect (Verify): + )| +Do (Delete V%): + dV% +Expect (Verify): + +Do (Delete %): + d% +Expect (Verify): + | + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vader/ruby.vader b/etc/soft/nvim/+plugins/vim-matchup/test/vader/ruby.vader new file mode 100644 index 0000000..097bd46 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/vader/ruby.vader @@ -0,0 +1,40 @@ +Given ruby (Ruby for if): + for i in 0..5 + if i < 2 then + next + end + puts "Value of local variable is #{i}" + end + +Do (Motion %): + go + % + +Then (Verify): + AssertEqual 'next', expand('') + +Given ruby (Ruby do end): + context 'webhooks' do + before { allow_any_instance_of(described_class).to receive(:webhook_endpoint_active?).and_return(true) } + + it 'runs webhooks' do + expect(Webhook::Runner).to receive(:deliver) + subject + end + end + +Do (Motion %): + go2W + % + +Then (Verify): + AssertEqual 'end', getline('.') + +Do (Motion %): + 2ggee + % + % + +Then (Verify): + AssertEqual '{', getline('.')[col('.')-1] + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vader/run b/etc/soft/nvim/+plugins/vim-matchup/test/vader/run new file mode 100755 index 0000000..d185244 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/vader/run @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +cd "$(dirname "${BASH_SOURCE[0]}")" +${VIMCMD:-vim} -Nu minvimrc +"Vader! ${1:-*}" + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vader/syn.vader b/etc/soft/nvim/+plugins/vim-matchup/test/vader/syn.vader new file mode 100644 index 0000000..8d7a784 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/vader/syn.vader @@ -0,0 +1,17 @@ +Execute (opts): + let matchup_matchparen_offscreen = {} + let matchup_delim_noskips = 2 + +Given scheme (Syntax): + (define procname ; ) in comment isn't matched as expected + ") in string is however matched" + body) + +Before (): + 2normal! f) + +Do (%): + % +Then (Verify line): + Assert line('.') == 2 + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vader/text_obj.vader b/etc/soft/nvim/+plugins/vim-matchup/test/vader/text_obj.vader new file mode 100644 index 0000000..043e017 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/vader/text_obj.vader @@ -0,0 +1,40 @@ +Given (Parentheses): + ( + + + + ) + + ( hello + + + + ) + + (vibd) + (dvib) + (dib) + () + +Do (Delete inner %): + 16gg0 + di% + kdi% + kdvi% + kvi%d + 3kdi% + 4kdi% + +Expect (Verify): + ( + ) + + ( + + ) + + () + (b) + () + () + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/vimrc-startup b/etc/soft/nvim/+plugins/vim-matchup/test/vimrc-startup new file mode 100644 index 0000000..933ed2b --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/vimrc-startup @@ -0,0 +1,14 @@ +set nocompatible + +let &rtp = '~/.vim/bundle/vim-matchup,' . &rtp +let &rtp .= ',~/.vim/bundle/vim-matchup/after' + +let g:matchup_delim_start_plaintext = !!$TEST_PLAIN +" let g:matchup_matchparen_enabled = 0 + +filetype plugin indent on +syntax enable + +autocmd VimEnter * put!=execute('MatchupShowTimes')|set nomodified +nnoremap q :quit + diff --git a/etc/soft/nvim/+plugins/vim-matchup/test/zsze.matchuptest b/etc/soft/nvim/+plugins/vim-matchup/test/zsze.matchuptest new file mode 100644 index 0000000..6d46096 --- /dev/null +++ b/etc/soft/nvim/+plugins/vim-matchup/test/zsze.matchuptest @@ -0,0 +1,14 @@ + +bazbar + +barbaz + +zabrab + +rabzab + +where + +when + +" vim: set ft=matchuptest : diff --git a/etc/soft/nvim/+plugins_disabled/matchit/doc/matchit.txt b/etc/soft/nvim/+plugins_disabled/matchit/doc/matchit.txt new file mode 100644 index 0000000..8a3a96e --- /dev/null +++ b/etc/soft/nvim/+plugins_disabled/matchit/doc/matchit.txt @@ -0,0 +1,406 @@ +*matchit.txt* Extended "%" matching + +For instructions on installing this file, type + :help matchit-install +inside Vim. + +For Vim version 6.3. Last change: 2007 Aug 29 + + + VIM REFERENCE MANUAL by Benji Fisher + +*matchit* *matchit.vim* + +1. Extended matching with "%" |matchit-intro| +2. Activation |matchit-activate| +3. Configuration |matchit-configure| +4. Supporting a New Language |matchit-newlang| +5. Known Bugs and Limitations |matchit-bugs| + +The functionality mentioned here is a plugin, see |add-plugin|. +This plugin is only available if 'compatible' is not set. +You can avoid loading this plugin by setting the "loaded_matchit" variable +in your |vimrc| file: > + :let loaded_matchit = 1 + +{Vi does not have any of this} + +============================================================================== +1. Extended matching with "%" *matchit-intro* + + *matchit-%* +% Cycle forward through matching groups, such as "if", "else", "endif", + as specified by |b:match_words|. + + *g%* *v_g%* *o_g%* +g% Cycle backwards through matching groups, as specified by + |b:match_words|. For example, go from "if" to "endif" to "else". + + *[%* *v_[%* *o_[%* +[% Go to [count] previous unmatched group, as specified by + |b:match_words|. Similar to |[{|. + + *]%* *v_]%* *o_]%* +]% Go to [count] next unmatched group, as specified by + |b:match_words|. Similar to |]}|. + + *v_a%* +a% In Visual mode, select the matching group, as specified by + |b:match_words|, containing the cursor. Similar to |v_a[|. + A [count] is ignored, and only the first character of the closing + pattern is selected. + +In Vim, as in plain vi, the percent key, |%|, jumps the cursor from a brace, +bracket, or paren to its match. This can be configured with the 'matchpairs' +option. The matchit plugin extends this in several ways: + + You can match whole words, such as "if" and "endif", not just + single characters. You can also specify a |regular-expression|. + You can define groups with more than two words, such as "if", + "else", "endif". Banging on the "%" key will cycle from the "if" to + the first "else", the next "else", ..., the closing "endif", and back + to the opening "if". Nested structures are skipped. Using |g%| goes + in the reverse direction. + By default, words inside comments and strings are ignored, unless + the cursor is inside a comment or string when you type "%". If the + only thing you want to do is modify the behavior of "%" so that it + behaves this way, you do not have to define |b:match_words|, since the + script uses the 'matchpairs' option as well as this variable. + +See |matchit-details| for details on what the script does, and |b:match_words| +for how to specify matching patterns. + +MODES: *matchit-modes* *matchit-v_%* *matchit-o_%* + +Mostly, % and related motions (|g%| and |[%| and |]%|) work just like built-in +|motion| commands in |Operator-pending| and |Visual| modes. However, you +cannot make these motions |linewise| or |characterwise|, since the |:omap|s +that define them start with "v" in order to make the default behavior +inclusive. (See |o_v|.) In other words, "dV%" will not work. The +work-around is to go through Visual mode: "V%d" will work. + +LANGUAGES: *matchit-languages* + +Currently, the following languages are supported: Ada, ASP with VBS, Csh, +DTD, Entity, Essbase, Fortran, HTML, JSP (same as HTML), LaTeX, Lua, Pascal, +SGML, Shell, Tcsh, Vim, XML. Other languages may already have support via +the default |filetype-plugin|s in the standard vim distribution. + +To support a new language, see |matchit-newlang| below. + +DETAILS: *matchit-details* *matchit-parse* + +Here is an outline of what matchit.vim does each time you hit the "%" key. If +there are |backref|s in |b:match_words| then the first step is to produce a +version in which these back references have been eliminated; if there are no +|backref|s then this step is skipped. This step is called parsing. For +example, "\(foo\|bar\):end\1" is parsed to yield +"\(foo\|bar\):end\(foo\|bar\)". This can get tricky, especially if there are +nested groups. If debugging is turned on, the parsed version is saved as +|b:match_pat|. + + *matchit-choose* +Next, the script looks for a word on the current line that matches the pattern +just constructed. It includes the patterns from the 'matchpairs' option. +The goal is to do what you expect, which turns out to be a little complicated. +The script follows these rules: + + Insist on a match that ends on or after the cursor. + Prefer a match that includes the cursor position (that is, one that + starts on or before the cursor). + Prefer a match that starts as close to the cursor as possible. + If more than one pattern in |b:match_words| matches, choose the one + that is listed first. + +Examples: + + Suppose you > + :let b:match_words = '<:>,:' +< and hit "%" with the cursor on or before the "<" in "a is born". + The pattern '<' comes first, so it is preferred over '', which + also matches. If the cursor is on the "t", however, then '' is + preferred, because this matches a bit of text containing the cursor. + If the two groups of patterns were reversed then '<' would never be + preferred. + + Suppose you > + :let b:match_words = 'if:end if' +< (Note the space!) and hit "%" with the cursor at the end of "end if". + Then "if" matches, which is probably not what you want, but if the + cursor starts on the "end " then "end if" is chosen. (You can avoid + this problem by using a more complicated pattern.) + +If there is no match, the cursor does not move. (Before version 1.13 of the +script, it would fall back on the usual behavior of |%|). If debugging is +turned on, the matched bit of text is saved as |b:match_match| and the cursor +column of the start of the match is saved as |b:match_col|. + +Next, the script looks through |b:match_words| (original and parsed versions) +for the group and pattern that match. If debugging is turned on, the group is +saved as |b:match_ini| (the first pattern) and |b:match_tail| (the rest). If +there are |backref|s then, in addition, the matching pattern is saved as +|b:match_word| and a table of translations is saved as |b:match_table|. If +there are |backref|s, these are determined from the matching pattern and +|b:match_match| and substituted into each pattern in the matching group. + +The script decides whether to search forwards or backwards and chooses +arguments for the |searchpair()| function. Then, the cursor is moved to the +start of the match, and |searchpair()| is called. By default, matching +structures inside strings and comments are ignored. This can be changed by +setting |b:match_skip|. + +============================================================================== +2. Activation *matchit-activate* + +You can use this script as a plugin, by copying it to your plugin directory. +See |add-global-plugin| for instructions. You can also add a line to your +|vimrc| file, such as > + :source $VIMRUNTIME/macros/matchit.vim +or > + :runtime macros/matchit.vim +Either way, the script should start working the next time you start up Vim. + +(Earlier versions of the script did nothing unless a |buffer-variable| named +|b:match_words| was defined. Even earlier versions contained autocommands +that set this variable for various file types. Now, |b:match_words| is +defined in many of the default |filetype-plugin|s instead.) + +For a new language, you can add autocommands to the script or to your vimrc +file, but the recommended method is to add a line such as > + let b:match_words = '\:\' +to the |filetype-plugin| for your language. See |b:match_words| below for how +this variable is interpreted. + +TROUBLESHOOTING *matchit-troubleshoot* + +The script should work in most installations of Vim. It may not work if Vim +was compiled with a minimal feature set, for example if the |+syntax| option +was not enabled. If your Vim has support for syntax compiled in, but you do +not have |syntax| highlighting turned on, matchit.vim should work, but it may +fail to skip matching groups in comments and strings. If the |filetype| +mechanism is turned off, the |b:match_words| variable will probably not be +defined automatically. + +============================================================================== +3. Configuration *matchit-configure* + +There are several variables that govern the behavior of matchit.vim. Note +that these are variables local to the buffer, not options, so use |:let| to +define them, not |:set|. Some of these variables have values that matter; for +others, it only matters whether the variable has been defined. All of these +can be defined in the |filetype-plugin| or autocommand that defines +|b:match_words| or "on the fly." + +The main variable is |b:match_words|. It is described in the section below on +supporting a new language. + + *MatchError* *matchit-hl* *matchit-highlight* +MatchError is the highlight group for error messages from the script. By +default, it is linked to WarningMsg. If you do not want to be bothered by +error messages, you can define this to be something invisible. For example, +if you use the GUI version of Vim and your command line is normally white, you +can do > + :hi MatchError guifg=white guibg=white +< + *b:match_ignorecase* +If you > + :let b:match_ignorecase = 1 +then matchit.vim acts as if 'ignorecase' is set: for example, "end" and "END" +are equivalent. If you > + :let b:match_ignorecase = 0 +then matchit.vim treats "end" and "END" differently. (There will be no +b:match_infercase option unless someone requests it.) + + *b:match_debug* +Define b:match_debug if you want debugging information to be saved. See +|matchit-debug|, below. + + *b:match_skip* +If b:match_skip is defined, it is passed as the skip argument to +|searchpair()|. This controls when matching structures are skipped, or +ignored. By default, they are ignored inside comments and strings, as +determined by the |syntax| mechanism. (If syntax highlighting is turned off, +nothing is skipped.) You can set b:match_skip to a string, which evaluates to +a non-zero, numerical value if the match is to be skipped or zero if the match +should not be skipped. In addition, the following special values are +supported by matchit.vim: + 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 +(The "s" is meant to suggest "syntax", and the "r" is meant to suggest +"regular expression".) + +Examples: + + You can get the default behavior with > + :let b:match_skip = 's:comment\|string' +< + If you want to skip matching structures unless they are at the start + of the line (ignoring whitespace) then you can > + :let b:match_skip = 'R:^\s*' +< Do not do this if strings or comments can span several lines, since + the normal syntax checking will not be done if you set b:match_skip. + + In LaTeX, since "%" is used as the comment character, you can > + :let b:match_skip = 'r:%' +< Unfortunately, this will skip anything after "\%", an escaped "%". To + allow for this, and also "\\%" (an excaped backslash followed by the + comment character) you can > + :let b:match_skip = 'r:\(^\|[^\\]\)\(\\\\\)*%' +< + See the $VIMRUNTIME/ftplugin/vim.vim for an example that uses both + syntax and a regular expression. + +============================================================================== +4. Supporting a New Language *matchit-newlang* + *b:match_words* +In order for matchit.vim to support a new language, you must define a suitable +pattern for |b:match_words|. You may also want to set some of the +|matchit-configure| variables, as described above. If your language has a +complicated syntax, or many keywords, you will need to know something about +Vim's |regular-expression|s. + +The format for |b:match_words| is similar to that of the 'matchpairs' option: +it is a comma (,)-separated list of groups; each group is a colon(:)-separated +list of patterns (regular expressions). Commas and backslashes that are part +of a pattern should be escaped with backslashes ('\:' and '\,'). It is OK to +have only one group; the effect is undefined if a group has only one pattern. +A simple example is > + :let b:match_words = '\:\,' + \ . '\:\:\:\' +(In Vim regular expressions, |\<| and |\>| denote word boundaries. Thus "if" +matches the end of "endif" but "\" does not.) Then banging on the "%" +key will bounce the cursor between "if" and the matching "endif"; and from +"while" to any matching "continue" or "break", then to the matching "endwhile" +and back to the "while". It is almost always easier to use |literal-string|s +(single quotes) as above: '\' rather than "\\" and so on. + +Exception: If the ":" character does not appear in b:match_words, then it is +treated as an expression to be evaluated. For example, > + :let b:match_words = 'GetMatchWords()' +allows you to define a function. This can return a different string depending +on the current syntax, for example. + +Once you have defined the appropriate value of |b:match_words|, you will +probably want to have this set automatically each time you edit the +appropriate file type. The recommended way to do this is by adding the +definition to a |filetype-plugin| file. + +Tips: Be careful that your initial pattern does not match your final pattern. +See the example above for the use of word-boundary expressions. It is usually +better to use ".\{-}" (as many as necessary) instead of ".*" (as many as +possible). See |\{-|. For example, in the string "label", "<.*>" +matches the whole string whereas "<.\{-}>" and "<[^>]*>" match "" and +"". + + *matchit-spaces* *matchit-s:notend* +If "if" is to be paired with "end if" (Note the space!) then word boundaries +are not enough. Instead, define a regular expression s:notend that will match +anything but "end" and use it as follows: > + :let s:notend = '\%(\:\' +< *matchit-s:sol* +This is a simplified version of what is done for Ada. The s:notend is a +|script-variable|. Similarly, you may want to define a start-of-line regular +expression > + :let s:sol = '\%(^\|;\)\s*' +if keywords are only recognized after the start of a line or after a +semicolon (;), with optional white space. + + *matchit-backref* *matchit-\1* +In any group, the expressions |\1|, |\2|, ..., |\9| refer to parts of the +INITIAL pattern enclosed in |\(|escaped parentheses|\)|. These are referred +to as back references, or backrefs. For example, > + :let b:match_words = '\:\(h\)\1\>' +means that "bo" pairs with "ho" and "boo" pairs with "hoo" and so on. Note +that "\1" does not refer to the "\(h\)" in this example. If you have +"\(nested \(parentheses\)\) then "\d" refers to the d-th "\(" and everything +up to and including the matching "\)": in "\(nested\(parentheses\)\)", "\1" +refers to everything and "\2" refers to "\(parentheses\)". If you use a +variable such as |s:notend| or |s:sol| in the previous paragraph then remember +to count any "\(" patterns in this variable. You do not have to count groups +defined by |\%(\)|. + +It should be possible to resolve back references from any pattern in the +group. For example, > + :let b:match_words = '\(foo\)\(bar\):more\1:and\2:end\1\2' +would not work because "\2" cannot be determined from "morefoo" and "\1" +cannot be determined from "andbar". On the other hand, > + :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' +should work (and have the same effect as "foobar:barfoo:endfoobar"), although +this has not been thoroughly tested. + +You can use |zero-width| patterns such as |\@<=| and |\zs|. (The latter has +not been thouroughly tested in matchit.vim.) For example, if the keyword "if" +must occur at the start of the line, with optional white space, you might use +the pattern "\(^\s*\)\@<=if" so that the cursor will end on the "i" instead of +at the start of the line. For another example, if HTML had only one tag then +one could > + :let b:match_words = '<:>,<\@<=tag>:<\@<=/tag>' +so that "%" can bounce between matching "<" and ">" pairs or (starting on +"tag" or "/tag") between matching tags. Without the |\@<=|, the script would +bounce from "tag" to the "<" in "", and another "%" would not take you +back to where you started. + +DEBUGGING *matchit-debug* *:MatchDebug* + +If you are having trouble figuring out the appropriate definition of +|b:match_words| then you can take advantage of the same information I use when +debugging the script. This is especially true if you are not sure whether +your patterns or my script are at fault! To make this more convenient, I have +made the command :MatchDebug, which defines the variable |b:match_debug| and +creates a Matchit menu. This menu makes it convenient to check the values of +the variables described below. You will probably also want to read +|matchit-details| above. + +Defining the variable |b:match_debug| causes the script to set the following +variables, each time you hit the "%" key. Several of these are only defined +if |b:match_words| includes |backref|s. + + *b:match_pat* +The b:match_pat variable is set to |b:match_words| with |backref|s parsed. + *b:match_match* +The b:match_match variable is set to the bit of text that is recognized as a +match. + *b:match_col* +The b:match_col variable is set to the cursor column of the start of the +matching text. + *b:match_wholeBR* +The b:match_wholeBR variable is set to the comma-separated group of patterns +that matches, with |backref|s unparsed. + *b:match_iniBR* +The b:match_iniBR variable is set to the first pattern in |b:match_wholeBR|. + *b:match_ini* +The b:match_ini variable is set to the first pattern in |b:match_wholeBR|, +with |backref|s resolved from |b:match_match|. + *b:match_tail* +The b:match_tail variable is set to the remaining patterns in +|b:match_wholeBR|, with |backref|s resolved from |b:match_match|. + *b:match_word* +The b:match_word variable is set to the pattern from |b:match_wholeBR| that +matches |b:match_match|. + *b:match_table* +The back reference '\'.d refers to the same thing as '\'.b:match_table[d] in +|b:match_word|. + +============================================================================== +5. Known Bugs and Limitations *matchit-bugs* + +Just because I know about a bug does not mean that it is on my todo list. I +try to respond to reports of bugs that cause real problems. If it does not +cause serious problems, or if there is a work-around, a bug may sit there for +a while. Moral: if a bug (known or not) bothers you, let me know. + +The various |:vmap|s defined in the script (%, |g%|, |[%|, |]%|, |a%|) may +have undesired effects in Select mode |Select-mode-mapping|. At least, if you +want to replace the selection with any character in "ag%[]" there will be a +pause of |'updatetime'| first. + +It would be nice if "\0" were recognized as the entire pattern. That is, it +would be nice if "foo:\end\0" had the same effect as "\(foo\):\end\1". I may +try to implement this in a future version. (This is not so easy to arrange as +you might think!) + +============================================================================== +vim:tw=78:fo=tcq2: diff --git a/etc/soft/nvim/+plugins_disabled/matchit/plugin/matchit.vim b/etc/soft/nvim/+plugins_disabled/matchit/plugin/matchit.vim new file mode 100644 index 0000000..e41cda9 --- /dev/null +++ b/etc/soft/nvim/+plugins_disabled/matchit/plugin/matchit.vim @@ -0,0 +1,812 @@ +" matchit.vim: (global plugin) Extended "%" matching +" Last Change: Fri Jan 25 10:00 AM 2008 EST +" Maintainer: Benji Fisher PhD +" Version: 1.13.2, for Vim 6.3+ +" URL: http://www.vim.org/script.php?script_id=39 + +" Documentation: +" The documentation is in a separate file, matchit.txt . + +" Credits: +" Vim editor by Bram Moolenaar (Thanks, Bram!) +" Original script and design by Raul Segura Acevedo +" Support for comments by Douglas Potts +" Support for back references and other improvements by Benji Fisher +" Support for many languages by Johannes Zellner +" Suggestions for improvement, bug reports, and support for additional +" languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark +" Collett, Stephen Wall, Dany St-Amant, Yuheng Xie, and Johannes Zellner. + +" Debugging: +" If you'd like to try the built-in debugging commands... +" :MatchDebug to activate debugging for the current buffer +" This saves the values of several key script variables as buffer-local +" variables. See the MatchDebug() function, below, for details. + +" TODO: I should think about multi-line patterns for b:match_words. +" This would require an option: how many lines to scan (default 1). +" This would be useful for Python, maybe also for *ML. +" TODO: Maybe I should add a menu so that people will actually use some of +" the features that I have implemented. +" TODO: Eliminate the MultiMatch function. Add yet another argument to +" Match_wrapper() instead. +" TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' +" TODO: Make backrefs safer by using '\V' (very no-magic). +" TODO: Add a level of indirection, so that custom % scripts can use my +" work but extend it. + +" allow user to prevent loading +" and prevent duplicate loading +if exists("loaded_matchit") || &cp + finish +endif +let loaded_matchit = 1 +let s:last_mps = "" +let s:last_words = ":" + +let s:save_cpo = &cpo +set cpo&vim + +nnoremap % :call Match_wrapper('',1,'n') +nnoremap g% :call Match_wrapper('',0,'n') +vnoremap % :call Match_wrapper('',1,'v') m'gv`` +vnoremap g% :call Match_wrapper('',0,'v') m'gv`` +onoremap % v:call Match_wrapper('',1,'o') +onoremap g% v:call Match_wrapper('',0,'o') + +" Analogues of [{ and ]} using matching patterns: +nnoremap [% :call MultiMatch("bW", "n") +nnoremap ]% :call MultiMatch("W", "n") +vmap [% [%m'gv`` +vmap ]% ]%m'gv`` +" vnoremap [% :call MultiMatch("bW", "v") m'gv`` +" vnoremap ]% :call MultiMatch("W", "v") m'gv`` +onoremap [% v:call MultiMatch("bW", "o") +onoremap ]% v:call MultiMatch("W", "o") + +" text object: +vmap a% [%v]% + +" Auto-complete mappings: (not yet "ready for prime time") +" TODO Read :help write-plugin for the "right" way to let the user +" specify a key binding. +" let g:match_auto = '' +" let g:match_autoCR = '' +" if exists("g:match_auto") +" execute "inoremap " . g:match_auto . ' x"=Autocomplete()Pls' +" endif +" if exists("g:match_autoCR") +" execute "inoremap " . g:match_autoCR . ' =Autocomplete()' +" endif +" if exists("g:match_gthhoh") +" execute "inoremap " . g:match_gthhoh . ' :call Gthhoh()' +" endif " gthhoh = "Get the heck out of here!" + +let s:notslash = '\\\@" + endif + " In s:CleanUp(), we may need to check whether the cursor moved forward. + let startline = line(".") + let startcol = col(".") + " Use default behavior if called with a count. + if v:count + exe "normal! " . v:count . "%" + return s:CleanUp(restore_options, a:mode, startline, startcol) + end + + " First step: if not already done, set the script variables + " s:do_BR flag for whether there are backrefs + " s:pat parsed version of b:match_words + " s:all regexp based on s:pat and the default groups + " + if !exists("b:match_words") || b:match_words == "" + let match_words = "" + " Allow b:match_words = "GetVimMatchWords()" . + elseif b:match_words =~ ":" + let match_words = b:match_words + else + execute "let match_words =" b:match_words + endif +" Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion! + if (match_words != s:last_words) || (&mps != s:last_mps) || + \ exists("b:match_debug") + let s:last_words = match_words + let s:last_mps = &mps + " The next several lines were here before + " BF started messing with this script. + " quote the special chars in 'matchpairs', replace [,:] with \| and then + " append the builtin pairs (/*, */, #if, #ifdef, #else, #elif, #endif) + " let default = substitute(escape(&mps, '[$^.*~\\/?]'), '[,:]\+', + " \ '\\|', 'g').'\|\/\*\|\*\/\|#if\>\|#ifdef\>\|#else\>\|#elif\>\|#endif\>' + let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . + \ '\/\*:\*\/,#if\%(def\)\=:#else\>:#elif\>:#endif\>' + " s:all = pattern with all the keywords + let match_words = match_words . (strlen(match_words) ? "," : "") . default + if match_words !~ s:notslash . '\\\d' + let s:do_BR = 0 + let s:pat = match_words + else + let s:do_BR = 1 + let s:pat = s:ParseWords(match_words) + endif + let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g') + let s:all = '\%(' . s:all . '\)' + " let s:all = '\%(' . substitute(s:all, '\\\ze[,:]', '', 'g') . '\)' + if exists("b:match_debug") + let b:match_pat = s:pat + endif + endif + + " Second step: set the following local variables: + " matchline = line on which the cursor started + " curcol = number of characters before match + " prefix = regexp for start of line to start of match + " suffix = regexp for end of match to end of line + " Require match to end on or after the cursor and prefer it to + " start on or before the cursor. + let matchline = getline(startline) + if a:word != '' + " word given + if a:word !~ s:all + echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE + return s:CleanUp(restore_options, a:mode, startline, startcol) + endif + let matchline = a:word + let curcol = 0 + let prefix = '^\%(' + let suffix = '\)$' + " Now the case when "word" is not given + else " Find the match that ends on or after the cursor and set curcol. + let regexp = s:Wholematch(matchline, s:all, startcol-1) + let curcol = match(matchline, regexp) + " If there is no match, give up. + if curcol == -1 + return s:CleanUp(restore_options, a:mode, startline, startcol) + endif + let endcol = matchend(matchline, regexp) + let suf = strlen(matchline) - endcol + let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(') + let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$') + endif + if exists("b:match_debug") + let b:match_match = matchstr(matchline, regexp) + let b:match_col = curcol+1 + endif + + " Third step: Find the group and single word that match, and the original + " (backref) versions of these. Then, resolve the backrefs. + " Set the following local variable: + " group = colon-separated list of patterns, one of which matches + " = ini:mid:fin or ini:fin + " + " Reconstruct the version with unresolved backrefs. + let patBR = substitute(match_words.',', + \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g') + let patBR = substitute(patBR, s:notslash.'\zs:\{2,}', ':', 'g') + " Now, set group and groupBR to the matching group: 'if:endif' or + " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns + " group . "," . groupBR, and we pick it apart. + let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR) + let i = matchend(group, s:notslash . ",") + let groupBR = strpart(group, i) + let group = strpart(group, 0, i-1) + " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix + if s:do_BR " Do the hard part: resolve those backrefs! + let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) + endif + if exists("b:match_debug") + let b:match_wholeBR = groupBR + let i = matchend(groupBR, s:notslash . ":") + let b:match_iniBR = strpart(groupBR, 0, i-1) + endif + + " Fourth step: Set the arguments for searchpair(). + let i = matchend(group, s:notslash . ":") + let j = matchend(group, '.*' . s:notslash . ":") + let ini = strpart(group, 0, i-1) + let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g') + let fin = strpart(group, j) + "Un-escape the remaining , and : characters. + let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') + let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') + let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') + " searchpair() requires that these patterns avoid \(\) groups. + let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g') + let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g') + let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g') + " Set mid. This is optimized for readability, not micro-efficiency! + if a:forward && matchline =~ prefix . fin . suffix + \ || !a:forward && matchline =~ prefix . ini . suffix + let mid = "" + endif + " Set flag. This is optimized for readability, not micro-efficiency! + if a:forward && matchline =~ prefix . fin . suffix + \ || !a:forward && matchline !~ prefix . ini . suffix + let flag = "bW" + else + let flag = "W" + endif + " Set skip. + if exists("b:match_skip") + let skip = b:match_skip + elseif exists("b:match_comment") " backwards compatibility and testing! + let skip = "r:" . b:match_comment + else + let skip = 's:comment\|string' + endif + let skip = s:ParseSkip(skip) + if exists("b:match_debug") + let b:match_ini = ini + let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin + endif + + " Fifth step: actually start moving the cursor and call searchpair(). + " Later, :execute restore_cursor to get to the original screen. + let restore_cursor = virtcol(".") . "|" + normal! g0 + let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor + normal! H + let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor + execute restore_cursor + call cursor(0, curcol + 1) + " normal! 0 + " if curcol + " execute "normal!" . curcol . "l" + " endif + if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on")) + let skip = "0" + else + execute "if " . skip . "| let skip = '0' | endif" + endif + let sp_return = searchpair(ini, mid, fin, flag, skip) + let final_position = "call cursor(" . line(".") . "," . col(".") . ")" + " Restore cursor position and original screen. + execute restore_cursor + normal! m' + if sp_return > 0 + execute final_position + endif + return s:CleanUp(restore_options, a:mode, startline, startcol, mid.'\|'.fin) +endfun + +" Restore options and do some special handling for Operator-pending mode. +" The optional argument is the tail of the matching group. +fun! s:CleanUp(options, mode, startline, startcol, ...) + execute "set" a:options + " Open folds, if appropriate. + if a:mode != "o" + if &foldopen =~ "percent" + normal! zv + endif + " In Operator-pending mode, we want to include the whole match + " (for example, d%). + " This is only a problem if we end up moving in the forward direction. + elseif (a:startline < line(".")) || + \ (a:startline == line(".") && a:startcol < col(".")) + if a:0 + " Check whether the match is a single character. If not, move to the + " end of the match. + let matchline = getline(".") + let currcol = col(".") + let regexp = s:Wholematch(matchline, a:1, currcol-1) + let endcol = matchend(matchline, regexp) + if endcol > currcol " This is NOT off by one! + execute "normal!" . (endcol - currcol) . "l" + endif + endif " a:0 + endif " a:mode != "o" && etc. + return 0 +endfun + +" Example (simplified HTML patterns): if +" a:groupBR = '<\(\k\+\)>:' +" a:prefix = '^.\{3}\(' +" a:group = '<\(\k\+\)>:' +" a:suffix = '\).\{2}$' +" a:matchline = "12312" or "12312" +" then extract "tag" from a:matchline and return ":" . +fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline) + if a:matchline !~ a:prefix . + \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix + return a:group + endif + let i = matchend(a:groupBR, s:notslash . ':') + let ini = strpart(a:groupBR, 0, i-1) + let tailBR = strpart(a:groupBR, i) + let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix, + \ a:groupBR) + let i = matchend(word, s:notslash . ":") + let wordBR = strpart(word, i) + let word = strpart(word, 0, i-1) + " Now, a:matchline =~ a:prefix . word . a:suffix + if wordBR != ini + let table = s:Resolve(ini, wordBR, "table") + else + " let table = "----------" + let table = "" + let d = 0 + while d < 10 + if tailBR =~ s:notslash . '\\' . d + " let table[d] = d + let table = table . d + else + let table = table . "-" + endif + let d = d + 1 + endwhile + endif + let d = 9 + while d + if table[d] != "-" + let backref = substitute(a:matchline, a:prefix.word.a:suffix, + \ '\'.table[d], "") + " Are there any other characters that should be escaped? + let backref = escape(backref, '*,:') + execute s:Ref(ini, d, "start", "len") + let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len) + let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d, + \ escape(backref, '\\'), 'g') + endif + let d = d-1 + endwhile + if exists("b:match_debug") + if s:do_BR + let b:match_table = table + let b:match_word = word + else + let b:match_table = "" + let b:match_word = "" + endif + endif + return ini . ":" . tailBR +endfun + +" Input a comma-separated list of groups with backrefs, such as +" a:groups = '\(foo\):end\1,\(bar\):end\1' +" and return a comma-separated list of groups with backrefs replaced: +" return '\(foo\):end\(foo\),\(bar\):end\(bar\)' +fun! s:ParseWords(groups) + let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g') + let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g') + let parsed = "" + while groups =~ '[^,:]' + let i = matchend(groups, s:notslash . ':') + let j = matchend(groups, s:notslash . ',') + let ini = strpart(groups, 0, i-1) + let tail = strpart(groups, i, j-i-1) . ":" + let groups = strpart(groups, j) + let parsed = parsed . ini + let i = matchend(tail, s:notslash . ':') + while i != -1 + " In 'if:else:endif', ini='if' and word='else' and then word='endif'. + let word = strpart(tail, 0, i-1) + let tail = strpart(tail, i) + let i = matchend(tail, s:notslash . ':') + let parsed = parsed . ":" . s:Resolve(ini, word, "word") + endwhile " Now, tail has been used up. + let parsed = parsed . "," + endwhile " groups =~ '[^,:]' + let parsed = substitute(parsed, ',$', '', '') + return parsed +endfun + +" TODO I think this can be simplified and/or made more efficient. +" TODO What should I do if a:start is out of range? +" Return a regexp that matches all of a:string, such that +" matchstr(a:string, regexp) represents the match for a:pat that starts +" as close to a:start as possible, before being preferred to after, and +" ends after a:start . +" Usage: +" let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1) +" let i = match(getline("."), regexp) +" let j = matchend(getline("."), regexp) +" let match = matchstr(getline("."), regexp) +fun! s:Wholematch(string, pat, start) + let group = '\%(' . a:pat . '\)' + let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^') + let len = strlen(a:string) + let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$') + if a:string !~ prefix . group . suffix + let prefix = '' + endif + return prefix . group . suffix +endfun + +" No extra arguments: s:Ref(string, d) will +" find the d'th occurrence of '\(' and return it, along with everything up +" to and including the matching '\)'. +" One argument: s:Ref(string, d, "start") returns the index of the start +" of the d'th '\(' and any other argument returns the length of the group. +" Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be +" executed, having the effect of +" :let foo = s:Ref(string, d, "start") +" :let bar = s:Ref(string, d, "len") +fun! s:Ref(string, d, ...) + let len = strlen(a:string) + if a:d == 0 + let start = 0 + else + let cnt = a:d + let match = a:string + while cnt + let cnt = cnt - 1 + let index = matchend(match, s:notslash . '\\(') + if index == -1 + return "" + endif + let match = strpart(match, index) + endwhile + let start = len - strlen(match) + if a:0 == 1 && a:1 == "start" + return start - 2 + endif + let cnt = 1 + while cnt + let index = matchend(match, s:notslash . '\\(\|\\)') - 1 + if index == -2 + return "" + endif + " Increment if an open, decrement if a ')': + let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')' + " let cnt = stridx('0(', match[index]) + cnt + let match = strpart(match, index+1) + endwhile + let start = start - 2 + let len = len - start - strlen(match) + endif + if a:0 == 1 + return len + elseif a:0 == 2 + return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len + else + return strpart(a:string, start, len) + endif +endfun + +" Count the number of disjoint copies of pattern in string. +" If the pattern is a literal string and contains no '0' or '1' characters +" then s:Count(string, pattern, '0', '1') should be faster than +" s:Count(string, pattern). +fun! s:Count(string, pattern, ...) + let pat = escape(a:pattern, '\\') + if a:0 > 1 + let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g") + let foo = substitute(a:string, pat, a:2, "g") + let foo = substitute(foo, '[^' . a:2 . ']', "", "g") + return strlen(foo) + endif + let result = 0 + let foo = a:string + let index = matchend(foo, pat) + while index != -1 + let result = result + 1 + let foo = strpart(foo, index) + let index = matchend(foo, pat) + endwhile + return result +endfun + +" s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where +" word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first +" '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this +" indicates that all other instances of '\1' in target are to be replaced +" by '\3'. The hard part is dealing with nesting... +" Note that ":" is an illegal character for source and target, +" unless it is preceded by "\". +fun! s:Resolve(source, target, output) + let word = a:target + let i = matchend(word, s:notslash . '\\\d') - 1 + let table = "----------" + while i != -2 " There are back references to be replaced. + let d = word[i] + let backref = s:Ref(a:source, d) + " The idea is to replace '\d' with backref. Before we do this, + " replace any \(\) groups in backref with :1, :2, ... if they + " correspond to the first, second, ... group already inserted + " into backref. Later, replace :1 with \1 and so on. The group + " number w+b within backref corresponds to the group number + " s within a:source. + " w = number of '\(' in word before the current one + let w = s:Count( + \ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1') + let b = 1 " number of the current '\(' in backref + let s = d " number of the current '\(' in a:source + while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1') + \ && s < 10 + if table[s] == "-" + if w + b < 10 + " let table[s] = w + b + let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1) + endif + let b = b + 1 + let s = s + 1 + else + execute s:Ref(backref, b, "start", "len") + let ref = strpart(backref, start, len) + let backref = strpart(backref, 0, start) . ":". table[s] + \ . strpart(backref, start+len) + let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1') + endif + endwhile + let word = strpart(word, 0, i-1) . backref . strpart(word, i+1) + let i = matchend(word, s:notslash . '\\\d') - 1 + endwhile + let word = substitute(word, s:notslash . '\zs:', '\\', 'g') + if a:output == "table" + return table + elseif a:output == "word" + return word + else + return table . word + endif +endfun + +" Assume a:comma = ",". Then the format for a:patterns and a:1 is +" a:patterns = ",,..." +" a:1 = ",,..." +" If is the first pattern that matches a:string then return +" if no optional arguments are given; return , if a:1 is given. +fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...) + let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma) + let i = matchend(tail, s:notslash . a:comma) + if a:0 + let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma) + let j = matchend(alttail, s:notslash . a:comma) + endif + let current = strpart(tail, 0, i-1) + if a:branch == "" + let currpat = current + else + let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') + endif + while a:string !~ a:prefix . currpat . a:suffix + let tail = strpart(tail, i) + let i = matchend(tail, s:notslash . a:comma) + if i == -1 + return -1 + endif + let current = strpart(tail, 0, i-1) + if a:branch == "" + let currpat = current + else + let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') + endif + if a:0 + let alttail = strpart(alttail, j) + let j = matchend(alttail, s:notslash . a:comma) + endif + endwhile + if a:0 + let current = current . a:comma . strpart(alttail, 0, j-1) + endif + return current +endfun + +" Call this function to turn on debugging information. Every time the main +" script is run, buffer variables will be saved. These can be used directly +" or viewed using the menu items below. +if !exists(":MatchDebug") + command! -nargs=0 MatchDebug call s:Match_debug() +endif + +fun! s:Match_debug() + let b:match_debug = 1 " Save debugging information. + " pat = all of b:match_words with backrefs parsed + amenu &Matchit.&pat :echo b:match_pat + " match = bit of text that is recognized as a match + amenu &Matchit.&match :echo b:match_match + " curcol = cursor column of the start of the matching text + amenu &Matchit.&curcol :echo b:match_col + " wholeBR = matching group, original version + amenu &Matchit.wh&oleBR :echo b:match_wholeBR + " iniBR = 'if' piece, original version + amenu &Matchit.ini&BR :echo b:match_iniBR + " ini = 'if' piece, with all backrefs resolved from match + amenu &Matchit.&ini :echo b:match_ini + " tail = 'else\|endif' piece, with all backrefs resolved from match + amenu &Matchit.&tail :echo b:match_tail + " fin = 'endif' piece, with all backrefs resolved from match + amenu &Matchit.&word :echo b:match_word + " '\'.d in ini refers to the same thing as '\'.table[d] in word. + amenu &Matchit.t&able :echo '0:' . b:match_table . ':9' +endfun + +" Jump to the nearest unmatched "(" or "if" or "" if a:spflag == "bW" +" or the nearest unmatched "" or "endif" or ")" if a:spflag == "W". +" Return a "mark" for the original position, so that +" let m = MultiMatch("bW", "n") ... execute m +" will return to the original position. If there is a problem, do not +" move the cursor and return "", unless a count is given, in which case +" go up or down as many levels as possible and again return "". +" TODO This relies on the same patterns as % matching. It might be a good +" idea to give it its own matching patterns. +fun! s:MultiMatch(spflag, mode) + if !exists("b:match_words") || b:match_words == "" + return "" + end + let restore_options = (&ic ? "" : "no") . "ignorecase" + if exists("b:match_ignorecase") + let &ignorecase = b:match_ignorecase + endif + let startline = line(".") + let startcol = col(".") + + " First step: if not already done, set the script variables + " s:do_BR flag for whether there are backrefs + " s:pat parsed version of b:match_words + " s:all regexp based on s:pat and the default groups + " This part is copied and slightly modified from s:Match_wrapper(). + let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . + \ '\/\*:\*\/,#if\%(def\)\=:#else\>:#elif\>:#endif\>' + " Allow b:match_words = "GetVimMatchWords()" . + if b:match_words =~ ":" + let match_words = b:match_words + else + execute "let match_words =" b:match_words + endif + if (match_words != s:last_words) || (&mps != s:last_mps) || + \ exists("b:match_debug") + let s:last_words = match_words + let s:last_mps = &mps + if match_words !~ s:notslash . '\\\d' + let s:do_BR = 0 + let s:pat = match_words + else + let s:do_BR = 1 + let s:pat = s:ParseWords(match_words) + endif + let s:all = '\%(' . substitute(s:pat . (strlen(s:pat)?",":"") . default, + \ '[,:]\+','\\|','g') . '\)' + if exists("b:match_debug") + let b:match_pat = s:pat + endif + endif + + " Second step: figure out the patterns for searchpair() + " and save the screen, cursor position, and 'ignorecase'. + " - TODO: A lot of this is copied from s:Match_wrapper(). + " - maybe even more functionality should be split off + " - into separate functions! + let cdefault = (s:pat =~ '[^,]$' ? "," : "") . default + let open = substitute(s:pat . cdefault, + \ s:notslash . '\zs:.\{-}' . s:notslash . ',', '\\),\\(', 'g') + let open = '\(' . substitute(open, s:notslash . '\zs:.*$', '\\)', '') + let close = substitute(s:pat . cdefault, + \ s:notslash . '\zs,.\{-}' . s:notslash . ':', '\\),\\(', 'g') + let close = substitute(close, '^.\{-}' . s:notslash . ':', '\\(', '') . '\)' + if exists("b:match_skip") + let skip = b:match_skip + elseif exists("b:match_comment") " backwards compatibility and testing! + let skip = "r:" . b:match_comment + else + let skip = 's:comment\|string' + endif + let skip = s:ParseSkip(skip) + " let restore_cursor = line(".") . "G" . virtcol(".") . "|" + " normal! H + " let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor + let restore_cursor = virtcol(".") . "|" + normal! g0 + let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor + normal! H + let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor + execute restore_cursor + + " Third step: call searchpair(). + " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'. + let openpat = substitute(open, '\(\\\@" or ... +" and return "endif" or "endwhile" or "" or ... . +" For now, this uses b:match_words and the same script variables +" as s:Match_wrapper() . Later, it may get its own patterns, +" either from a buffer variable or passed as arguments. +" fun! s:Autocomplete() +" echo "autocomplete not yet implemented :-(" +" if !exists("b:match_words") || b:match_words == "" +" return "" +" end +" let startpos = s:MultiMatch("bW") +" +" if startpos == "" +" return "" +" endif +" " - TODO: figure out whether 'if' or '' matched, and construct +" " - the appropriate closing. +" let matchline = getline(".") +" let curcol = col(".") - 1 +" " - TODO: Change the s:all argument if there is a new set of match pats. +" let regexp = s:Wholematch(matchline, s:all, curcol) +" let suf = strlen(matchline) - matchend(matchline, regexp) +" let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(') +" let suffix = (suf ? '\).\{' . suf . '}$' : '\)$') +" " Reconstruct the version with unresolved backrefs. +" let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g') +" let patBR = substitute(patBR, ':\{2,}', ':', "g") +" " Now, set group and groupBR to the matching group: 'if:endif' or +" " 'while:endwhile' or whatever. +" let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR) +" let i = matchend(group, s:notslash . ",") +" let groupBR = strpart(group, i) +" let group = strpart(group, 0, i-1) +" " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix +" if s:do_BR +" let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) +" endif +" " let g:group = group +" +" " - TODO: Construct the closing from group. +" let fake = "end" . expand("") +" execute startpos +" return fake +" endfun + +" Close all open structures. "Get the heck out of here!" +" fun! s:Gthhoh() +" let close = s:Autocomplete() +" while strlen(close) +" put=close +" let close = s:Autocomplete() +" endwhile +" endfun + +" Parse special strings as typical skip arguments for searchpair(): +" 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 +fun! s:ParseSkip(str) + let skip = a:str + if skip[1] == ":" + if skip[0] == "s" + let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" . + \ strpart(skip,2) . "'" + elseif skip[0] == "S" + let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" . + \ strpart(skip,2) . "'" + elseif skip[0] == "r" + let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'" + elseif skip[0] == "R" + let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'" + endif + endif + return skip +endfun + +let &cpo = s:save_cpo + +" vim:sts=2:sw=2: diff --git a/etc/soft/nvim/vimrc b/etc/soft/nvim/vimrc index cfc2939..d0db55e 100644 --- a/etc/soft/nvim/vimrc +++ b/etc/soft/nvim/vimrc @@ -914,5 +914,13 @@ let g:floaterm_borderchars = ['─', '│', '─', '│', '┌', '┐', '┘', ' " }}} +" vim-matchup {{{ + +let g:matchup_matchparen_stopline = 400 + +hi MatchParen ctermbg=193 ctermfg=53 + +" }}} + " }}}###########################################################################