14770d09aSBram Moolenaar" Vim completion script
24770d09aSBram Moolenaar" Language:    All languages, uses existing syntax highlighting rules
36dfc28beSBram Moolenaar" Maintainer:  David Fishburn <dfishburn dot vim at gmail dot com>
4*34feacbcSBram Moolenaar" Version:     11.0
5*34feacbcSBram Moolenaar" Last Change: 2012 Dec 04
697e8f356SBram Moolenaar" Usage:       For detailed help, ":help ft-syntax-omni"
74770d09aSBram Moolenaar
86dfc28beSBram Moolenaar" History
940af4e39SBram Moolenaar"
10*34feacbcSBram Moolenaar" Version 11.0
11*34feacbcSBram Moolenaar"     Corrected which characters required escaping during
12*34feacbcSBram Moolenaar"     substitution calls.
13*34feacbcSBram Moolenaar"
1497d62497SBram Moolenaar" Version 10.0
1597d62497SBram Moolenaar"     Cycle through all the character ranges specified in the
1697d62497SBram Moolenaar"     iskeyword option and build a list of valid word separators.
1797d62497SBram Moolenaar"     Prior to this change, only actual characters were used,
1897d62497SBram Moolenaar"     where for example ASCII "45" == "-".  If "45" were used
1997d62497SBram Moolenaar"     in iskeyword the hyphen would not be picked up.
2097d62497SBram Moolenaar"     This introduces a new option, since the character ranges
2197d62497SBram Moolenaar"     specified could be multibyte:
2297d62497SBram Moolenaar"         let g:omni_syntax_use_single_byte = 1
2397d62497SBram Moolenaar"     This by default will only allow single byte ASCII
2497d62497SBram Moolenaar"     characters to be added and an additional check to ensure
2597d62497SBram Moolenaar"     the charater is printable (see documentation for isprint).
2697d62497SBram Moolenaar"
2797d62497SBram Moolenaar" Version 9.0
2897d62497SBram Moolenaar"     Add the check for cpo.
2997d62497SBram Moolenaar"
30f1568ecaSBram Moolenaar" Version 8.0
31f1568ecaSBram Moolenaar"     Updated SyntaxCSyntaxGroupItems()
32f1568ecaSBram Moolenaar"         - Some additional syntax items were also allowed
33f1568ecaSBram Moolenaar"           on nextgroup= lines which were ignored by default.
34f1568ecaSBram Moolenaar"           Now these lines are processed independently.
35f1568ecaSBram Moolenaar"
3640af4e39SBram Moolenaar" Version 7.0
3740af4e39SBram Moolenaar"     Updated syntaxcomplete#OmniSyntaxList()
3840af4e39SBram Moolenaar"         - Looking up the syntax groups defined from a syntax file
3940af4e39SBram Moolenaar"           looked for only 1 format of {filetype}GroupName, but some
4040af4e39SBram Moolenaar"           syntax writers use this format as well:
4140af4e39SBram Moolenaar"               {b:current_syntax}GroupName
4240af4e39SBram Moolenaar"           OmniSyntaxList() will now check for both if the first
4340af4e39SBram Moolenaar"           method does not find a match.
4440af4e39SBram Moolenaar"
4540af4e39SBram Moolenaar" Version 6.0
4640af4e39SBram Moolenaar"     Added syntaxcomplete#OmniSyntaxList()
4740af4e39SBram Moolenaar"         - Allows other plugins to use this for their own
4840af4e39SBram Moolenaar"           purposes.
4940af4e39SBram Moolenaar"         - It will return a List of all syntax items for the
5040af4e39SBram Moolenaar"           syntax group name passed in.
5140af4e39SBram Moolenaar"         - XPTemplate for SQL will use this function via the
5240af4e39SBram Moolenaar"           sqlcomplete plugin to populate a Choose box.
5340af4e39SBram Moolenaar"
546dfc28beSBram Moolenaar" Version 5.0
5540af4e39SBram Moolenaar"     Updated SyntaxCSyntaxGroupItems()
5640af4e39SBram Moolenaar"         - When processing a list of syntax groups, the final group
576dfc28beSBram Moolenaar"           was missed in function SyntaxCSyntaxGroupItems.
586dfc28beSBram Moolenaar"
594770d09aSBram Moolenaar" Set completion with CTRL-X CTRL-O to autoloaded function.
60c15ef30cSBram Moolenaar" This check is in place in case this script is
61c15ef30cSBram Moolenaar" sourced directly instead of using the autoload feature.
62c06ac340SBram Moolenaarif exists('+omnifunc')
63c15ef30cSBram Moolenaar    " Do not set the option if already set since this
64c15ef30cSBram Moolenaar    " results in an E117 warning.
65c15ef30cSBram Moolenaar    if &omnifunc == ""
66c06ac340SBram Moolenaar        setlocal omnifunc=syntaxcomplete#Complete
674770d09aSBram Moolenaar    endif
68c15ef30cSBram Moolenaarendif
694770d09aSBram Moolenaar
704770d09aSBram Moolenaarif exists('g:loaded_syntax_completion')
714770d09aSBram Moolenaar    finish
724770d09aSBram Moolenaarendif
73*34feacbcSBram Moolenaarlet g:loaded_syntax_completion = 110
7497d62497SBram Moolenaar
7597d62497SBram Moolenaar" Turn on support for line continuations when creating the script
7697d62497SBram Moolenaarlet s:cpo_save = &cpo
7797d62497SBram Moolenaarset cpo&vim
7897e8f356SBram Moolenaar
7997e8f356SBram Moolenaar" Set ignorecase to the ftplugin standard
809964e468SBram Moolenaar" This is the default setting, but if you define a buffer local
819964e468SBram Moolenaar" variable you can override this on a per filetype.
8297e8f356SBram Moolenaarif !exists('g:omni_syntax_ignorecase')
8397e8f356SBram Moolenaar    let g:omni_syntax_ignorecase = &ignorecase
8497e8f356SBram Moolenaarendif
854770d09aSBram Moolenaar
869964e468SBram Moolenaar" Indicates whether we should use the iskeyword option to determine
879964e468SBram Moolenaar" how to split words.
889964e468SBram Moolenaar" This is the default setting, but if you define a buffer local
899964e468SBram Moolenaar" variable you can override this on a per filetype.
909964e468SBram Moolenaarif !exists('g:omni_syntax_use_iskeyword')
919964e468SBram Moolenaar    let g:omni_syntax_use_iskeyword = 1
929964e468SBram Moolenaarendif
939964e468SBram Moolenaar
9497d62497SBram Moolenaar" When using iskeyword, this setting controls whether the characters
9597d62497SBram Moolenaar" should be limited to single byte characters.
9697d62497SBram Moolenaarif !exists('g:omni_syntax_use_single_byte')
9797d62497SBram Moolenaar    let g:omni_syntax_use_single_byte = 1
9897d62497SBram Moolenaarendif
9997d62497SBram Moolenaar
10097d62497SBram Moolenaar" When using iskeyword, this setting controls whether the characters
10197d62497SBram Moolenaar" should be limited to single byte characters.
10297d62497SBram Moolenaarif !exists('g:omni_syntax_use_iskeyword_numeric')
10397d62497SBram Moolenaar    let g:omni_syntax_use_iskeyword_numeric = 1
10497d62497SBram Moolenaarendif
10597d62497SBram Moolenaar
1069964e468SBram Moolenaar" Only display items in the completion window that are at least
1079964e468SBram Moolenaar" this many characters in length.
1089964e468SBram Moolenaar" This is the default setting, but if you define a buffer local
1099964e468SBram Moolenaar" variable you can override this on a per filetype.
1109964e468SBram Moolenaarif !exists('g:omni_syntax_minimum_length')
1119964e468SBram Moolenaar    let g:omni_syntax_minimum_length = 0
1129964e468SBram Moolenaarendif
1139964e468SBram Moolenaar
1144770d09aSBram Moolenaar" This script will build a completion list based on the syntax
1154770d09aSBram Moolenaar" elements defined by the files in $VIMRUNTIME/syntax.
1164770d09aSBram Moolenaarlet s:syn_remove_words = 'match,matchgroup=,contains,'.
117f1568ecaSBram Moolenaar            \ 'links to,start=,end='
118f1568ecaSBram Moolenaar            " \ 'links to,start=,end=,nextgroup='
1194770d09aSBram Moolenaar
1204770d09aSBram Moolenaarlet s:cache_name = []
1214770d09aSBram Moolenaarlet s:cache_list = []
122c15ef30cSBram Moolenaarlet s:prepended  = ''
1234770d09aSBram Moolenaar
1244770d09aSBram Moolenaar" This function is used for the 'omnifunc' option.
1254770d09aSBram Moolenaarfunction! syntaxcomplete#Complete(findstart, base)
1264770d09aSBram Moolenaar
1279964e468SBram Moolenaar    " Only display items in the completion window that are at least
1289964e468SBram Moolenaar    " this many characters in length
1299964e468SBram Moolenaar    if !exists('b:omni_syntax_ignorecase')
1309964e468SBram Moolenaar        if exists('g:omni_syntax_ignorecase')
1319964e468SBram Moolenaar            let b:omni_syntax_ignorecase = g:omni_syntax_ignorecase
1329964e468SBram Moolenaar        else
1339964e468SBram Moolenaar            let b:omni_syntax_ignorecase = &ignorecase
1349964e468SBram Moolenaar        endif
1359964e468SBram Moolenaar    endif
1369964e468SBram Moolenaar
1374770d09aSBram Moolenaar    if a:findstart
1384770d09aSBram Moolenaar        " Locate the start of the item, including "."
1394770d09aSBram Moolenaar        let line = getline('.')
1404770d09aSBram Moolenaar        let start = col('.') - 1
1414770d09aSBram Moolenaar        let lastword = -1
1424770d09aSBram Moolenaar        while start > 0
1439964e468SBram Moolenaar            " if line[start - 1] =~ '\S'
1449964e468SBram Moolenaar            "     let start -= 1
1459964e468SBram Moolenaar            " elseif line[start - 1] =~ '\.'
1469964e468SBram Moolenaar            if line[start - 1] =~ '\k'
1474770d09aSBram Moolenaar                let start -= 1
1489964e468SBram Moolenaar                let lastword = a:findstart
1494770d09aSBram Moolenaar            else
1504770d09aSBram Moolenaar                break
1514770d09aSBram Moolenaar            endif
1524770d09aSBram Moolenaar        endwhile
1534770d09aSBram Moolenaar
1544770d09aSBram Moolenaar        " Return the column of the last word, which is going to be changed.
1554770d09aSBram Moolenaar        " Remember the text that comes before it in s:prepended.
1564770d09aSBram Moolenaar        if lastword == -1
1574770d09aSBram Moolenaar            let s:prepended = ''
1584770d09aSBram Moolenaar            return start
1594770d09aSBram Moolenaar        endif
1609964e468SBram Moolenaar        let s:prepended = strpart(line, start, (col('.') - 1) - start)
1619964e468SBram Moolenaar        return start
1624770d09aSBram Moolenaar    endif
1634770d09aSBram Moolenaar
1649964e468SBram Moolenaar    " let base = s:prepended . a:base
1659964e468SBram Moolenaar    let base = s:prepended
1664770d09aSBram Moolenaar
16797e8f356SBram Moolenaar    let filetype = substitute(&filetype, '\.', '_', 'g')
16897e8f356SBram Moolenaar    let list_idx = index(s:cache_name, filetype, 0, &ignorecase)
1694770d09aSBram Moolenaar    if list_idx > -1
1704770d09aSBram Moolenaar        let compl_list = s:cache_list[list_idx]
1714770d09aSBram Moolenaar    else
172c06ac340SBram Moolenaar        let compl_list   = OmniSyntaxList()
17397e8f356SBram Moolenaar        let s:cache_name = add( s:cache_name,  filetype )
1744770d09aSBram Moolenaar        let s:cache_list = add( s:cache_list,  compl_list )
1754770d09aSBram Moolenaar    endif
1764770d09aSBram Moolenaar
1774770d09aSBram Moolenaar    " Return list of matches.
1784770d09aSBram Moolenaar
1799964e468SBram Moolenaar    if base != ''
1809964e468SBram Moolenaar        " let compstr    = join(compl_list, ' ')
1819964e468SBram Moolenaar        " let expr       = (b:omni_syntax_ignorecase==0?'\C':'').'\<\%('.base.'\)\@!\w\+\s*'
1829964e468SBram Moolenaar        " let compstr    = substitute(compstr, expr, '', 'g')
1839964e468SBram Moolenaar        " let compl_list = split(compstr, '\s\+')
1849964e468SBram Moolenaar
1859964e468SBram Moolenaar        " Filter the list based on the first few characters the user
1869964e468SBram Moolenaar        " entered
1879964e468SBram Moolenaar        let expr = 'v:val '.(g:omni_syntax_ignorecase==1?'=~?':'=~#')." '^".escape(base, '\\/.*$^~[]').".*'"
1889964e468SBram Moolenaar        let compl_list = filter(deepcopy(compl_list), expr)
1894770d09aSBram Moolenaar    endif
1904770d09aSBram Moolenaar
1914770d09aSBram Moolenaar    return compl_list
1924770d09aSBram Moolenaarendfunc
1934770d09aSBram Moolenaar
19440af4e39SBram Moolenaarfunction! syntaxcomplete#OmniSyntaxList(...)
19540af4e39SBram Moolenaar    if a:0 > 0
19640af4e39SBram Moolenaar        let parms = []
19740af4e39SBram Moolenaar        if 3 == type(a:1)
19840af4e39SBram Moolenaar            let parms = a:1
19940af4e39SBram Moolenaar        elseif 1 == type(a:1)
20040af4e39SBram Moolenaar            let parms = split(a:1, ',')
20140af4e39SBram Moolenaar        endif
20240af4e39SBram Moolenaar        return OmniSyntaxList( parms )
20340af4e39SBram Moolenaar    else
20440af4e39SBram Moolenaar        return OmniSyntaxList()
20540af4e39SBram Moolenaar    endif
20640af4e39SBram Moolenaarendfunc
20740af4e39SBram Moolenaar
20840af4e39SBram Moolenaarfunction! OmniSyntaxList(...)
20940af4e39SBram Moolenaar    let list_parms = []
21040af4e39SBram Moolenaar    if a:0 > 0
21140af4e39SBram Moolenaar        if 3 == type(a:1)
21240af4e39SBram Moolenaar            let list_parms = a:1
21340af4e39SBram Moolenaar        elseif 1 == type(a:1)
21440af4e39SBram Moolenaar            let list_parms = split(a:1, ',')
21540af4e39SBram Moolenaar        endif
21640af4e39SBram Moolenaar    endif
21740af4e39SBram Moolenaar
21897e8f356SBram Moolenaar    " Default to returning a dictionary, if use_dictionary is set to 0
21997e8f356SBram Moolenaar    " a list will be returned.
22097e8f356SBram Moolenaar    " let use_dictionary = 1
22197e8f356SBram Moolenaar    " if a:0 > 0 && a:1 != ''
22297e8f356SBram Moolenaar    "     let use_dictionary = a:1
22397e8f356SBram Moolenaar    " endif
22497e8f356SBram Moolenaar
2259964e468SBram Moolenaar    " Only display items in the completion window that are at least
2269964e468SBram Moolenaar    " this many characters in length
2279964e468SBram Moolenaar    if !exists('b:omni_syntax_use_iskeyword')
2289964e468SBram Moolenaar        if exists('g:omni_syntax_use_iskeyword')
2299964e468SBram Moolenaar            let b:omni_syntax_use_iskeyword = g:omni_syntax_use_iskeyword
2309964e468SBram Moolenaar        else
2319964e468SBram Moolenaar            let b:omni_syntax_use_iskeyword = 1
2329964e468SBram Moolenaar        endif
2339964e468SBram Moolenaar    endif
2349964e468SBram Moolenaar
2359964e468SBram Moolenaar    " Only display items in the completion window that are at least
2369964e468SBram Moolenaar    " this many characters in length
2379964e468SBram Moolenaar    if !exists('b:omni_syntax_minimum_length')
2389964e468SBram Moolenaar        if exists('g:omni_syntax_minimum_length')
2399964e468SBram Moolenaar            let b:omni_syntax_minimum_length = g:omni_syntax_minimum_length
2409964e468SBram Moolenaar        else
2419964e468SBram Moolenaar            let b:omni_syntax_minimum_length = 0
2429964e468SBram Moolenaar        endif
2439964e468SBram Moolenaar    endif
2449964e468SBram Moolenaar
2454770d09aSBram Moolenaar    let saveL = @l
24640af4e39SBram Moolenaar    let filetype = substitute(&filetype, '\.', '_', 'g')
24740af4e39SBram Moolenaar
24840af4e39SBram Moolenaar    if empty(list_parms)
24940af4e39SBram Moolenaar        " Default the include group to include the requested syntax group
25040af4e39SBram Moolenaar        let syntax_group_include_{filetype} = ''
25140af4e39SBram Moolenaar        " Check if there are any overrides specified for this filetype
25240af4e39SBram Moolenaar        if exists('g:omni_syntax_group_include_'.filetype)
25340af4e39SBram Moolenaar            let syntax_group_include_{filetype} =
25440af4e39SBram Moolenaar                        \ substitute( g:omni_syntax_group_include_{filetype},'\s\+','','g')
25540af4e39SBram Moolenaar            let list_parms = split(g:omni_syntax_group_include_{filetype}, ',')
25640af4e39SBram Moolenaar            if syntax_group_include_{filetype} =~ '\w'
25740af4e39SBram Moolenaar                let syntax_group_include_{filetype} =
25840af4e39SBram Moolenaar                            \ substitute( syntax_group_include_{filetype},
25940af4e39SBram Moolenaar                            \ '\s*,\s*', '\\|', 'g'
26040af4e39SBram Moolenaar                            \ )
26140af4e39SBram Moolenaar            endif
26240af4e39SBram Moolenaar        endif
26340af4e39SBram Moolenaar    else
26440af4e39SBram Moolenaar        " A specific list was provided, use it
26540af4e39SBram Moolenaar    endif
2664770d09aSBram Moolenaar
2674770d09aSBram Moolenaar    " Loop through all the syntax groupnames, and build a
2684770d09aSBram Moolenaar    " syntax file which contains these names.  This can
2694770d09aSBram Moolenaar    " work generically for any filetype that does not already
2704770d09aSBram Moolenaar    " have a plugin defined.
2714770d09aSBram Moolenaar    " This ASSUMES the syntax groupname BEGINS with the name
272c06ac340SBram Moolenaar    " of the filetype.  From my casual viewing of the vim7\syntax
27340af4e39SBram Moolenaar    " directory this is true for almost all syntax definitions.
27440af4e39SBram Moolenaar    " As an example, the SQL syntax groups have this pattern:
27540af4e39SBram Moolenaar    "     sqlType
27640af4e39SBram Moolenaar    "     sqlOperators
27740af4e39SBram Moolenaar    "     sqlKeyword ...
2784770d09aSBram Moolenaar    redir @l
27940af4e39SBram Moolenaar    silent! exec 'syntax list '.join(list_parms)
2804770d09aSBram Moolenaar    redir END
2814770d09aSBram Moolenaar
282c06ac340SBram Moolenaar    let syntax_full = "\n".@l
2834770d09aSBram Moolenaar    let @l = saveL
2844770d09aSBram Moolenaar
285c06ac340SBram Moolenaar    if syntax_full =~ 'E28'
286c06ac340SBram Moolenaar                \ || syntax_full =~ 'E411'
287c06ac340SBram Moolenaar                \ || syntax_full =~ 'E415'
288c06ac340SBram Moolenaar                \ || syntax_full =~ 'No Syntax items'
289c06ac340SBram Moolenaar        return []
2904770d09aSBram Moolenaar    endif
2914770d09aSBram Moolenaar
29297e8f356SBram Moolenaar    let filetype = substitute(&filetype, '\.', '_', 'g')
29397e8f356SBram Moolenaar
29440af4e39SBram Moolenaar    let list_exclude_groups = []
29540af4e39SBram Moolenaar    if a:0 > 0
29640af4e39SBram Moolenaar        " Do nothing since we have specific a specific list of groups
29740af4e39SBram Moolenaar    else
298c06ac340SBram Moolenaar        " Default the exclude group to nothing
29997e8f356SBram Moolenaar        let syntax_group_exclude_{filetype} = ''
300c06ac340SBram Moolenaar        " Check if there are any overrides specified for this filetype
30197e8f356SBram Moolenaar        if exists('g:omni_syntax_group_exclude_'.filetype)
30297e8f356SBram Moolenaar            let syntax_group_exclude_{filetype} =
30397e8f356SBram Moolenaar                        \ substitute( g:omni_syntax_group_exclude_{filetype},'\s\+','','g')
30440af4e39SBram Moolenaar            let list_exclude_groups = split(g:omni_syntax_group_exclude_{filetype}, ',')
30597e8f356SBram Moolenaar            if syntax_group_exclude_{filetype} =~ '\w'
30697e8f356SBram Moolenaar                let syntax_group_exclude_{filetype} =
30797e8f356SBram Moolenaar                            \ substitute( syntax_group_exclude_{filetype},
308c06ac340SBram Moolenaar                            \ '\s*,\s*', '\\|', 'g'
309c06ac340SBram Moolenaar                            \ )
310c06ac340SBram Moolenaar            endif
311c06ac340SBram Moolenaar        endif
31240af4e39SBram Moolenaar    endif
313c06ac340SBram Moolenaar
31497e8f356SBram Moolenaar    " Sometimes filetypes can be composite names, like c.doxygen
31597e8f356SBram Moolenaar    " Loop through each individual part looking for the syntax
31697e8f356SBram Moolenaar    " items specific to each individual filetype.
31797e8f356SBram Moolenaar    let syn_list = ''
31897e8f356SBram Moolenaar    let ftindex  = 0
31997e8f356SBram Moolenaar    let ftindex  = match(&filetype, '\w\+', ftindex)
32097e8f356SBram Moolenaar
32197e8f356SBram Moolenaar    while ftindex > -1
32297e8f356SBram Moolenaar        let ft_part_name = matchstr( &filetype, '\w\+', ftindex )
32397e8f356SBram Moolenaar
324c06ac340SBram Moolenaar        " Syntax rules can contain items for more than just the current
325c06ac340SBram Moolenaar        " filetype.  They can contain additional items added by the user
326c06ac340SBram Moolenaar        " via autocmds or their vimrc.
327c06ac340SBram Moolenaar        " Some syntax files can be combined (html, php, jsp).
328c06ac340SBram Moolenaar        " We want only items that begin with the filetype we are interested in.
3294770d09aSBram Moolenaar        let next_group_regex = '\n' .
33097e8f356SBram Moolenaar                    \ '\zs'.ft_part_name.'\w\+\ze'.
331c06ac340SBram Moolenaar                    \ '\s\+xxx\s\+'
3324770d09aSBram Moolenaar        let index    = 0
333c06ac340SBram Moolenaar        let index    = match(syntax_full, next_group_regex, index)
3344770d09aSBram Moolenaar
33540af4e39SBram Moolenaar        if index == -1 && exists('b:current_syntax') && ft_part_name != b:current_syntax
33640af4e39SBram Moolenaar            " There appears to be two standards when writing syntax files.
33740af4e39SBram Moolenaar            " Either items begin as:
33840af4e39SBram Moolenaar            "     syn keyword {filetype}Keyword         values ...
33940af4e39SBram Moolenaar            "     let b:current_syntax = "sql"
34040af4e39SBram Moolenaar            "     let b:current_syntax = "sqlanywhere"
34140af4e39SBram Moolenaar            " Or
34240af4e39SBram Moolenaar            "     syn keyword {syntax_filename}Keyword  values ...
34340af4e39SBram Moolenaar            "     let b:current_syntax = "mysql"
34440af4e39SBram Moolenaar            " So, we will make the format of finding the syntax group names
34540af4e39SBram Moolenaar            " a bit more flexible and look for both if the first fails to
34640af4e39SBram Moolenaar            " find a match.
34740af4e39SBram Moolenaar            let next_group_regex = '\n' .
34840af4e39SBram Moolenaar                        \ '\zs'.b:current_syntax.'\w\+\ze'.
34940af4e39SBram Moolenaar                        \ '\s\+xxx\s\+'
35040af4e39SBram Moolenaar            let index    = 0
35140af4e39SBram Moolenaar            let index    = match(syntax_full, next_group_regex, index)
35240af4e39SBram Moolenaar        endif
35340af4e39SBram Moolenaar
35497e8f356SBram Moolenaar        while index > -1
355c06ac340SBram Moolenaar            let group_name = matchstr( syntax_full, '\w\+', index )
3564770d09aSBram Moolenaar
357c06ac340SBram Moolenaar            let get_syn_list = 1
35840af4e39SBram Moolenaar            for exclude_group_name in list_exclude_groups
35940af4e39SBram Moolenaar                if '\<'.exclude_group_name.'\>' =~ '\<'.group_name.'\>'
360c06ac340SBram Moolenaar                    let get_syn_list = 0
361c06ac340SBram Moolenaar                endif
36240af4e39SBram Moolenaar            endfor
363c06ac340SBram Moolenaar
36440af4e39SBram Moolenaar            " This code is no longer needed in version 6.0 since we have
36540af4e39SBram Moolenaar            " augmented the syntax list command to only retrieve the syntax
36640af4e39SBram Moolenaar            " groups we are interested in.
36740af4e39SBram Moolenaar            "
36840af4e39SBram Moolenaar            " if get_syn_list == 1
36940af4e39SBram Moolenaar            "     if syntax_group_include_{filetype} != ''
37040af4e39SBram Moolenaar            "         if '\<'.syntax_group_include_{filetype}.'\>' !~ '\<'.group_name.'\>'
37140af4e39SBram Moolenaar            "             let get_syn_list = 0
37240af4e39SBram Moolenaar            "         endif
37340af4e39SBram Moolenaar            "     endif
37440af4e39SBram Moolenaar            " endif
375c06ac340SBram Moolenaar
376c06ac340SBram Moolenaar            if get_syn_list == 1
377c06ac340SBram Moolenaar                " Pass in the full syntax listing, plus the group name we
378c06ac340SBram Moolenaar                " are interested in.
379e2f98b95SBram Moolenaar                let extra_syn_list = s:SyntaxCSyntaxGroupItems(group_name, syntax_full)
3804770d09aSBram Moolenaar                let syn_list = syn_list . extra_syn_list . "\n"
381c06ac340SBram Moolenaar            endif
3824770d09aSBram Moolenaar
3834770d09aSBram Moolenaar            let index = index + strlen(group_name)
384c06ac340SBram Moolenaar            let index = match(syntax_full, next_group_regex, index)
3854770d09aSBram Moolenaar        endwhile
3864770d09aSBram Moolenaar
38797e8f356SBram Moolenaar        let ftindex  = ftindex + len(ft_part_name)
38897e8f356SBram Moolenaar        let ftindex  = match( &filetype, '\w\+', ftindex )
38997e8f356SBram Moolenaar    endwhile
39097e8f356SBram Moolenaar
391c06ac340SBram Moolenaar    " Convert the string to a List and sort it.
392c06ac340SBram Moolenaar    let compl_list = sort(split(syn_list))
393c06ac340SBram Moolenaar
394c06ac340SBram Moolenaar    if &filetype == 'vim'
395c06ac340SBram Moolenaar        let short_compl_list = []
396c06ac340SBram Moolenaar        for i in range(len(compl_list))
397c06ac340SBram Moolenaar            if i == len(compl_list)-1
398c06ac340SBram Moolenaar                let next = i
399c06ac340SBram Moolenaar            else
400c06ac340SBram Moolenaar                let next = i + 1
401c06ac340SBram Moolenaar            endif
402c06ac340SBram Moolenaar            if  compl_list[next] !~ '^'.compl_list[i].'.$'
403c06ac340SBram Moolenaar                let short_compl_list += [compl_list[i]]
404c06ac340SBram Moolenaar            endif
405c06ac340SBram Moolenaar        endfor
406c06ac340SBram Moolenaar
407c06ac340SBram Moolenaar        return short_compl_list
408c06ac340SBram Moolenaar    else
409c06ac340SBram Moolenaar        return compl_list
410c06ac340SBram Moolenaar    endif
4114770d09aSBram Moolenaarendfunction
4124770d09aSBram Moolenaar
413e2f98b95SBram Moolenaarfunction! s:SyntaxCSyntaxGroupItems( group_name, syntax_full )
4144770d09aSBram Moolenaar
415c06ac340SBram Moolenaar    let syn_list = ""
4164770d09aSBram Moolenaar
417c06ac340SBram Moolenaar    " From the full syntax listing, strip out the portion for the
418c06ac340SBram Moolenaar    " request group.
419c06ac340SBram Moolenaar    " Query:
420c06ac340SBram Moolenaar    "     \n           - must begin with a newline
421c06ac340SBram Moolenaar    "     a:group_name - the group name we are interested in
422c06ac340SBram Moolenaar    "     \s\+xxx\s\+  - group names are always followed by xxx
423c06ac340SBram Moolenaar    "     \zs          - start the match
424c06ac340SBram Moolenaar    "     .\{-}        - everything ...
425c06ac340SBram Moolenaar    "     \ze          - end the match
4266dfc28beSBram Moolenaar    "     \(           - start a group or 2 potential matches
427c06ac340SBram Moolenaar    "     \n\w         - at the first newline starting with a character
4286dfc28beSBram Moolenaar    "     \|           - 2nd potential match
4296dfc28beSBram Moolenaar    "     \%$          - matches end of the file or string
4306dfc28beSBram Moolenaar    "     \)           - end a group
431c06ac340SBram Moolenaar    let syntax_group = matchstr(a:syntax_full,
4326dfc28beSBram Moolenaar                \ "\n".a:group_name.'\s\+xxx\s\+\zs.\{-}\ze\(\n\w\|\%$\)'
433c06ac340SBram Moolenaar                \ )
434c06ac340SBram Moolenaar
435c06ac340SBram Moolenaar    if syntax_group != ""
4364770d09aSBram Moolenaar        " let syn_list = substitute( @l, '^.*xxx\s*\%(contained\s*\)\?', "", '' )
437c06ac340SBram Moolenaar        " let syn_list = substitute( @l, '^.*xxx\s*', "", '' )
4384770d09aSBram Moolenaar
4394770d09aSBram Moolenaar        " We only want the words for the lines begining with
4404770d09aSBram Moolenaar        " containedin, but there could be other items.
4414770d09aSBram Moolenaar
4424770d09aSBram Moolenaar        " Tried to remove all lines that do not begin with contained
4434770d09aSBram Moolenaar        " but this does not work in all cases since you can have
4444770d09aSBram Moolenaar        "    contained nextgroup=...
4454770d09aSBram Moolenaar        " So this will strip off the ending of lines with known
4464770d09aSBram Moolenaar        " keywords.
44797e8f356SBram Moolenaar        let syn_list = substitute(
44897e8f356SBram Moolenaar                    \    syntax_group, '\<\('.
4494770d09aSBram Moolenaar                    \    substitute(
4504770d09aSBram Moolenaar                    \      escape(s:syn_remove_words, '\\/.*$^~[]')
45197e8f356SBram Moolenaar                    \      , ',', '\\|', 'g'
45297e8f356SBram Moolenaar                    \    ).
4534770d09aSBram Moolenaar                    \    '\).\{-}\%($\|'."\n".'\)'
45497e8f356SBram Moolenaar                    \    , "\n", 'g'
45597e8f356SBram Moolenaar                    \  )
4564770d09aSBram Moolenaar
457f1568ecaSBram Moolenaar        " Now strip off the newline + blank space + contained.
458f1568ecaSBram Moolenaar        " Also include lines with nextgroup=@someName skip_key_words syntax_element
45997e8f356SBram Moolenaar        let syn_list = substitute(
460f1568ecaSBram Moolenaar                    \    syn_list, '\%(^\|\n\)\@<=\s*\<\(contained\|nextgroup=\)'
461f1568ecaSBram Moolenaar                    \    , "", 'g'
462f1568ecaSBram Moolenaar                    \ )
463f1568ecaSBram Moolenaar
464f1568ecaSBram Moolenaar        " This can leave lines like this
465f1568ecaSBram Moolenaar        "     =@vimMenuList  skipwhite onoremenu
466f1568ecaSBram Moolenaar        " Strip the special option keywords first
467f1568ecaSBram Moolenaar        "     :h :syn-skipwhite*
468f1568ecaSBram Moolenaar        let syn_list = substitute(
469f1568ecaSBram Moolenaar                    \    syn_list, '\<\(skipwhite\|skipnl\|skipempty\)\>'
470f1568ecaSBram Moolenaar                    \    , "", 'g'
471f1568ecaSBram Moolenaar                    \ )
472f1568ecaSBram Moolenaar
473f1568ecaSBram Moolenaar        " Now remove the remainder of the nextgroup=@someName lines
474f1568ecaSBram Moolenaar        let syn_list = substitute(
475f1568ecaSBram Moolenaar                    \    syn_list, '\%(^\|\n\)\@<=\s*\(@\w\+\)'
47697e8f356SBram Moolenaar                    \    , "", 'g'
47797e8f356SBram Moolenaar                    \ )
4784770d09aSBram Moolenaar
4799964e468SBram Moolenaar        if b:omni_syntax_use_iskeyword == 0
4804770d09aSBram Moolenaar            " There are a number of items which have non-word characters in
4814770d09aSBram Moolenaar            " them, *'T_F1'*.  vim.vim is one such file.
4824770d09aSBram Moolenaar            " This will replace non-word characters with spaces.
4834770d09aSBram Moolenaar            let syn_list = substitute( syn_list, '[^0-9A-Za-z_ ]', ' ', 'g' )
4844770d09aSBram Moolenaar        else
48597d62497SBram Moolenaar            if g:omni_syntax_use_iskeyword_numeric == 1
48697d62497SBram Moolenaar                " iskeyword can contain value like this
48797d62497SBram Moolenaar                " 38,42,43,45,47-58,60-62,64-90,97-122,_,+,-,*,/,%,<,=,>,:,$,?,!,@-@,94
48897d62497SBram Moolenaar                " Numeric values convert to their ASCII equivalent using the
48997d62497SBram Moolenaar                " nr2char() function.
49097d62497SBram Moolenaar                "     &       38
49197d62497SBram Moolenaar                "     *       42
49297d62497SBram Moolenaar                "     +       43
49397d62497SBram Moolenaar                "     -       45
49497d62497SBram Moolenaar                "     ^       94
49597d62497SBram Moolenaar                " Iterate through all numeric specifications and convert those
49697d62497SBram Moolenaar                " to their ascii equivalent ensuring the character is printable.
49797d62497SBram Moolenaar                " If so, add it to the list.
49897d62497SBram Moolenaar                let accepted_chars = ''
49997d62497SBram Moolenaar                for item in split(&iskeyword, ',')
50097d62497SBram Moolenaar                    if item =~ '-'
50197d62497SBram Moolenaar                        " This is a character range (ie 47-58),
50297d62497SBram Moolenaar                        " cycle through each character within the range
50397d62497SBram Moolenaar                        let [b:start, b:end] = split(item, '-')
50497d62497SBram Moolenaar                        for range_item in range( b:start, b:end )
50597d62497SBram Moolenaar                            if range_item <= 127 || g:omni_syntax_use_single_byte == 0
50697d62497SBram Moolenaar                                if nr2char(range_item) =~ '\p'
50797d62497SBram Moolenaar                                    let accepted_chars = accepted_chars . nr2char(range_item)
50897d62497SBram Moolenaar                                endif
50997d62497SBram Moolenaar                            endif
51097d62497SBram Moolenaar                        endfor
51197d62497SBram Moolenaar                    elseif item =~ '^\d\+$'
51297d62497SBram Moolenaar                        " Only numeric, translate to a character
51397d62497SBram Moolenaar                        if item < 127 || g:omni_syntax_use_single_byte == 0
51497d62497SBram Moolenaar                            if nr2char(item) =~ '\p'
51597d62497SBram Moolenaar                                let accepted_chars = accepted_chars . nr2char(item)
51697d62497SBram Moolenaar                            endif
51797d62497SBram Moolenaar                        endif
51897d62497SBram Moolenaar                    else
51997d62497SBram Moolenaar                        if char2nr(item) < 127 || g:omni_syntax_use_single_byte == 0
52097d62497SBram Moolenaar                            if item =~ '\p'
52197d62497SBram Moolenaar                                let accepted_chars = accepted_chars . item
52297d62497SBram Moolenaar                            endif
52397d62497SBram Moolenaar                        endif
52497d62497SBram Moolenaar                    endif
52597d62497SBram Moolenaar                endfor
52697d62497SBram Moolenaar                " Escape special regex characters
527*34feacbcSBram Moolenaar                " Looks like the wrong chars are escaped.  In a collection,
528*34feacbcSBram Moolenaar                "      :h /[]
529*34feacbcSBram Moolenaar                "      only `]', `\', `-' and `^' are special:
530*34feacbcSBram Moolenaar                " let accepted_chars = escape(accepted_chars, '\\/.*$^~[]' )
531*34feacbcSBram Moolenaar                let accepted_chars = escape(accepted_chars, ']\-^' )
53297d62497SBram Moolenaar                " Remove all characters that are not acceptable
53397d62497SBram Moolenaar                let syn_list = substitute( syn_list, '[^A-Za-z'.accepted_chars.']', ' ', 'g' )
53497d62497SBram Moolenaar            else
5359964e468SBram Moolenaar                let accept_chars = ','.&iskeyword.','
5369964e468SBram Moolenaar                " Remove all character ranges
5373577c6faSBram Moolenaar                " let accept_chars = substitute(accept_chars, ',[^,]\+-[^,]\+,', ',', 'g')
5383577c6faSBram Moolenaar                let accept_chars = substitute(accept_chars, ',\@<=[^,]\+-[^,]\+,', '', 'g')
5399964e468SBram Moolenaar                " Remove all numeric specifications
5403577c6faSBram Moolenaar                " let accept_chars = substitute(accept_chars, ',\d\{-},', ',', 'g')
5413577c6faSBram Moolenaar                let accept_chars = substitute(accept_chars, ',\@<=\d\{-},', '', 'g')
5429964e468SBram Moolenaar                " Remove all commas
5439964e468SBram Moolenaar                let accept_chars = substitute(accept_chars, ',', '', 'g')
5449964e468SBram Moolenaar                " Escape special regex characters
545*34feacbcSBram Moolenaar                " Looks like the wrong chars are escaped.  In a collection,
546*34feacbcSBram Moolenaar                "      :h /[]
547*34feacbcSBram Moolenaar                "      only `]', `\', `-' and `^' are special:
548*34feacbcSBram Moolenaar                " let accept_chars = escape(accept_chars, '\\/.*$^~[]' )
549*34feacbcSBram Moolenaar                let accept_chars = escape(accept_chars, ']\-^' )
5509964e468SBram Moolenaar                " Remove all characters that are not acceptable
5519964e468SBram Moolenaar                let syn_list = substitute( syn_list, '[^0-9A-Za-z_'.accept_chars.']', ' ', 'g' )
5529964e468SBram Moolenaar            endif
55397d62497SBram Moolenaar        endif
5549964e468SBram Moolenaar
5559964e468SBram Moolenaar        if b:omni_syntax_minimum_length > 0
5569964e468SBram Moolenaar            " If the user specified a minimum length, enforce it
5579964e468SBram Moolenaar            let syn_list = substitute(' '.syn_list.' ', ' \S\{,'.b:omni_syntax_minimum_length.'}\ze ', ' ', 'g')
5589964e468SBram Moolenaar        endif
5599964e468SBram Moolenaar    else
5604770d09aSBram Moolenaar        let syn_list = ''
5614770d09aSBram Moolenaar    endif
5624770d09aSBram Moolenaar
5634770d09aSBram Moolenaar    return syn_list
5644770d09aSBram Moolenaarendfunction
56597d62497SBram Moolenaar
56697d62497SBram Moolenaarfunction! OmniSyntaxShowChars(spec)
56797d62497SBram Moolenaar  let result = []
56897d62497SBram Moolenaar  for item in split(a:spec, ',')
56997d62497SBram Moolenaar    if len(item) > 1
57097d62497SBram Moolenaar      if item == '@-@'
57197d62497SBram Moolenaar        call add(result, char2nr(item))
57297d62497SBram Moolenaar      else
57397d62497SBram Moolenaar        call extend(result, call('range', split(item, '-')))
57497d62497SBram Moolenaar      endif
57597d62497SBram Moolenaar    else
57697d62497SBram Moolenaar      if item == '@'  " assume this is [A-Za-z]
57797d62497SBram Moolenaar        for [c1, c2] in [['A', 'Z'], ['a', 'z']]
57897d62497SBram Moolenaar          call extend(result, range(char2nr(c1), char2nr(c2)))
57997d62497SBram Moolenaar        endfor
58097d62497SBram Moolenaar      else
58197d62497SBram Moolenaar        call add(result, char2nr(item))
58297d62497SBram Moolenaar      endif
58397d62497SBram Moolenaar    endif
58497d62497SBram Moolenaar  endfor
58597d62497SBram Moolenaar  return join(map(result, 'nr2char(v:val)'), ', ')
58697d62497SBram Moolenaarendfunction
58797d62497SBram Moolenaarlet &cpo = s:cpo_save
58897d62497SBram Moolenaarunlet s:cpo_save
589