1" Vim completion script 2" Language: All languages, uses existing syntax highlighting rules 3" Maintainer: David Fishburn <dfishburn dot vim at gmail dot com> 4" Version: 15.0 5" Last Change: 2021 Apr 27 6" Usage: For detailed help, ":help ft-syntax-omni" 7 8" History 9" 10" Version 15.0 11" - SyntaxComplete ignored all buffer specific overrides, always used global 12" https://github.com/vim/vim/issues/8153 13" 14" Version 14.0 15" - Fixed issue with single quotes and is_keyword 16" https://github.com/vim/vim/issues/7463 17" 18" Version 13.0 19" - Extended the option omni_syntax_group_include_{filetype} 20" to accept a comma separated list of regex's rather than 21" string. For example, for the javascript filetype you could 22" use: 23" let g:omni_syntax_group_include_javascript = 'javascript\w\+,jquery\w\+' 24" - Some syntax files (perl.vim) use the match // syntax as a mechanism 25" to identify keywords. This update attempts to parse the 26" match syntax and pull out syntax items which are at least 27" 3 words or more. 28" 29" Version 12.0 30" - It is possible to have '-' as part of iskeyword, when 31" checking for character ranges, tighten up the regex. 32" E688: More targets than List items. 33" 34" Version 11.0 35" - Corrected which characters required escaping during 36" substitution calls. 37" 38" Version 10.0 39" - Cycle through all the character ranges specified in the 40" iskeyword option and build a list of valid word separators. 41" Prior to this change, only actual characters were used, 42" where for example ASCII "45" == "-". If "45" were used 43" in iskeyword the hyphen would not be picked up. 44" This introduces a new option, since the character ranges 45" specified could be multibyte: 46" let g:omni_syntax_use_single_byte = 1 47" - This by default will only allow single byte ASCII 48" characters to be added and an additional check to ensure 49" the character is printable (see documentation for isprint). 50" 51" Version 9.0 52" - Add the check for cpo. 53" 54" Version 8.0 55" - Updated SyntaxCSyntaxGroupItems() 56" - Some additional syntax items were also allowed 57" on nextgroup= lines which were ignored by default. 58" Now these lines are processed independently. 59" 60" Version 7.0 61" - Updated syntaxcomplete#OmniSyntaxList() 62" - Looking up the syntax groups defined from a syntax file 63" looked for only 1 format of {filetype}GroupName, but some 64" syntax writers use this format as well: 65" {b:current_syntax}GroupName 66" - OmniSyntaxList() will now check for both if the first 67" method does not find a match. 68" 69" Version 6.0 70" - Added syntaxcomplete#OmniSyntaxList() 71" - Allows other plugins to use this for their own 72" purposes. 73" - It will return a List of all syntax items for the 74" syntax group name passed in. 75" - XPTemplate for SQL will use this function via the 76" sqlcomplete plugin to populate a Choose box. 77" 78" Version 5.0 79" - Updated SyntaxCSyntaxGroupItems() 80" - When processing a list of syntax groups, the final group 81" was missed in function SyntaxCSyntaxGroupItems. 82" 83" Set completion with CTRL-X CTRL-O to autoloaded function. 84" This check is in place in case this script is 85" sourced directly instead of using the autoload feature. 86if exists('+omnifunc') 87 " Do not set the option if already set since this 88 " results in an E117 warning. 89 if &omnifunc == "" 90 setlocal omnifunc=syntaxcomplete#Complete 91 endif 92endif 93 94if exists('g:loaded_syntax_completion') 95 finish 96endif 97let g:loaded_syntax_completion = 150 98 99" Turn on support for line continuations when creating the script 100let s:cpo_save = &cpo 101set cpo&vim 102 103" Set ignorecase to the ftplugin standard 104" This is the default setting, but if you define a buffer local 105" variable you can override this on a per filetype. 106if !exists('g:omni_syntax_ignorecase') 107 let g:omni_syntax_ignorecase = &ignorecase 108endif 109 110" Indicates whether we should use the iskeyword option to determine 111" how to split words. 112" This is the default setting, but if you define a buffer local 113" variable you can override this on a per filetype. 114if !exists('g:omni_syntax_use_iskeyword') 115 let g:omni_syntax_use_iskeyword = 1 116endif 117 118" When using iskeyword, this setting controls whether the characters 119" should be limited to single byte characters. 120if !exists('g:omni_syntax_use_single_byte') 121 let g:omni_syntax_use_single_byte = 1 122endif 123 124" When using iskeyword, this setting controls whether the characters 125" should be limited to single byte characters. 126if !exists('g:omni_syntax_use_iskeyword_numeric') 127 let g:omni_syntax_use_iskeyword_numeric = 1 128endif 129 130" Only display items in the completion window that are at least 131" this many characters in length. 132" This is the default setting, but if you define a buffer local 133" variable you can override this on a per filetype. 134if !exists('g:omni_syntax_minimum_length') 135 let g:omni_syntax_minimum_length = 0 136endif 137 138" This script will build a completion list based on the syntax 139" elements defined by the files in $VIMRUNTIME/syntax. 140" let s:syn_remove_words = 'match,matchgroup=,contains,'. 141let s:syn_remove_words = 'matchgroup=,contains,'. 142 \ 'links to,start=,end=' 143 " \ 'links to,start=,end=,nextgroup=' 144 145let s:cache_name = [] 146let s:cache_list = [] 147let s:prepended = '' 148 149" This function is used for the 'omnifunc' option. 150function! syntaxcomplete#Complete(findstart, base) 151 152 " Allow user to override ignorecase per buffer 153 let l:omni_syntax_ignorecase = g:omni_syntax_ignorecase 154 if exists('b:omni_syntax_ignorecase') 155 let l:omni_syntax_ignorecase = b:omni_syntax_ignorecase 156 endif 157 158 if a:findstart 159 " Locate the start of the item, including "." 160 let line = getline('.') 161 let start = col('.') - 1 162 let lastword = -1 163 while start > 0 164 " if line[start - 1] =~ '\S' 165 " let start -= 1 166 " elseif line[start - 1] =~ '\.' 167 if line[start - 1] =~ '\k' 168 let start -= 1 169 let lastword = a:findstart 170 else 171 break 172 endif 173 endwhile 174 175 " Return the column of the last word, which is going to be changed. 176 " Remember the text that comes before it in s:prepended. 177 if lastword == -1 178 let s:prepended = '' 179 return start 180 endif 181 let s:prepended = strpart(line, start, (col('.') - 1) - start) 182 return start 183 endif 184 185 " let base = s:prepended . a:base 186 let base = substitute(s:prepended, "'", "''", 'g') 187 188 let filetype = substitute(&filetype, '\.', '_', 'g') 189 let list_idx = index(s:cache_name, filetype, 0, &ignorecase) 190 if list_idx > -1 191 let compl_list = s:cache_list[list_idx] 192 else 193 let compl_list = OmniSyntaxList() 194 let s:cache_name = add( s:cache_name, filetype ) 195 let s:cache_list = add( s:cache_list, compl_list ) 196 endif 197 198 " Return list of matches. 199 200 if base != '' 201 " let compstr = join(compl_list, ' ') 202 " let expr = (l:omni_syntax_ignorecase==0?'\C':'').'\<\%('.base.'\)\@!\w\+\s*' 203 " let compstr = substitute(compstr, expr, '', 'g') 204 " let compl_list = split(compstr, '\s\+') 205 206 " Filter the list based on the first few characters the user 207 " entered 208 let expr = 'v:val '.(l:omni_syntax_ignorecase==1?'=~?':'=~#')." '^".escape(base, '\\/.*$^~[]').".*'" 209 let compl_list = filter(deepcopy(compl_list), expr) 210 endif 211 212 return compl_list 213endfunc 214 215function! syntaxcomplete#OmniSyntaxList(...) 216 if a:0 > 0 217 let parms = [] 218 if 3 == type(a:1) 219 let parms = a:1 220 elseif 1 == type(a:1) 221 let parms = split(a:1, ',') 222 endif 223 return OmniSyntaxList( parms ) 224 else 225 return OmniSyntaxList() 226 endif 227endfunc 228 229function! syntaxcomplete#OmniSyntaxClearCache() 230 let s:cache_name = [] 231 let s:cache_list = [] 232endfunction 233 234" To retrieve all syntax items regardless of syntax group: 235" echo OmniSyntaxList( [] ) 236" 237" To retrieve only the syntax items for the sqlOperator syntax group: 238" echo OmniSyntaxList( ['sqlOperator'] ) 239" 240" To retrieve all syntax items for both the sqlOperator and sqlType groups: 241" echo OmniSyntaxList( ['sqlOperator', 'sqlType'] ) 242" 243" A regular expression can also be used: 244" echo OmniSyntaxList( ['sql\w\+'] ) 245" 246" From within a plugin, you would typically assign the output to a List: > 247" let myKeywords = [] 248" let myKeywords = OmniSyntaxList( ['sqlKeyword'] ) 249function! OmniSyntaxList(...) 250 let list_parms = [] 251 if a:0 > 0 252 if 3 == type(a:1) 253 let list_parms = a:1 254 elseif 1 == type(a:1) 255 let list_parms = split(a:1, ',') 256 endif 257 endif 258 259 " Default to returning a dictionary, if use_dictionary is set to 0 260 " a list will be returned. 261 " let use_dictionary = 1 262 " if a:0 > 0 && a:1 != '' 263 " let use_dictionary = a:1 264 " endif 265 266 let saveL = @l 267 let filetype = substitute(&filetype, '\.', '_', 'g') 268 269 if empty(list_parms) 270 " Allow user to override per buffer 271 if exists('g:omni_syntax_group_include_'.filetype) 272 let l:omni_syntax_group_include_{filetype} = g:omni_syntax_group_include_{filetype} 273 endif 274 if exists('b:omni_syntax_group_include_'.filetype) 275 let l:omni_syntax_group_include_{filetype} = b:omni_syntax_group_include_{filetype} 276 endif 277 278 " Default the include group to include the requested syntax group 279 let syntax_group_include_{filetype} = '' 280 " Check if there are any overrides specified for this filetype 281 if exists('l:omni_syntax_group_include_'.filetype) 282 let syntax_group_include_{filetype} = 283 \ substitute( l:omni_syntax_group_include_{filetype},'\s\+','','g') 284 let list_parms = split(l:omni_syntax_group_include_{filetype}, ',') 285 if syntax_group_include_{filetype} =~ '\w' 286 let syntax_group_include_{filetype} = 287 \ substitute( syntax_group_include_{filetype}, 288 \ '\s*,\s*', '\\|', 'g' 289 \ ) 290 endif 291 endif 292 else 293 " A specific list was provided, use it 294 endif 295 296 " Loop through all the syntax groupnames, and build a 297 " syntax file which contains these names. This can 298 " work generically for any filetype that does not already 299 " have a plugin defined. 300 " This ASSUMES the syntax groupname BEGINS with the name 301 " of the filetype. From my casual viewing of the vim7\syntax 302 " directory this is true for almost all syntax definitions. 303 " As an example, the SQL syntax groups have this pattern: 304 " sqlType 305 " sqlOperators 306 " sqlKeyword ... 307 if !empty(list_parms) && empty(substitute(join(list_parms), '[a-zA-Z ]', '', 'g')) 308 " If list_parms only includes word characters, use it to limit 309 " the syntax elements. 310 " If using regex syntax list will fail to find those items, so 311 " simply grab the who syntax list. 312 redir @l 313 silent! exec 'syntax list '.join(list_parms) 314 redir END 315 else 316 redir @l 317 silent! exec 'syntax list' 318 redir END 319 endif 320 321 let syntax_full = "\n".@l 322 let @l = saveL 323 324 if syntax_full =~ 'E28' 325 \ || syntax_full =~ 'E411' 326 \ || syntax_full =~ 'E415' 327 \ || syntax_full =~ 'No Syntax items' 328 return [] 329 endif 330 331 let filetype = substitute(&filetype, '\.', '_', 'g') 332 333 let list_exclude_groups = [] 334 if a:0 > 0 335 " Do nothing since we have specific a specific list of groups 336 else 337 " Default the exclude group to nothing 338 let syntax_group_exclude_{filetype} = '' 339 340 " Allow user to override per buffer 341 if exists('g:omni_syntax_group_exclude_'.filetype) 342 let l:omni_syntax_group_exclude_{filetype} = g:omni_syntax_group_exclude_{filetype} 343 endif 344 if exists('b:omni_syntax_group_exclude_'.filetype) 345 let l:omni_syntax_group_exclude_{filetype} = b:omni_syntax_group_exclude_{filetype} 346 endif 347 348 " Check if there are any overrides specified for this filetype 349 if exists('l:omni_syntax_group_exclude_'.filetype) 350 let syntax_group_exclude_{filetype} = 351 \ substitute( l:omni_syntax_group_exclude_{filetype},'\s\+','','g') 352 let list_exclude_groups = split(l:omni_syntax_group_exclude_{filetype}, ',') 353 if syntax_group_exclude_{filetype} =~ '\w' 354 let syntax_group_exclude_{filetype} = 355 \ substitute( syntax_group_exclude_{filetype}, 356 \ '\s*,\s*', '\\|', 'g' 357 \ ) 358 endif 359 endif 360 endif 361 362 if empty(list_parms) 363 let list_parms = [&filetype.'\w\+'] 364 endif 365 366 let syn_list = '' 367 let index = 0 368 for group_regex in list_parms 369 " Sometimes filetypes can be composite names, like c.doxygen 370 " Loop through each individual part looking for the syntax 371 " items specific to each individual filetype. 372 " let ftindex = 0 373 " let ftindex = match(syntax_full, group_regex, ftindex) 374 375 " while ftindex > -1 376 " let ft_part_name = matchstr( syntax_full, '\w\+', ftindex ) 377 378 " Syntax rules can contain items for more than just the current 379 " filetype. They can contain additional items added by the user 380 " via autocmds or their vimrc. 381 " Some syntax files can be combined (html, php, jsp). 382 " We want only items that begin with the filetype we are interested in. 383 let next_group_regex = '\n' . 384 \ '\zs'.group_regex.'\ze'. 385 \ '\s\+xxx\s\+' 386 let index = match(syntax_full, next_group_regex, index) 387 388 " For the matched group name, strip off any of the regex special 389 " characters and see if we get a match with the current syntax 390 if index == -1 && exists('b:current_syntax') && substitute(group_regex, '[^a-zA-Z ]\+.*', '', 'g') !~ '^'.b:current_syntax 391 " There appears to be two standards when writing syntax files. 392 " Either items begin as: 393 " syn keyword {filetype}Keyword values ... 394 " let b:current_syntax = "sql" 395 " let b:current_syntax = "sqlanywhere" 396 " Or 397 " syn keyword {syntax_filename}Keyword values ... 398 " let b:current_syntax = "mysql" 399 " So, we will make the format of finding the syntax group names 400 " a bit more flexible and look for both if the first fails to 401 " find a match. 402 let next_group_regex = '\n' . 403 \ '\zs'.b:current_syntax.'\w\+\ze'. 404 \ '\s\+xxx\s\+' 405 let index = 0 406 let index = match(syntax_full, next_group_regex, index) 407 endif 408 409 while index > -1 410 let group_name = matchstr( syntax_full, '\w\+', index ) 411 412 let get_syn_list = 1 413 for exclude_group_name in list_exclude_groups 414 if '\<'.exclude_group_name.'\>' =~ '\<'.group_name.'\>' 415 let get_syn_list = 0 416 endif 417 endfor 418 419 " This code is no longer needed in version 6.0 since we have 420 " augmented the syntax list command to only retrieve the syntax 421 " groups we are interested in. 422 " 423 " if get_syn_list == 1 424 " if syntax_group_include_{filetype} != '' 425 " if '\<'.syntax_group_include_{filetype}.'\>' !~ '\<'.group_name.'\>' 426 " let get_syn_list = 0 427 " endif 428 " endif 429 " endif 430 431 if get_syn_list == 1 432 " Pass in the full syntax listing, plus the group name we 433 " are interested in. 434 let extra_syn_list = s:SyntaxCSyntaxGroupItems(group_name, syntax_full) 435 let syn_list = syn_list . extra_syn_list . "\n" 436 endif 437 438 let index = index + strlen(group_name) 439 let index = match(syntax_full, next_group_regex, index) 440 endwhile 441 442 " let ftindex = ftindex + len(ft_part_name) 443 " let ftindex = match( syntax_full, group_regex, ftindex ) 444 " endwhile 445 endfor 446 447" " Sometimes filetypes can be composite names, like c.doxygen 448" " Loop through each individual part looking for the syntax 449" " items specific to each individual filetype. 450" let syn_list = '' 451" let ftindex = 0 452" let ftindex = match(&filetype, '\w\+', ftindex) 453 454" while ftindex > -1 455" let ft_part_name = matchstr( &filetype, '\w\+', ftindex ) 456 457" " Syntax rules can contain items for more than just the current 458" " filetype. They can contain additional items added by the user 459" " via autocmds or their vimrc. 460" " Some syntax files can be combined (html, php, jsp). 461" " We want only items that begin with the filetype we are interested in. 462" let next_group_regex = '\n' . 463" \ '\zs'.ft_part_name.'\w\+\ze'. 464" \ '\s\+xxx\s\+' 465" let index = 0 466" let index = match(syntax_full, next_group_regex, index) 467 468" if index == -1 && exists('b:current_syntax') && ft_part_name != b:current_syntax 469" " There appears to be two standards when writing syntax files. 470" " Either items begin as: 471" " syn keyword {filetype}Keyword values ... 472" " let b:current_syntax = "sql" 473" " let b:current_syntax = "sqlanywhere" 474" " Or 475" " syn keyword {syntax_filename}Keyword values ... 476" " let b:current_syntax = "mysql" 477" " So, we will make the format of finding the syntax group names 478" " a bit more flexible and look for both if the first fails to 479" " find a match. 480" let next_group_regex = '\n' . 481" \ '\zs'.b:current_syntax.'\w\+\ze'. 482" \ '\s\+xxx\s\+' 483" let index = 0 484" let index = match(syntax_full, next_group_regex, index) 485" endif 486 487" while index > -1 488" let group_name = matchstr( syntax_full, '\w\+', index ) 489 490" let get_syn_list = 1 491" for exclude_group_name in list_exclude_groups 492" if '\<'.exclude_group_name.'\>' =~ '\<'.group_name.'\>' 493" let get_syn_list = 0 494" endif 495" endfor 496 497" " This code is no longer needed in version 6.0 since we have 498" " augmented the syntax list command to only retrieve the syntax 499" " groups we are interested in. 500" " 501" " if get_syn_list == 1 502" " if syntax_group_include_{filetype} != '' 503" " if '\<'.syntax_group_include_{filetype}.'\>' !~ '\<'.group_name.'\>' 504" " let get_syn_list = 0 505" " endif 506" " endif 507" " endif 508 509" if get_syn_list == 1 510" " Pass in the full syntax listing, plus the group name we 511" " are interested in. 512" let extra_syn_list = s:SyntaxCSyntaxGroupItems(group_name, syntax_full) 513" let syn_list = syn_list . extra_syn_list . "\n" 514" endif 515 516" let index = index + strlen(group_name) 517" let index = match(syntax_full, next_group_regex, index) 518" endwhile 519 520" let ftindex = ftindex + len(ft_part_name) 521" let ftindex = match( &filetype, '\w\+', ftindex ) 522" endwhile 523 524 " Convert the string to a List and sort it. 525 let compl_list = sort(split(syn_list)) 526 527 if &filetype == 'vim' 528 let short_compl_list = [] 529 for i in range(len(compl_list)) 530 if i == len(compl_list)-1 531 let next = i 532 else 533 let next = i + 1 534 endif 535 if compl_list[next] !~ '^'.compl_list[i].'.$' 536 let short_compl_list += [compl_list[i]] 537 endif 538 endfor 539 540 return short_compl_list 541 else 542 return compl_list 543 endif 544endfunction 545 546function! s:SyntaxCSyntaxGroupItems( group_name, syntax_full ) 547 548 " Allow user to override iskeyword per buffer 549 let l:omni_syntax_use_iskeyword = g:omni_syntax_use_iskeyword 550 if exists('b:omni_syntax_use_iskeyword') 551 let l:omni_syntax_use_iskeyword = b:omni_syntax_use_iskeyword 552 endif 553 554 " Allow user to override iskeyword_numeric per buffer 555 let l:omni_syntax_use_iskeyword_numeric = g:omni_syntax_use_iskeyword_numeric 556 if exists('b:omni_syntax_use_iskeyword_numeric') 557 let l:omni_syntax_use_iskeyword_numeric = b:omni_syntax_use_iskeyword_numeric 558 endif 559 560 " Allow user to override iskeyword_numeric per buffer 561 let l:omni_syntax_use_single_byte = g:omni_syntax_use_single_byte 562 if exists('b:omni_syntax_use_single_byte') 563 let l:omni_syntax_use_single_byte = b:omni_syntax_use_single_byte 564 endif 565 566 " Allow user to override minimum_length per buffer 567 let l:omni_syntax_minimum_length = g:omni_syntax_minimum_length 568 if exists('b:omni_syntax_minimum_length') 569 let l:omni_syntax_minimum_length = b:omni_syntax_minimum_length 570 endif 571 572 let syn_list = "" 573 574 " From the full syntax listing, strip out the portion for the 575 " request group. 576 " Query: 577 " \n - must begin with a newline 578 " a:group_name - the group name we are interested in 579 " \s\+xxx\s\+ - group names are always followed by xxx 580 " \zs - start the match 581 " .\{-} - everything ... 582 " \ze - end the match 583 " \( - start a group or 2 potential matches 584 " \n\w - at the first newline starting with a character 585 " \| - 2nd potential match 586 " \%$ - matches end of the file or string 587 " \) - end a group 588 let syntax_group = matchstr(a:syntax_full, 589 \ "\n".a:group_name.'\s\+xxx\s\+\zs.\{-}\ze\(\n\w\|\%$\)' 590 \ ) 591 592 if syntax_group != "" 593 " let syn_list = substitute( @l, '^.*xxx\s*\%(contained\s*\)\?', "", '' ) 594 " let syn_list = substitute( @l, '^.*xxx\s*', "", '' ) 595 596 " We only want the words for the lines beginning with 597 " containedin, but there could be other items. 598 599 " Tried to remove all lines that do not begin with contained 600 " but this does not work in all cases since you can have 601 " contained nextgroup=... 602 " So this will strip off the ending of lines with known 603 " keywords. 604 let syn_list = substitute( 605 \ syntax_group, '\<\('. 606 \ substitute( 607 \ escape(s:syn_remove_words, '\\/.*$^~[]') 608 \ , ',', '\\|', 'g' 609 \ ). 610 \ '\).\{-}\%($\|'."\n".'\)' 611 \ , "\n", 'g' 612 \ ) 613 614 " Attempt to deal with lines using the match syntax 615 " javaScriptDocTags xxx match /@\(param\|argument\|requires\|file\)\>/ 616 " Though it can use any types of regex, so this plugin will attempt 617 " to restrict it 618 " 1. Only use \( or \%( constructs remove all else 619 " 2 Remove and []s 620 " 3. Account for match //constructs 621 " \%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\? 622 " 4. Hope for the best 623 " 624 " 625 let syn_list_old = syn_list 626 while syn_list =~ '\<match\>\s\+\/' 627 if syn_list =~ 'perlElseIfError' 628 let syn_list = syn_list 629 endif 630 " Check if the match has words at least 3 characters long 631 if syn_list =~ '\<match \/\zs.\{-}\<\w\{3,}\>.\{-}\ze\\\@<!\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?\s\+' 632 " Remove everything after / and before the first \( 633 let syn_list = substitute( syn_list, '\<match \/\zs.\{-}\ze\\%\?(.\{-}\\\@<!\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?\s\+', '', 'g' ) 634 " Remove everything after \) and up to the ending / 635 let syn_list = substitute( syn_list, '\<match \/.\{-}\\)\zs.\{-}\ze\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?\s\+', '', 'g' ) 636 637 " Remove any character classes 638 " let syn_list = substitute( syn_list, '\<match /\zs.\{-}\[[^]]*\].\{-}\ze\/ ', '', 'g' ) 639 let syn_list = substitute( syn_list, '\%(\<match \/[^/]\{-}\)\@<=\[[^]]*\]\ze.\{-}\\\@<!\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?', '', 'g' ) 640 " Remove any words < 3 characters 641 let syn_list = substitute( syn_list, '\%(\<match \/[^/]\{-}\)\@<=\<\w\{1,2}\>\ze.\{-}\\\@<!\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?\s\+', '', 'g' ) 642 " Remove all non-word characters 643 " let syn_list = substitute( syn_list, '\<match /\zs.\{-}\<\W\+\>.\{-}\ze\/ ', "", 'g' ) 644 " let syn_list = substitute( syn_list, '\%(\<match \/[^/]\{-}\)\@<=\W\+\ze.\{-}\/ ', ' ', 'g' ) 645 " Do this by using the outer substitute() call to gather all 646 " text between the match /.../ tags. 647 " The inner substitute() call operates on the text selected 648 " and replaces all non-word characters. 649 let syn_list = substitute( syn_list, '\<match \/\zs\(.\{-}\)\ze\\\@<!\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?\s\+' 650 \ , '\=substitute(submatch(1), "\\W\\+", " ", "g")' 651 \ , 'g' ) 652 " Remove the match / / syntax 653 let syn_list = substitute( syn_list, '\<match \/\(.\{-}\)\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?\s\+', '\1', 'g' ) 654 else 655 " No words long enough, remove the match 656 " Remove the match syntax 657 " let syn_list = substitute( syn_list, '\<match \/[^\/]*\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?\s\+', '', 'g' ) 658 let syn_list = substitute( syn_list, '\<match \/\%(.\{-}\)\?\/\%(\%(ms\|me\|hs\|he\|rs\|re\|lc\)\S\+\)\?\s\+', '', 'g' ) 659 endif 660 if syn_list =~ '\<match\>\s\+\/' 661 " Problem removing the match / / tags 662 let syn_list = '' 663 endif 664 endwhile 665 666 667 " Now strip off the newline + blank space + contained. 668 " Also include lines with nextgroup=@someName skip_key_words syntax_element 669 " \ syn_list, '\%(^\|\n\)\@<=\s*\<\(contained\|nextgroup=\)' 670 " \ syn_list, '\%(^\|\n\)\@<=\s*\<\(contained\|nextgroup=[@a-zA-Z,]*\)' 671 let syn_list = substitute( 672 \ syn_list, '\<\(contained\|nextgroup=[@a-zA-Z,]*\)' 673 \ , "", 'g' 674 \ ) 675 676 " This can leave lines like this 677 " =@vimMenuList skipwhite onoremenu 678 " Strip the special option keywords first 679 " :h :syn-skipwhite* 680 let syn_list = substitute( 681 \ syn_list, '\<\(skipwhite\|skipnl\|skipempty\)\>' 682 \ , "", 'g' 683 \ ) 684 685 " Now remove the remainder of the nextgroup=@someName lines 686 let syn_list = substitute( 687 \ syn_list, '\%(^\|\n\)\@<=\s*\(@\w\+\)' 688 \ , "", 'g' 689 \ ) 690 691 if l:omni_syntax_use_iskeyword == 0 692 " There are a number of items which have non-word characters in 693 " them, *'T_F1'*. vim.vim is one such file. 694 " This will replace non-word characters with spaces. 695 " setlocal filetype=forth 696 " let g:omni_syntax_use_iskeyword = 1 697 " let g:omni_syntax_use_iskeyword_numeric = 1 698 " You will see entries like 699 " #>> 700 " (.local) 701 " These were found doing a grep in vim82\syntax 702 " grep iskeyword * 703 " forth.vim:setlocal iskeyword=!,@,33-35,%,$,38-64,A-Z,91-96,a-z,123-126,128-255 704 let syn_list = substitute( syn_list, '[^0-9A-Za-z_ ]', ' ', 'g' ) 705 else 706 if l:omni_syntax_use_iskeyword_numeric == 1 707 " iskeyword can contain value like this 708 " 38,42,43,45,47-58,60-62,64-90,97-122,_,+,-,*,/,%,<,=,>,:,$,?,!,@-@,94 709 " Numeric values convert to their ASCII equivalent using the 710 " nr2char() function. 711 " & 38 712 " * 42 713 " + 43 714 " - 45 715 " ^ 94 716 " Iterate through all numeric specifications and convert those 717 " to their ascii equivalent ensuring the character is printable. 718 " If so, add it to the list. 719 let accepted_chars = '' 720 for item in split(&iskeyword, ',') 721 if item =~ '\d-\d' 722 " This is a character range (ie 47-58), 723 " cycle through each character within the range 724 let [b:start, b:end] = split(item, '-') 725 for range_item in range( b:start, b:end ) 726 if range_item <= 127 || l:omni_syntax_use_single_byte == 0 727 if nr2char(range_item) =~ '\p' 728 let accepted_chars = accepted_chars . nr2char(range_item) 729 endif 730 endif 731 endfor 732 elseif item =~ '^\d\+$' 733 " Only numeric, translate to a character 734 if item < 127 || l:omni_syntax_use_single_byte == 0 735 if nr2char(item) =~ '\p' 736 let accepted_chars = accepted_chars . nr2char(item) 737 endif 738 endif 739 else 740 if char2nr(item) < 127 || l:omni_syntax_use_single_byte == 0 741 if item =~ '\p' 742 let accepted_chars = accepted_chars . item 743 endif 744 endif 745 endif 746 endfor 747 " Escape special regex characters 748 " Looks like the wrong chars are escaped. In a collection, 749 " :h /[] 750 " only `]', `\', `-' and `^' are special: 751 " let accepted_chars = escape(accepted_chars, '\\/.*$^~[]' ) 752 let accepted_chars = escape(accepted_chars, ']\-^' ) 753 " Remove all characters that are not acceptable 754 let syn_list = substitute( syn_list, '[^A-Za-z'.accepted_chars.']', ' ', 'g' ) 755 else 756 let accept_chars = ','.&iskeyword.',' 757 " Remove all character ranges 758 " let accept_chars = substitute(accept_chars, ',[^,]\+-[^,]\+,', ',', 'g') 759 let accept_chars = substitute(accept_chars, ',\@<=[^,]\+-[^,]\+,', '', 'g') 760 " Remove all numeric specifications 761 " let accept_chars = substitute(accept_chars, ',\d\{-},', ',', 'g') 762 let accept_chars = substitute(accept_chars, ',\@<=\d\{-},', '', 'g') 763 " Remove all commas 764 let accept_chars = substitute(accept_chars, ',', '', 'g') 765 " Escape special regex characters 766 " Looks like the wrong chars are escaped. In a collection, 767 " :h /[] 768 " only `]', `\', `-' and `^' are special: 769 " let accept_chars = escape(accept_chars, '\\/.*$^~[]' ) 770 let accept_chars = escape(accept_chars, ']\-^' ) 771 " Remove all characters that are not acceptable 772 let syn_list = substitute( syn_list, '[^0-9A-Za-z_'.accept_chars.']', ' ', 'g' ) 773 endif 774 endif 775 776 if l:omni_syntax_minimum_length > 0 777 " If the user specified a minimum length, enforce it 778 let syn_list = substitute(' '.syn_list.' ', ' \S\{,'.l:omni_syntax_minimum_length.'}\ze ', ' ', 'g') 779 endif 780 else 781 let syn_list = '' 782 endif 783 784 return syn_list 785endfunction 786 787function! OmniSyntaxShowChars(spec) 788 let result = [] 789 for item in split(a:spec, ',') 790 if len(item) > 1 791 if item == '@-@' 792 call add(result, char2nr(item)) 793 else 794 call extend(result, call('range', split(item, '-'))) 795 endif 796 else 797 if item == '@' " assume this is [A-Za-z] 798 for [c1, c2] in [['A', 'Z'], ['a', 'z']] 799 call extend(result, range(char2nr(c1), char2nr(c2))) 800 endfor 801 else 802 call add(result, char2nr(item)) 803 endif 804 endif 805 endfor 806 return join(map(result, 'nr2char(v:val)'), ', ') 807endfunction 808 809let &cpo = s:cpo_save 810unlet s:cpo_save 811