Install vim73
[git/jnareb-git.git] / share / vim / vim73 / autoload / syntaxcomplete.vim
blob7b96bfd77ade2312aa5d568c495a2abfc52095d2
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:     7.0
5 " Last Change: 2010 Jul 29
6 " Usage:       For detailed help, ":help ft-syntax-omni" 
8 " History
10 " Version 7.0
11 "     Updated syntaxcomplete#OmniSyntaxList()
12 "         - Looking up the syntax groups defined from a syntax file
13 "           looked for only 1 format of {filetype}GroupName, but some 
14 "           syntax writers use this format as well:
15 "               {b:current_syntax}GroupName
16 "           OmniSyntaxList() will now check for both if the first
17 "           method does not find a match.
19 " Version 6.0
20 "     Added syntaxcomplete#OmniSyntaxList()
21 "         - Allows other plugins to use this for their own 
22 "           purposes.
23 "         - It will return a List of all syntax items for the
24 "           syntax group name passed in.  
25 "         - XPTemplate for SQL will use this function via the 
26 "           sqlcomplete plugin to populate a Choose box.
28 " Version 5.0
29 "     Updated SyntaxCSyntaxGroupItems()
30 "         - When processing a list of syntax groups, the final group
31 "           was missed in function SyntaxCSyntaxGroupItems.
33 " Set completion with CTRL-X CTRL-O to autoloaded function.
34 " This check is in place in case this script is
35 " sourced directly instead of using the autoload feature. 
36 if exists('+omnifunc')
37     " Do not set the option if already set since this
38     " results in an E117 warning.
39     if &omnifunc == ""
40         setlocal omnifunc=syntaxcomplete#Complete
41     endif
42 endif
44 if exists('g:loaded_syntax_completion')
45     finish 
46 endif
47 let g:loaded_syntax_completion = 70
49 " Set ignorecase to the ftplugin standard
50 " This is the default setting, but if you define a buffer local
51 " variable you can override this on a per filetype.
52 if !exists('g:omni_syntax_ignorecase')
53     let g:omni_syntax_ignorecase = &ignorecase
54 endif
56 " Indicates whether we should use the iskeyword option to determine
57 " how to split words.
58 " This is the default setting, but if you define a buffer local
59 " variable you can override this on a per filetype.
60 if !exists('g:omni_syntax_use_iskeyword')
61     let g:omni_syntax_use_iskeyword = 1
62 endif
64 " Only display items in the completion window that are at least
65 " this many characters in length.
66 " This is the default setting, but if you define a buffer local
67 " variable you can override this on a per filetype.
68 if !exists('g:omni_syntax_minimum_length')
69     let g:omni_syntax_minimum_length = 0
70 endif
72 " This script will build a completion list based on the syntax
73 " elements defined by the files in $VIMRUNTIME/syntax.
74 let s:syn_remove_words = 'match,matchgroup=,contains,'.
75             \ 'links to,start=,end=,nextgroup='
77 let s:cache_name = []
78 let s:cache_list = []
79 let s:prepended  = ''
81 " This function is used for the 'omnifunc' option.
82 function! syntaxcomplete#Complete(findstart, base)
84     " Only display items in the completion window that are at least
85     " this many characters in length
86     if !exists('b:omni_syntax_ignorecase')
87         if exists('g:omni_syntax_ignorecase')
88             let b:omni_syntax_ignorecase = g:omni_syntax_ignorecase
89         else
90             let b:omni_syntax_ignorecase = &ignorecase
91         endif
92     endif
94     if a:findstart
95         " Locate the start of the item, including "."
96         let line = getline('.')
97         let start = col('.') - 1
98         let lastword = -1
99         while start > 0
100             " if line[start - 1] =~ '\S'
101             "     let start -= 1
102             " elseif line[start - 1] =~ '\.'
103             if line[start - 1] =~ '\k'
104                 let start -= 1
105                 let lastword = a:findstart
106             else
107                 break
108             endif
109         endwhile
111         " Return the column of the last word, which is going to be changed.
112         " Remember the text that comes before it in s:prepended.
113         if lastword == -1
114             let s:prepended = ''
115             return start
116         endif
117         let s:prepended = strpart(line, start, (col('.') - 1) - start)
118         return start
119     endif
121     " let base = s:prepended . a:base
122     let base = s:prepended
124     let filetype = substitute(&filetype, '\.', '_', 'g')
125     let list_idx = index(s:cache_name, filetype, 0, &ignorecase)
126     if list_idx > -1
127         let compl_list = s:cache_list[list_idx]
128     else
129         let compl_list   = OmniSyntaxList()
130         let s:cache_name = add( s:cache_name,  filetype )
131         let s:cache_list = add( s:cache_list,  compl_list )
132     endif
134     " Return list of matches.
136     if base != ''
137         " let compstr    = join(compl_list, ' ')
138         " let expr       = (b:omni_syntax_ignorecase==0?'\C':'').'\<\%('.base.'\)\@!\w\+\s*'
139         " let compstr    = substitute(compstr, expr, '', 'g')
140         " let compl_list = split(compstr, '\s\+')
142         " Filter the list based on the first few characters the user
143         " entered
144         let expr = 'v:val '.(g:omni_syntax_ignorecase==1?'=~?':'=~#')." '^".escape(base, '\\/.*$^~[]').".*'"
145         let compl_list = filter(deepcopy(compl_list), expr)
146     endif
148     return compl_list
149 endfunc
151 function! syntaxcomplete#OmniSyntaxList(...)
152     if a:0 > 0
153         let parms = []
154         if 3 == type(a:1) 
155             let parms = a:1
156         elseif 1 == type(a:1)
157             let parms = split(a:1, ',')
158         endif
159         return OmniSyntaxList( parms )
160     else
161         return OmniSyntaxList()
162     endif
163 endfunc
165 function! OmniSyntaxList(...)
166     let list_parms = []
167     if a:0 > 0
168         if 3 == type(a:1) 
169             let list_parms = a:1
170         elseif 1 == type(a:1)
171             let list_parms = split(a:1, ',')
172         endif
173     endif
175     " Default to returning a dictionary, if use_dictionary is set to 0
176     " a list will be returned.
177     " let use_dictionary = 1
178     " if a:0 > 0 && a:1 != ''
179     "     let use_dictionary = a:1
180     " endif
182     " Only display items in the completion window that are at least
183     " this many characters in length
184     if !exists('b:omni_syntax_use_iskeyword')
185         if exists('g:omni_syntax_use_iskeyword')
186             let b:omni_syntax_use_iskeyword = g:omni_syntax_use_iskeyword
187         else
188             let b:omni_syntax_use_iskeyword = 1
189         endif
190     endif
192     " Only display items in the completion window that are at least
193     " this many characters in length
194     if !exists('b:omni_syntax_minimum_length')
195         if exists('g:omni_syntax_minimum_length')
196             let b:omni_syntax_minimum_length = g:omni_syntax_minimum_length
197         else
198             let b:omni_syntax_minimum_length = 0
199         endif
200     endif
202     let saveL = @l
203     let filetype = substitute(&filetype, '\.', '_', 'g')
204     
205     if empty(list_parms)
206         " Default the include group to include the requested syntax group
207         let syntax_group_include_{filetype} = ''
208         " Check if there are any overrides specified for this filetype
209         if exists('g:omni_syntax_group_include_'.filetype)
210             let syntax_group_include_{filetype} =
211                         \ substitute( g:omni_syntax_group_include_{filetype},'\s\+','','g') 
212             let list_parms = split(g:omni_syntax_group_include_{filetype}, ',')
213             if syntax_group_include_{filetype} =~ '\w'
214                 let syntax_group_include_{filetype} = 
215                             \ substitute( syntax_group_include_{filetype}, 
216                             \ '\s*,\s*', '\\|', 'g'
217                             \ )
218             endif
219         endif
220     else
221         " A specific list was provided, use it
222     endif
224     " Loop through all the syntax groupnames, and build a
225     " syntax file which contains these names.  This can 
226     " work generically for any filetype that does not already
227     " have a plugin defined.
228     " This ASSUMES the syntax groupname BEGINS with the name
229     " of the filetype.  From my casual viewing of the vim7\syntax 
230     " directory this is true for almost all syntax definitions.
231     " As an example, the SQL syntax groups have this pattern:
232     "     sqlType
233     "     sqlOperators
234     "     sqlKeyword ...
235     redir @l
236     silent! exec 'syntax list '.join(list_parms)
237     redir END
239     let syntax_full = "\n".@l
240     let @l = saveL
242     if syntax_full =~ 'E28' 
243                 \ || syntax_full =~ 'E411'
244                 \ || syntax_full =~ 'E415'
245                 \ || syntax_full =~ 'No Syntax items'
246         return []
247     endif
249     let filetype = substitute(&filetype, '\.', '_', 'g')
251     let list_exclude_groups = []
252     if a:0 > 0 
253         " Do nothing since we have specific a specific list of groups
254     else
255         " Default the exclude group to nothing
256         let syntax_group_exclude_{filetype} = ''
257         " Check if there are any overrides specified for this filetype
258         if exists('g:omni_syntax_group_exclude_'.filetype)
259             let syntax_group_exclude_{filetype} =
260                         \ substitute( g:omni_syntax_group_exclude_{filetype},'\s\+','','g') 
261             let list_exclude_groups = split(g:omni_syntax_group_exclude_{filetype}, ',')
262             if syntax_group_exclude_{filetype} =~ '\w' 
263                 let syntax_group_exclude_{filetype} = 
264                             \ substitute( syntax_group_exclude_{filetype}, 
265                             \ '\s*,\s*', '\\|', 'g'
266                             \ )
267             endif
268         endif
269     endif
271     " Sometimes filetypes can be composite names, like c.doxygen
272     " Loop through each individual part looking for the syntax
273     " items specific to each individual filetype.
274     let syn_list = ''
275     let ftindex  = 0
276     let ftindex  = match(&filetype, '\w\+', ftindex)
278     while ftindex > -1
279         let ft_part_name = matchstr( &filetype, '\w\+', ftindex )
281         " Syntax rules can contain items for more than just the current 
282         " filetype.  They can contain additional items added by the user
283         " via autocmds or their vimrc.
284         " Some syntax files can be combined (html, php, jsp).
285         " We want only items that begin with the filetype we are interested in.
286         let next_group_regex = '\n' .
287                     \ '\zs'.ft_part_name.'\w\+\ze'.
288                     \ '\s\+xxx\s\+' 
289         let index    = 0
290         let index    = match(syntax_full, next_group_regex, index)
292         if index == -1 && exists('b:current_syntax') && ft_part_name != b:current_syntax
293             " There appears to be two standards when writing syntax files.
294             " Either items begin as:
295             "     syn keyword {filetype}Keyword         values ...
296             "     let b:current_syntax = "sql"
297             "     let b:current_syntax = "sqlanywhere"
298             " Or
299             "     syn keyword {syntax_filename}Keyword  values ...
300             "     let b:current_syntax = "mysql"
301             " So, we will make the format of finding the syntax group names
302             " a bit more flexible and look for both if the first fails to 
303             " find a match.
304             let next_group_regex = '\n' .
305                         \ '\zs'.b:current_syntax.'\w\+\ze'.
306                         \ '\s\+xxx\s\+' 
307             let index    = 0
308             let index    = match(syntax_full, next_group_regex, index)
309         endif
311         while index > -1
312             let group_name = matchstr( syntax_full, '\w\+', index )
314             let get_syn_list = 1
315             for exclude_group_name in list_exclude_groups
316                 if '\<'.exclude_group_name.'\>' =~ '\<'.group_name.'\>'
317                     let get_syn_list = 0
318                 endif
319             endfor
320         
321             " This code is no longer needed in version 6.0 since we have
322             " augmented the syntax list command to only retrieve the syntax 
323             " groups we are interested in.
324             "
325             " if get_syn_list == 1
326             "     if syntax_group_include_{filetype} != ''
327             "         if '\<'.syntax_group_include_{filetype}.'\>' !~ '\<'.group_name.'\>'
328             "             let get_syn_list = 0
329             "         endif
330             "     endif
331             " endif
333             if get_syn_list == 1
334                 " Pass in the full syntax listing, plus the group name we 
335                 " are interested in.
336                 let extra_syn_list = s:SyntaxCSyntaxGroupItems(group_name, syntax_full)
337                 let syn_list = syn_list . extra_syn_list . "\n"
338             endif
340             let index = index + strlen(group_name)
341             let index = match(syntax_full, next_group_regex, index)
342         endwhile
344         let ftindex  = ftindex + len(ft_part_name)
345         let ftindex  = match( &filetype, '\w\+', ftindex )
346     endwhile
348     " Convert the string to a List and sort it.
349     let compl_list = sort(split(syn_list))
351     if &filetype == 'vim'
352         let short_compl_list = []
353         for i in range(len(compl_list))
354             if i == len(compl_list)-1
355                 let next = i
356             else
357                 let next = i + 1
358             endif
359             if  compl_list[next] !~ '^'.compl_list[i].'.$'
360                 let short_compl_list += [compl_list[i]]
361             endif
362         endfor
364         return short_compl_list
365     else
366         return compl_list
367     endif
368 endfunction
370 function! s:SyntaxCSyntaxGroupItems( group_name, syntax_full )
372     let syn_list = ""
374     " From the full syntax listing, strip out the portion for the
375     " request group.
376     " Query:
377     "     \n           - must begin with a newline
378     "     a:group_name - the group name we are interested in
379     "     \s\+xxx\s\+  - group names are always followed by xxx
380     "     \zs          - start the match
381     "     .\{-}        - everything ...
382     "     \ze          - end the match
383     "     \(           - start a group or 2 potential matches
384     "     \n\w         - at the first newline starting with a character
385     "     \|           - 2nd potential match
386     "     \%$          - matches end of the file or string
387     "     \)           - end a group
388     let syntax_group = matchstr(a:syntax_full, 
389                 \ "\n".a:group_name.'\s\+xxx\s\+\zs.\{-}\ze\(\n\w\|\%$\)'
390                 \ )
392     if syntax_group != ""
393         " let syn_list = substitute( @l, '^.*xxx\s*\%(contained\s*\)\?', "", '' )
394         " let syn_list = substitute( @l, '^.*xxx\s*', "", '' )
396         " We only want the words for the lines begining with
397         " containedin, but there could be other items.
398         
399         " Tried to remove all lines that do not begin with contained
400         " but this does not work in all cases since you can have
401         "    contained nextgroup=...
402         " So this will strip off the ending of lines with known
403         " keywords.
404         let syn_list = substitute( 
405                     \    syntax_group, '\<\('.
406                     \    substitute(
407                     \      escape(s:syn_remove_words, '\\/.*$^~[]')
408                     \      , ',', '\\|', 'g'
409                     \    ).
410                     \    '\).\{-}\%($\|'."\n".'\)'
411                     \    , "\n", 'g' 
412                     \  )
414         " Now strip off the newline + blank space + contained
415         let syn_list = substitute( 
416                     \    syn_list, '\%(^\|\n\)\@<=\s*\<\(contained\)'
417                     \    , "", 'g' 
418                     \ )
420         if b:omni_syntax_use_iskeyword == 0
421             " There are a number of items which have non-word characters in
422             " them, *'T_F1'*.  vim.vim is one such file.
423             " This will replace non-word characters with spaces.
424             let syn_list = substitute( syn_list, '[^0-9A-Za-z_ ]', ' ', 'g' )
425         else
426             let accept_chars = ','.&iskeyword.','
427             " Remove all character ranges
428             " let accept_chars = substitute(accept_chars, ',[^,]\+-[^,]\+,', ',', 'g')
429             let accept_chars = substitute(accept_chars, ',\@<=[^,]\+-[^,]\+,', '', 'g')
430             " Remove all numeric specifications
431             " let accept_chars = substitute(accept_chars, ',\d\{-},', ',', 'g')
432             let accept_chars = substitute(accept_chars, ',\@<=\d\{-},', '', 'g')
433             " Remove all commas
434             let accept_chars = substitute(accept_chars, ',', '', 'g')
435             " Escape special regex characters
436             let accept_chars = escape(accept_chars, '\\/.*$^~[]' )
437             " Remove all characters that are not acceptable
438             let syn_list = substitute( syn_list, '[^0-9A-Za-z_ '.accept_chars.']', ' ', 'g' )
439         endif
441         if b:omni_syntax_minimum_length > 0
442             " If the user specified a minimum length, enforce it
443             let syn_list = substitute(' '.syn_list.' ', ' \S\{,'.b:omni_syntax_minimum_length.'}\ze ', ' ', 'g')
444         endif
445     else
446         let syn_list = ''
447     endif
449     return syn_list
450 endfunction