├── README.md ├── _config.yml ├── autoload └── matchtag.vim └── plugin └── matchtag.vim /README.md: -------------------------------------------------------------------------------- 1 | icon 2 | 3 | # vim-matchtag 4 | 5 |

6 | screenshot 7 | screenshot 8 | screenshot 9 |

10 | 11 | Highlight matching tags in any files such as html, xml, js, jsx, vue, svelte. 12 | 13 | ## Installation 14 | 15 |
16 | How to install 17 | 18 | - [VundleVim][1] 19 | 20 | Plugin 'leafOfTree/vim-matchtag' 21 | 22 | - [vim-pathogen][2] 23 | 24 | cd ~/.vim/bundle && \ 25 | git clone https://github.com/leafOfTree/vim-matchtag --depth 1 26 | 27 | - [vim-plug][3] 28 | 29 | Plug 'leafOfTree/vim-matchtag' 30 | 31 | - Or manually, clone this plugin to `path/to/this_plugin`, and add it to `rtp` in vimrc 32 | 33 | set rtp+=path/to/this_plugin 34 | 35 |
36 |
37 | 38 | ## How it works 39 | 40 | This plugin finds the matching tag and highlight it. Mainly inspired by vim builtin `matchparen` using `searchpairpos` and `matchaddpos`. Feel free to open an issue or a pull request. 41 | 42 | ## Configuration 43 | 44 | Set global variable to `1` to enable or `0` to disalbe. Or a proper value to make it effective. Ex: 45 | 46 | ```vim 47 | let g:vim_matchtag_enable_by_default = 1 48 | let g:vim_matchtag_files = '*.html,*.xml,*.js,*.jsx,*.ts,*.tsx,*.vue,*.svelte,*.jsp,*.php,*.erb,*.astro' 49 | ``` 50 | 51 | | variable | description | default | 52 | |--------------------------------------|-----------------------------------------------------|---------| 53 | | g:vim_matchtag_files | Enable on these files. | *See ^* | 54 | | g:vim_matchtag_enable_by_default | Enable by default. | 1 | 55 | | g:vim_matchtag_highlight_cursor_on | Highlight the tag when the cursor is on it. | 0 | 56 | | **Mappings / Performance / debug related** ||| 57 | | g:vim_matchtag_mapping_toggle | Key mapping to toggle highlighting. | `''` | 58 | | g:vim_matchtag_mapping_toggle_highlight_cursor_on | Key mapping to toggle `highlight_cursor_on`. | `''` | 59 | | g:vim_matchtag_skip | Syntax to skip. | *See +* | 60 | | g:vim_matchtag_skip_except | Syntax not to skip. | *See +* | 61 | | g:vim_matchtag_timeout | The search stops after timeout milliseconds. | 50 | 62 | | g:vim_matchtag_disable_cache | Disable the cache for lines.
(By default the lines are cached until text changed) | 0 | 63 | | g:vim_matchtag_debug | Echo debug messages. | 0 | 64 | 65 | **Note** 66 | 67 | - If you prefer to enable it on demand, you can set `g:vim_matchtag_enable_by_default` to `0` then toggle it by `:MatchTagToggle`. 68 | 69 | - ^: It is a comma separated file pattern (`:h autocmd-patterns`). It defaults to 70 | 71 | ```vim 72 | let g:vim_matchtag_files = '*.html,*.xml,*.js,*.jsx,*.ts,*.tsx,*.vue,*.svelte,*.jsp,*.php,*.erb,*.astro' 73 | ``` 74 | - +: Both are patterns (`:h pattern`). The default values are 75 | 76 | ```vim 77 | let g:vim_matchtag_skip = 'javascript\|css\|script\|style' 78 | let g:vim_matchtag_skip_except = 'html\|template' 79 | ``` 80 | - See [performance](#performance) if there are lags. 81 | 82 | ### Highlighting 83 | 84 | When the matching tag is found, the highlight group is `matchTag` (by default `Visual`). Otherwise, it's `matchTagError` (by default `Error`). 85 | 86 | You could change them as follows. 87 | 88 | ```vim 89 | highlight link matchTag Search 90 | highlight link matchTag MatchParen 91 | highlight matchTag gui=reverse 92 | 93 | highlight link matchTagError Todo 94 | ``` 95 | 96 | If these don't take effect, try putting them at the end of your vimrc. 97 | 98 | ### Commands 99 | 100 | There are commands you can call directly or add key mapping to. 101 | 102 | - `:MatchTagToggle` Toggle highlighting. 103 | 104 | - `:MatchTagToggleHighlightCursorOn` Toggle highlighting of the tag when the cursor is on it. 105 | 106 | ## Performance 107 | 108 | The highlighting should take about `0.001`~`0.01` depending on the file content. If there is a freeze, you can try 109 | 110 | ```vim 111 | let g:vim_matchtag_skip = '' " Syntax to skip 112 | let g:vim_matchtag_skip_except = '' " Syntax not to skip 113 | 114 | call matchtag#ReportTime() 115 | ``` 116 | and feel free to open an issue. 117 | 118 | You can show the syntax stack under the cursor by running 119 | ```vim 120 | echo map(synstack(line('.'), col('.')), { _, id -> synIDattr(id, 'name') }) 121 | ``` 122 | 123 | ## Others 124 | 125 | - Jump between matching tags? See `:h matchit`. 126 | 127 | ## Credits 128 | 129 | - matchparen.vim 130 | 131 | [1]: https://github.com/VundleVim/Vundle.vim 132 | [2]: https://github.com/tpope/vim-pathogen 133 | [3]: https://github.com/junegunn/vim-plug 134 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /autoload/matchtag.vim: -------------------------------------------------------------------------------- 1 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 2 | " 3 | " Settings {{{ 4 | " 5 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 6 | let s:name = 'vim-matchtag' 7 | let s:match_id = 999 8 | let s:tagname_regexp = '[0-9A-Za-z_.-]' 9 | let s:empty_tagname = '\v<(area|base|br|col|embed|hr|input|img|keygen|link|meta|param|source|track|wbr)>' 10 | let s:component_name = '\v\C^[A-Z]\w+' 11 | let s:exists_text_changed = exists('##TextChanged') 12 | 13 | "}}} 14 | 15 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 16 | " 17 | " Configs {{{ 18 | " 19 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 20 | function! s:GetConfig(name, default) 21 | let name = 'g:vim_matchtag_'.a:name 22 | return exists(name) ? eval(name) : a:default 23 | endfunction 24 | 25 | let s:highlight_cursor_on = s:GetConfig('highlight_cursor_on', s:GetConfig('both', 0)) 26 | let s:debug = s:GetConfig('debug', 0) 27 | let s:timeout = s:GetConfig('timeout', 50) 28 | let s:disable_cache = s:GetConfig('disable_cache', 29 | \ !s:exists_text_changed) 30 | let s:skip = s:GetConfig('skip', 31 | \ 'javascript\|css\|script\|style') 32 | let s:skip_except = s:GetConfig('skip_except', 33 | \ 'html\|template') 34 | "}}} 35 | 36 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 37 | " 38 | " Functions {{{ 39 | " 40 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 41 | " The function that is invoked (very often) to definie a ":match" 42 | " highlighting for any matching tag. 43 | function! matchtag#HighlightMatchingTag() 44 | " Remove any previous match. 45 | if exists('w:matchtag_hl_on') && w:matchtag_hl_on 46 | call s:DeleteMatch() 47 | let w:matchtag_hl_on = 0 48 | endif 49 | 50 | " Avoid removing the popup menu. 51 | " Or return when there are no colors 52 | if pumvisible() || (&t_Co < 8 && !has('gui_running')) 53 | return 54 | endif 55 | 56 | " Skip if current position contains specific syntax 57 | if s:IsInSkipSyntax() 58 | call s:Log('Skip syntax') 59 | return 60 | endif 61 | 62 | call s:HighlightTag() 63 | endfunction 64 | 65 | let s:cached_lines = {} 66 | function! s:ResetLineCache() 67 | let s:cached_lines = {} 68 | endfunction 69 | 70 | if !s:disable_cache 71 | " Cache lines 72 | function! s:GetLine(number) 73 | let number = a:number 74 | if has_key(s:cached_lines, number) 75 | return s:cached_lines[number] 76 | else 77 | let line = getline(number) 78 | let s:cached_lines[number] = line 79 | return line 80 | endif 81 | endfunction 82 | else 83 | function! s:GetLine(number) 84 | return getline(a:number) 85 | endfunction 86 | endif 87 | 88 | function! s:HighlightTag() 89 | let save_cursor = getcurpos() 90 | 91 | let [cursor_row, cursor_col] = save_cursor[1:2] 92 | if cursor_col < min([cursor_row * &shiftwidth, 20]) 93 | let bracket_col = searchpos('^\s\+\zs<', 'n', cursor_row, s:timeout)[1] 94 | if cursor_col < bracket_col 95 | call cursor(0, bracket_col) 96 | endif 97 | endif 98 | 99 | let [row, col] = s:GetTagPos() 100 | if row 101 | " Find current tag 102 | let line = s:GetLine(row) 103 | let tagname = s:GetTagName(line, col) 104 | let pos = [[row, col+1, len(tagname)]] 105 | call s:Log('On tag '.tagname) 106 | 107 | " Set cursor to tag start to search backward correctly 108 | call cursor(row, col) 109 | 110 | let [match_row, match_col, offset] = s:SearchMatchTag(tagname) 111 | if match_row " Find matching tag 112 | let match_line = match_row == row 113 | \ ? line 114 | \ : s:GetLine(match_row) 115 | let match_tagname = s:GetTagName(match_line, match_col) 116 | 117 | " Highlight tags 118 | " Current tag 119 | let cursor_on_tag = cursor_row == row 120 | \ && cursor_col >= col 121 | \ && cursor_col <= (col+len(tagname)+1) 122 | if !cursor_on_tag || s:highlight_cursor_on 123 | call matchaddpos('MatchTag', pos, 10, s:match_id) 124 | endif 125 | " Matching tag 126 | let match_pos = [[ 127 | \match_row, 128 | \match_col+offset, 129 | \len(match_tagname)+1-offset 130 | \]] 131 | call matchaddpos('MatchTag', match_pos, 10, s:match_id+1) 132 | call s:Log('Matching tag '.match_tagname) 133 | else " No matching tag found 134 | if s:IsEmptyTag(tagname) 135 | " Current tag is emtpy 136 | call matchaddpos('MatchTag', pos, 10, s:match_id) 137 | call s:Log('Current tag is empty: '.tagname) 138 | else 139 | " Matching tag not found 140 | call matchaddpos('MatchTagError', pos, 10, s:match_id) 141 | call s:Log('Matching tag Not found') 142 | endif 143 | endif 144 | let w:matchtag_hl_on = 1 145 | endif 146 | 147 | call setpos('.', save_cursor) 148 | endfunction 149 | 150 | function! s:IsEmptyTag(tagname) 151 | return match(a:tagname, s:empty_tagname) != -1 152 | \|| match(a:tagname, s:component_name) != -1 153 | endfunction 154 | 155 | " Compare two positions 156 | " 0: pos1 is after pos2 157 | " 1: pos1 is ahead of pos2 158 | function! s:IsAheadOf(pos1, pos2) 159 | let [row1, col1] = a:pos1 160 | let [row2, col2] = a:pos2 161 | if row2 > row1 || (row2 == row1 && col2 > col1) 162 | return 1 163 | else 164 | return 0 165 | endif 166 | endfunction 167 | 168 | function! s:IsEmptyPos(pos) 169 | let [row, col] = a:pos 170 | return row == 0 && col == 0 171 | endfunction 172 | 173 | function! s:IsSamePos(pos1, pos2) 174 | let [row1, col1] = a:pos1 175 | let [row2, col2] = a:pos2 176 | return row1 == row2 && col1 == col2 177 | endfunction 178 | 179 | function! s:NotAfter(main, excludes) 180 | let regexp = '\('.join(split(a:excludes, ','), '\|').'\)' 181 | return a:main.regexp.'\@!' 182 | endfunction 183 | 184 | function! s:NotBefore(main, excludes) 185 | let regexp = '\('.join(split(a:excludes, ','), '\|').'\)' 186 | return regexp.'\@' in empty tag 192 | " - '' in php tags 193 | " - '' in html comments 194 | " - '=>' in JavaScript 195 | let s:open_bracket_regexp = s:NotAfter('<', '?,!') 196 | let s:close_bracket_regexp = s:NotBefore('>', '?,=') 197 | let s:open_bracket_forward_regexp = s:NotAfter('', '?,-,=') 199 | 200 | function! s:GetTagPos() 201 | call s:Log('GetTagPos') 202 | 203 | if s:IsInComment() 204 | call s:Log('In coment, skip') 205 | return [0, 0] 206 | endif 207 | 208 | let timeout = s:timeout 209 | let firstline = line('w0') 210 | let lastline = line('w$') 211 | 212 | " Search for '<' backward 213 | let open_bracket = searchpos(s:open_bracket_regexp, 'cbnW', firstline, timeout) 214 | " Search for '>' backward 215 | let close_bracket = searchpos(s:close_bracket_regexp, 'bnW', firstline, timeout) 216 | 217 | let near_open = s:IsAheadOf(close_bracket, open_bracket) 218 | let near_close = !near_open 219 | 220 | " Search for '<' forward 221 | let open_bracket_forward = searchpos(s:open_bracket_forward_regexp, 'nW', lastline, timeout) 222 | " Search for '>' forward 223 | let close_bracket_forward = searchpos(s:close_bracket_forward_regexp, 'cnW', lastline, timeout) 224 | 225 | let near_close_forward = s:IsAheadOf(close_bracket_forward, open_bracket_forward) 226 | \ || s:IsEmptyPos(open_bracket_forward) 227 | let near_open_forward = !near_close_forward 228 | 229 | " On tag 230 | if near_open && near_close_forward 231 | call s:Log('On tag') 232 | return open_bracket 233 | endif 234 | 235 | " Check if in tag 236 | " Check forward 237 | if near_open_forward 238 | call s:Log('Find close tag forward ') 239 | return open_bracket_forward 240 | endif 241 | " Check backward 242 | if near_close 243 | let open_of_closetag 244 | \ = searchpos('', 'bcnW', firstline, timeout) 247 | 248 | if !s:IsSamePos(open_bracket, open_of_closetag) 249 | \ && !s:IsSamePos(close_bracket, close_of_closetag) 250 | 251 | let line = s:GetLine(open_bracket[0]) 252 | let tagname = s:GetTagName(line, open_bracket[1]) 253 | if s:IsEmptyTag(tagname) 254 | call s:Log('After an empty tag') 255 | return [0, 0] 256 | endif 257 | 258 | call s:Log('Find open tag backward') 259 | return open_bracket 260 | endif 261 | endif 262 | 263 | " Not on/in tag 264 | if s:IsEmptyPos(open_bracket) 265 | call s:Log('Not on/in tag, no open bracket') 266 | return [0, 0] 267 | endif 268 | if s:IsEmptyPos(close_bracket_forward) 269 | call s:Log('Not on/in tag, no close bracket') 270 | return [0, 0] 271 | endif 272 | 273 | call s:Log('Not on/in tag, <: '.near_open.', >: '.near_close_forward) 274 | return [0, 0] 275 | endfunction 276 | 277 | function! s:GetTagName(line, col) 278 | let line = a:line 279 | let col = a:col 280 | 281 | let end = col + 1 282 | while line[end] =~ s:tagname_regexp 283 | let end += 1 284 | endwhile 285 | let tagname = line[col: end-1] 286 | return tagname 287 | endfunction 288 | 289 | function! s:SearchMatchTag(tagname) 290 | let tagname = a:tagname 291 | let flags = 'nW' 292 | if tagname[0] == '/' 293 | let start = '<'.tagname[1:] 294 | let end = tagname 295 | let flags = flags.'b' 296 | 297 | " Don't include '<' if search backward 298 | let offset = 1 299 | else 300 | let start = '<'.tagname 301 | let end = '/'.tagname 302 | let offset = 0 303 | endif 304 | let [row, col] = searchpairpos(start, '', end, flags, function('s:IsInCommentOrString'), 0, s:timeout) 305 | 306 | return [row, col, offset] 307 | endfunction 308 | 309 | function! s:IsInCommentOrString() 310 | let names = s:SynNames() 311 | return s:containSyntax(names, '\ccomment\|string$') 312 | endfunction 313 | 314 | function! s:IsInComment() 315 | let names = s:SynNames() 316 | return s:containSyntax(names, '\ccomment$') 317 | endfunction 318 | 319 | function! s:IsInSkipSyntax() 320 | let names = s:SynNames() 321 | if empty(names) 322 | " Don't skip empty syntax to support treesitter 323 | return 0 324 | else 325 | return s:containSyntax(names, s:skip) 326 | \&& !s:containSyntax(names, s:skip_except) 327 | endif 328 | endfunction 329 | 330 | function! s:SynNames() 331 | let lnum = line('.') 332 | let cnum = col('.') 333 | let ids = synstack(lnum, cnum) 334 | let names = map(ids, { _, id -> synIDattr(id, 'name') }) 335 | 336 | if empty(names) 337 | let names = s:NearSynNames(lnum) 338 | endif 339 | return names 340 | endfunction 341 | 342 | function! s:NearSynNames(lnum) 343 | let lnum = a:lnum 344 | let cnum = col('$') 345 | let names = [] 346 | if empty(names) 347 | " Try next line if empty 348 | let nextlnum = nextnonblank(lnum) 349 | let nextcnum = cnum 350 | let ids = synstack(nextlnum, nextcnum) 351 | let names = map(ids, { _, id -> synIDattr(id, 'name') }) 352 | endif 353 | if empty(names) 354 | " Try prev line if empty 355 | let prevlnum = prevnonblank(lnum) 356 | let prevcnum = cnum 357 | let ids = synstack(prevlnum, prevcnum) 358 | let names = map(ids, { _, id -> synIDattr(id, 'name') }) 359 | endif 360 | 361 | " Not sure why names become 0 when opening empty file 362 | if empty(names) 363 | return [] 364 | else 365 | return names 366 | endif 367 | endfunction 368 | 369 | function! s:containSyntax(names, pat) 370 | if empty(a:pat) 371 | return 0 372 | endif 373 | 374 | for syn in a:names 375 | if syn =~ a:pat 376 | return 1 377 | endif 378 | endfor 379 | endfunction 380 | 381 | function! s:DeleteMatch() 382 | silent! call matchdelete(s:match_id) 383 | silent! call matchdelete(s:match_id+1) 384 | endfunction 385 | 386 | function! matchtag#DisableMatchTag() 387 | let g:loaded_matchtag = 0 388 | autocmd! matchtag 389 | call s:DeleteMatch() 390 | endfunction 391 | 392 | function! matchtag#EnableMatchTag() 393 | let g:loaded_matchtag = 1 394 | 395 | let files = s:GetConfig('files', g:vim_matchtag_files_default) 396 | augroup matchtag 397 | autocmd! matchtag 398 | execute 'autocmd! CursorMoved,CursorMovedI,WinEnter '.files 399 | \.' call matchtag#HighlightMatchingTag()' 400 | 401 | " Clear match for all buffers 402 | autocmd BufWinEnter * call s:DeleteMatch() 403 | 404 | if s:exists_text_changed 405 | execute 'autocmd! TextChanged,TextChangedI '.files 406 | \.' call s:ResetLineCache()' 407 | \.'|call matchtag#HighlightMatchingTag()' 408 | 409 | execute 'autocmd! BufLeave '.files 410 | \.' call s:ResetLineCache()' 411 | endif 412 | augroup END 413 | 414 | silent! doautocmd CursorMoved 415 | endfunction 416 | 417 | function! matchtag#Toggle() 418 | if exists('g:loaded_matchtag') && g:loaded_matchtag 419 | call s:Log('Disable') 420 | call matchtag#DisableMatchTag() 421 | else 422 | call s:Log('Enable') 423 | call matchtag#EnableMatchTag() 424 | endif 425 | endfunction 426 | 427 | function! matchtag#ToggleHighlightCursorOn() 428 | let s:highlight_cursor_on = 1 - s:highlight_cursor_on 429 | silent! doautocmd CursorMoved 430 | endfunction 431 | 432 | function! s:Log(msg) 433 | if s:debug 434 | echom '['.s:name.'] '.a:msg 435 | endif 436 | endfunction 437 | 438 | function! matchtag#Log(msg) 439 | call s:Log(msg) 440 | endfunction 441 | 442 | function! matchtag#ReportTime() 443 | let save_cursor = getcurpos() 444 | call s:ResetLineCache() 445 | 446 | let total = 0 447 | let max = 0 448 | let max_line = 0 449 | for i in range(1, line('$')) 450 | call cursor(i, 1) 451 | let start = reltime() 452 | call matchtag#HighlightMatchingTag() 453 | let end = reltime() 454 | let duration = reltime(start, end) 455 | echom 'line '.i.', time: '.reltimestr(duration) 456 | let value = reltimefloat(duration) 457 | let total += value 458 | if max < value 459 | let max = value 460 | let max_line = i 461 | endif 462 | endfor 463 | let ave = total / line('$') 464 | 465 | call setpos('.', save_cursor) 466 | echom 'report Ave: '.string(ave) 467 | \.' Max: '.string(max).' on line '.max_line 468 | endfunction 469 | 470 | 471 | "}}} 472 | " vim: fdm=marker 473 | -------------------------------------------------------------------------------- /plugin/matchtag.vim: -------------------------------------------------------------------------------- 1 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 2 | " Vim plugin for highlighting matching tags 3 | " Maintainer: leafOfTree 4 | " CREDITS: Inspired by matchParen. 5 | " 6 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 7 | 8 | " Exit quickly when: 9 | " - this plugin was already loaded (or disabled) 10 | " - when "compatiable" is set 11 | " - the "CursorMoved" autocmd event is not available. 12 | if exists('g:loaded_matchtag') 13 | \ || exists('*s:HighlightMatchingTag') 14 | \ || !exists('##CursorMoved') 15 | \ || &cp 16 | finish 17 | endif 18 | 19 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 20 | " 21 | " Config {{{ 22 | " 23 | """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 24 | function! s:GetConfig(name, default) 25 | let name = 'g:vim_matchtag_'.a:name 26 | return exists(name) ? eval(name) : a:default 27 | endfunction 28 | 29 | let s:mapping_toggle = s:GetConfig('mapping_toggle', '') 30 | let s:mapping_toggle_highlight_cursor_on = s:GetConfig('mapping_toggle_highlight_cursor_on', 31 | \s:GetConfig('mapping_both', '')) 32 | let s:enable_by_default = s:GetConfig('enable_by_default', 1) 33 | 34 | " Use global variable so it can also be used by scripts in autoload 35 | let g:vim_matchtag_files_default = '*.html,*.xml,*.js,*.jsx,*.ts,*.tsx,*.vue,*.svelte,*.jsp,*.php,*.erb,*.astro' 36 | let s:files = s:GetConfig('files', g:vim_matchtag_files_default) 37 | "}}} 38 | 39 | " Highlight 40 | highlight default link matchTag Visual 41 | highlight default link matchTagError Error 42 | 43 | " Command 44 | command! MatchTagToggle call matchtag#Toggle() 45 | command! MatchTagToggleHighlightCursorOn call matchtag#ToggleHighlightCursorOn() 46 | command! MatchTagToggleBoth call matchtag#ToggleHighlightCursorOn() 47 | 48 | " Mapping 49 | augroup matchtag-maping 50 | autocmd! matchtag-maping 51 | if !empty(s:mapping_toggle) 52 | execute 'autocmd BufNewFile,BufRead '.s:files 53 | \.' nnoremap ' 54 | \.s:mapping_toggle.' :MatchTagToggle' 55 | endif 56 | if !empty(s:mapping_toggle_highlight_cursor_on) 57 | execute 'autocmd BufNewFile,BufRead '.s:files 58 | \.' nnoremap ' 59 | \.s:mapping_toggle_highlight_cursor_on.' :MatchTagToggleHighlightCursorOn' 60 | endif 61 | augroup END 62 | 63 | function! s:ShouldEnableFile() 64 | return stridx(s:files, '*.'.&filetype) != -1 || stridx(s:files, expand('%:t')) != -1 65 | endfunction 66 | 67 | " Enable by default for specific files 68 | if s:enable_by_default 69 | if s:ShouldEnableFile() 70 | call matchtag#EnableMatchTag() 71 | else 72 | execute 'autocmd BufNewFile,BufRead '.s:files 73 | \.' ++once call matchtag#EnableMatchTag()' 74 | endif 75 | endif 76 | " vim: fdm=marker 77 | --------------------------------------------------------------------------------