├── .gitignore ├── LICENSE ├── autoload └── parenmatch.vim ├── doc └── parenmatch.txt └── plugin └── parenmatch.vim /.gitignore: -------------------------------------------------------------------------------- 1 | /doc/tags 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016,2017,2019,2020 itchyny 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /autoload/parenmatch.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " Filename: autoload/parenmatch.vim 3 | " Author: itchyny 4 | " License: MIT License 5 | " Last Change: 2020/03/10 11:53:23. 6 | " ============================================================================= 7 | 8 | let s:save_cpo = &cpo 9 | set cpo&vim 10 | 11 | function! parenmatch#highlight() abort 12 | if !get(g:, 'parenmatch_highlight', 1) | return | endif 13 | highlight ParenMatch term=underline cterm=underline gui=underline 14 | endfunction 15 | 16 | let s:paren = {} 17 | function! parenmatch#update(...) abort 18 | if !get(b:, 'parenmatch', get(g:, 'parenmatch', 1)) | return | endif 19 | let i = a:0 ? a:1 : mode() ==# 'i' || mode() ==# 'R' 20 | let c = matchstr(getline('.'), '.', col('.') - i - 1) 21 | if get(w:, 'parenmatch') 22 | silent! call matchdelete(w:parenmatch) 23 | endif 24 | if !has_key(s:paren, c) | return | endif 25 | let [open, closed, flags, stop] = s:paren[c] 26 | let q = [line('.'), col('.') - i] 27 | if i | let p = getcurpos() | call cursor(q) | endif 28 | let r = searchpairpos(open, '', closed, flags, '', line(stop), 10) 29 | if i | call setpos('.', p) | endif 30 | if r[0] > 0 | let w:parenmatch = matchaddpos('ParenMatch', [q, r]) | endif 31 | endfunction 32 | 33 | let s:matchpairs = '' 34 | function! parenmatch#setup() abort 35 | if s:matchpairs ==# &l:matchpairs 36 | return 37 | endif 38 | let s:matchpairs = &l:matchpairs 39 | let s:paren = {} 40 | for [open, closed] in map(split(&l:matchpairs, ','), 'split(v:val, ":")') 41 | let s:paren[open] = [ escape(open, '[]'), escape(closed, '[]'), 'nW', 'w$' ] 42 | let s:paren[closed] = [ escape(open, '[]'), escape(closed, '[]'), 'bnW', 'w0' ] 43 | endfor 44 | endfunction 45 | 46 | if has('timers') 47 | let s:timer = 0 48 | function! parenmatch#cursormoved() abort 49 | if get(w:, 'parenmatch') 50 | silent! call matchdelete(w:parenmatch) 51 | let w:parenmatch = 0 52 | endif 53 | call timer_stop(s:timer) 54 | let s:timer = timer_start(50, 'parenmatch#timer_callback') 55 | endfunction 56 | function! parenmatch#timer_callback(...) abort 57 | call parenmatch#update() 58 | endfunction 59 | else 60 | function! parenmatch#cursormoved() abort 61 | call parenmatch#update() 62 | endfunction 63 | endif 64 | 65 | let &cpo = s:save_cpo 66 | unlet s:save_cpo 67 | -------------------------------------------------------------------------------- /doc/parenmatch.txt: -------------------------------------------------------------------------------- 1 | *parenmatch.txt* Highlights matching delimiters 2 | 3 | Version: 0.2 4 | Author: itchyny (https://github.com/itchyny) 5 | License: MIT License 6 | Repository: https://github.com/itchyny/vim-parenmatch 7 | Last Change: 2016/09/16 00:00:00. 8 | 9 | CONTENTS *parenmatch-contents* 10 | 11 | Introduction |parenmatch-introduction| 12 | Options |parenmatch-options| 13 | Changelog |parenmatch-changelog| 14 | 15 | ============================================================================== 16 | INTRODUCTION *parenmatch-introduction* 17 | 18 | This *parenmatch* plugin highlights the matching parenthesis based on the 19 | value of |matchpairs|. This plugin is an alternative of the standard |matchparen| 20 | plugin. This plugin is about 8 times faster than the |matchparen| plugin. 21 | 22 | This plugin is enabled by default. But if you keep |matchparen| running, it is 23 | not efficient. In order to disable the standard |matchparen| plugin, add the 24 | following configuration to your vimrc file. > 25 | 26 | let g:loaded_matchparen = 1 27 | < 28 | Why is this |parenmatch| plugin such faster than the standard plugin? I took 29 | profiles again and again, and I found some inefficient codes in the standard 30 | |matchparen| plugin. 31 | 32 | 1. Skipping the parenthesis matching based on the syntax names. It 33 | uses the {skip} argument of |searchpairpos| and deals the 34 | parenthesis matching very correctly. This is actually an intended 35 | usage of this function as the example in the |match-parens| section 36 | shows. However, obtaining the sytnax under the cursor is basically 37 | an inefficient operation. This part of codes (the line of evaluating 38 | s_skip and searchpairpos) is the heaviest part of |matchparen|. 39 | 40 | 2. Obtaining the character under the cursor using a regular expression 41 | |/\%c|. 42 | 43 | 3. Splitting the value of |matchpairs| by a regular expression every 44 | time the cursor moves. The value of this option does not change so 45 | much. At least, it does not change while moving the cursor around. 46 | 47 | So, how does |parenmatch| overcome these problems? 48 | 49 | 1. It does not support strict matching of the parenthesis. Stop 50 | checking the syntax, the |parenmatch| cannot deal with the following 51 | code correctly. > 52 | [ [ "[ ] [" ], [ "] [ ]" ] ] 53 | < However, the plugin actually works in most pieces of code. If you 54 | still want it work with the code like above, you can use the 55 | standard plugin. 56 | 57 | 2. It uses the string indexing to obtain the character under the 58 | cursor. It does the same thing and is much faster. 59 | 60 | 3. It splits the value of |matchpairs| in advance. The cache is updated 61 | when the option is set (using |OptionSet|) or the active window is 62 | changed. 63 | 64 | The code of |parenmatch| is actually very small. The updating function is only 65 | about 10 lines. When the character under the cursor is not a parenthesis 66 | character, the function finishes after executing only 4 lines. I think the 67 | implimentation is optimal but if you find further performance improvement, 68 | please submit a pull request (https://github.com/itchyny/vim-parenmatch/pulls). 69 | 70 | ============================================================================== 71 | OPTIONS *parenmatch-options* 72 | 73 | g:parenmatch *g:parenmatch* 74 | Set this variable to 0 to disable this plugin globally. 75 | 76 | b:parenmatch *b:parenmatch* 77 | If you set this variable to 0, the plugin stops highlighting 78 | the parenthesis under the cursor in the buffer. This variable 79 | has priority over |g:parenmatch|. 80 | 81 | ============================================================================== 82 | CHANGELOG *parenmatch-changelog* 83 | 84 | 0.2 2016-09-16 85 | - Add options to disable the plugin. 86 | 87 | 0.1 2016-03-28 - 03-31 88 | - Improve performance. 89 | - Documentation. 90 | 91 | 0.0 2016-03-27 92 | - Initial commit. 93 | 94 | ============================================================================== 95 | vim:tw=78:sw=4:ts=8:ft=help:norl:noet: 96 | -------------------------------------------------------------------------------- /plugin/parenmatch.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " Filename: plugin/parenmatch.vim 3 | " Author: itchyny 4 | " License: MIT License 5 | " Last Change: 2020/05/01 19:18:42. 6 | " ============================================================================= 7 | 8 | if exists('g:loaded_parenmatch') || v:version < 703 || !exists('*matchaddpos') 9 | finish 10 | endif 11 | let g:loaded_parenmatch = 1 12 | 13 | let s:save_cpo = &cpo 14 | set cpo&vim 15 | 16 | augroup parenmatch 17 | autocmd! 18 | if has('vim_starting') 19 | autocmd VimEnter * call parenmatch#highlight() | 20 | \ call parenmatch#setup() | 21 | \ autocmd parenmatch WinEnter,BufEnter,BufWritePost * call parenmatch#update() 22 | else 23 | call parenmatch#highlight() 24 | call parenmatch#setup() 25 | autocmd WinEnter,BufEnter,BufWritePost * call parenmatch#update() 26 | endif 27 | autocmd ColorScheme * call parenmatch#highlight() 28 | autocmd CursorMoved,CursorMovedI * call parenmatch#cursormoved() 29 | autocmd InsertEnter * call parenmatch#update(1) 30 | autocmd InsertLeave * call parenmatch#update(0) 31 | autocmd WinEnter,BufWinEnter,FileType * call parenmatch#setup() 32 | autocmd OptionSet matchpairs call parenmatch#setup() 33 | augroup END 34 | 35 | let &cpo = s:save_cpo 36 | unlet s:save_cpo 37 | --------------------------------------------------------------------------------