blob: 396193d8b0203e004fb645f0479049e0d4a829dd [file] [log] [blame]
Bram Moolenaar4770d092006-01-12 23:22:24 +00001" Vim completion script
2" Language: All languages, uses existing syntax highlighting rules
Bram Moolenaar6dfc28b2010-02-11 14:19:15 +01003" Maintainer: David Fishburn <dfishburn dot vim at gmail dot com>
Bram Moolenaar4c295022021-05-02 17:19:11 +02004" Version: 15.0
5" Last Change: 2021 Apr 27
Bram Moolenaar34feacb2012-12-05 19:01:43 +01006" Usage: For detailed help, ":help ft-syntax-omni"
Bram Moolenaar4770d092006-01-12 23:22:24 +00007
Bram Moolenaar6dfc28b2010-02-11 14:19:15 +01008" History
Bram Moolenaar40af4e32010-07-29 22:33:18 +02009"
Bram Moolenaar4c295022021-05-02 17:19:11 +020010" Version 15.0
11" - SyntaxComplete ignored all buffer specific overrides, always used global
12" https://github.com/vim/vim/issues/8153
13"
Bram Moolenaar9faec4e2021-02-27 16:38:07 +010014" Version 14.0
15" - Fixed issue with single quotes and is_keyword
16" https://github.com/vim/vim/issues/7463
17"
Bram Moolenaarad3b3662013-05-17 18:14:19 +020018" 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"
Bram Moolenaar34feacb2012-12-05 19:01:43 +010034" Version 11.0
Bram Moolenaarad3b3662013-05-17 18:14:19 +020035" - Corrected which characters required escaping during
Bram Moolenaar34feacb2012-12-05 19:01:43 +010036" substitution calls.
37"
Bram Moolenaar97d62492012-11-15 21:28:22 +010038" Version 10.0
Bram Moolenaarad3b3662013-05-17 18:14:19 +020039" - Cycle through all the character ranges specified in the
Bram Moolenaar97d62492012-11-15 21:28:22 +010040" iskeyword option and build a list of valid word separators.
Bram Moolenaar34feacb2012-12-05 19:01:43 +010041" 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.
Bram Moolenaar97d62492012-11-15 21:28:22 +010044" This introduces a new option, since the character ranges
45" specified could be multibyte:
46" let g:omni_syntax_use_single_byte = 1
Bram Moolenaarad3b3662013-05-17 18:14:19 +020047" - This by default will only allow single byte ASCII
Bram Moolenaar97d62492012-11-15 21:28:22 +010048" characters to be added and an additional check to ensure
Bram Moolenaar4c295022021-05-02 17:19:11 +020049" the character is printable (see documentation for isprint).
Bram Moolenaar97d62492012-11-15 21:28:22 +010050"
51" Version 9.0
Bram Moolenaarad3b3662013-05-17 18:14:19 +020052" - Add the check for cpo.
Bram Moolenaar97d62492012-11-15 21:28:22 +010053"
Bram Moolenaarf1568ec2011-12-14 21:17:39 +010054" Version 8.0
Bram Moolenaarad3b3662013-05-17 18:14:19 +020055" - Updated SyntaxCSyntaxGroupItems()
Bram Moolenaarf1568ec2011-12-14 21:17:39 +010056" - Some additional syntax items were also allowed
57" on nextgroup= lines which were ignored by default.
58" Now these lines are processed independently.
59"
Bram Moolenaar40af4e32010-07-29 22:33:18 +020060" Version 7.0
Bram Moolenaarad3b3662013-05-17 18:14:19 +020061" - Updated syntaxcomplete#OmniSyntaxList()
Bram Moolenaar40af4e32010-07-29 22:33:18 +020062" - Looking up the syntax groups defined from a syntax file
Bram Moolenaar34feacb2012-12-05 19:01:43 +010063" looked for only 1 format of {filetype}GroupName, but some
Bram Moolenaar40af4e32010-07-29 22:33:18 +020064" syntax writers use this format as well:
65" {b:current_syntax}GroupName
Bram Moolenaarad3b3662013-05-17 18:14:19 +020066" - OmniSyntaxList() will now check for both if the first
Bram Moolenaar40af4e32010-07-29 22:33:18 +020067" method does not find a match.
68"
69" Version 6.0
Bram Moolenaarad3b3662013-05-17 18:14:19 +020070" - Added syntaxcomplete#OmniSyntaxList()
Bram Moolenaar34feacb2012-12-05 19:01:43 +010071" - Allows other plugins to use this for their own
Bram Moolenaar40af4e32010-07-29 22:33:18 +020072" purposes.
73" - It will return a List of all syntax items for the
Bram Moolenaar34feacb2012-12-05 19:01:43 +010074" syntax group name passed in.
75" - XPTemplate for SQL will use this function via the
Bram Moolenaar40af4e32010-07-29 22:33:18 +020076" sqlcomplete plugin to populate a Choose box.
77"
Bram Moolenaar6dfc28b2010-02-11 14:19:15 +010078" Version 5.0
Bram Moolenaarad3b3662013-05-17 18:14:19 +020079" - Updated SyntaxCSyntaxGroupItems()
Bram Moolenaar40af4e32010-07-29 22:33:18 +020080" - When processing a list of syntax groups, the final group
81" was missed in function SyntaxCSyntaxGroupItems.
Bram Moolenaar6dfc28b2010-02-11 14:19:15 +010082"
Bram Moolenaar4770d092006-01-12 23:22:24 +000083" Set completion with CTRL-X CTRL-O to autoloaded function.
Bram Moolenaarc15ef302006-03-19 22:11:16 +000084" This check is in place in case this script is
Bram Moolenaar34feacb2012-12-05 19:01:43 +010085" sourced directly instead of using the autoload feature.
Bram Moolenaarc06ac342006-03-02 22:43:39 +000086if exists('+omnifunc')
Bram Moolenaarc15ef302006-03-19 22:11:16 +000087 " 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
Bram Moolenaar4770d092006-01-12 23:22:24 +000092endif
93
94if exists('g:loaded_syntax_completion')
Bram Moolenaar34feacb2012-12-05 19:01:43 +010095 finish
Bram Moolenaar4770d092006-01-12 23:22:24 +000096endif
Bram Moolenaar4c295022021-05-02 17:19:11 +020097let g:loaded_syntax_completion = 150
Bram Moolenaar97d62492012-11-15 21:28:22 +010098
99" Turn on support for line continuations when creating the script
100let s:cpo_save = &cpo
101set cpo&vim
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000102
103" Set ignorecase to the ftplugin standard
Bram Moolenaar9964e462007-05-05 17:54:07 +0000104" This is the default setting, but if you define a buffer local
105" variable you can override this on a per filetype.
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000106if !exists('g:omni_syntax_ignorecase')
107 let g:omni_syntax_ignorecase = &ignorecase
108endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000109
Bram Moolenaar9964e462007-05-05 17:54:07 +0000110" 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
Bram Moolenaar97d62492012-11-15 21:28:22 +0100118" 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
Bram Moolenaar9964e462007-05-05 17:54:07 +0000130" 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
Bram Moolenaar4770d092006-01-12 23:22:24 +0000138" This script will build a completion list based on the syntax
139" elements defined by the files in $VIMRUNTIME/syntax.
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200140" let s:syn_remove_words = 'match,matchgroup=,contains,'.
141let s:syn_remove_words = 'matchgroup=,contains,'.
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100142 \ 'links to,start=,end='
143 " \ 'links to,start=,end=,nextgroup='
Bram Moolenaar4770d092006-01-12 23:22:24 +0000144
145let s:cache_name = []
146let s:cache_list = []
Bram Moolenaarc15ef302006-03-19 22:11:16 +0000147let s:prepended = ''
Bram Moolenaar4770d092006-01-12 23:22:24 +0000148
149" This function is used for the 'omnifunc' option.
150function! syntaxcomplete#Complete(findstart, base)
151
Bram Moolenaar4c295022021-05-02 17:19:11 +0200152 " 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
Bram Moolenaar9964e462007-05-05 17:54:07 +0000156 endif
157
Bram Moolenaar4770d092006-01-12 23:22:24 +0000158 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
Bram Moolenaar9964e462007-05-05 17:54:07 +0000164 " if line[start - 1] =~ '\S'
165 " let start -= 1
166 " elseif line[start - 1] =~ '\.'
167 if line[start - 1] =~ '\k'
Bram Moolenaar4770d092006-01-12 23:22:24 +0000168 let start -= 1
Bram Moolenaar9964e462007-05-05 17:54:07 +0000169 let lastword = a:findstart
Bram Moolenaar4770d092006-01-12 23:22:24 +0000170 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
Bram Moolenaar9964e462007-05-05 17:54:07 +0000181 let s:prepended = strpart(line, start, (col('.') - 1) - start)
182 return start
Bram Moolenaar4770d092006-01-12 23:22:24 +0000183 endif
184
Bram Moolenaar9964e462007-05-05 17:54:07 +0000185 " let base = s:prepended . a:base
Bram Moolenaar9faec4e2021-02-27 16:38:07 +0100186 let base = substitute(s:prepended, "'", "''", 'g')
Bram Moolenaar4770d092006-01-12 23:22:24 +0000187
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000188 let filetype = substitute(&filetype, '\.', '_', 'g')
189 let list_idx = index(s:cache_name, filetype, 0, &ignorecase)
Bram Moolenaar4770d092006-01-12 23:22:24 +0000190 if list_idx > -1
191 let compl_list = s:cache_list[list_idx]
192 else
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000193 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 )
Bram Moolenaar4770d092006-01-12 23:22:24 +0000196 endif
197
198 " Return list of matches.
199
Bram Moolenaar9964e462007-05-05 17:54:07 +0000200 if base != ''
201 " let compstr = join(compl_list, ' ')
Bram Moolenaar4c295022021-05-02 17:19:11 +0200202 " let expr = (l:omni_syntax_ignorecase==0?'\C':'').'\<\%('.base.'\)\@!\w\+\s*'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000203 " 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
Bram Moolenaar4c295022021-05-02 17:19:11 +0200208 let expr = 'v:val '.(l:omni_syntax_ignorecase==1?'=~?':'=~#')." '^".escape(base, '\\/.*$^~[]').".*'"
Bram Moolenaar9964e462007-05-05 17:54:07 +0000209 let compl_list = filter(deepcopy(compl_list), expr)
Bram Moolenaar4770d092006-01-12 23:22:24 +0000210 endif
211
212 return compl_list
213endfunc
214
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200215function! syntaxcomplete#OmniSyntaxList(...)
216 if a:0 > 0
217 let parms = []
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100218 if 3 == type(a:1)
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200219 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
Bram Moolenaar4c295022021-05-02 17:19:11 +0200229function! 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'] )
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200249function! OmniSyntaxList(...)
250 let list_parms = []
251 if a:0 > 0
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100252 if 3 == type(a:1)
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200253 let list_parms = a:1
254 elseif 1 == type(a:1)
255 let list_parms = split(a:1, ',')
256 endif
257 endif
258
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000259 " 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
Bram Moolenaar4770d092006-01-12 23:22:24 +0000266 let saveL = @l
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200267 let filetype = substitute(&filetype, '\.', '_', 'g')
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100268
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200269 if empty(list_parms)
Bram Moolenaar4c295022021-05-02 17:19:11 +0200270 " 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
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200278 " 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
Bram Moolenaar4c295022021-05-02 17:19:11 +0200281 if exists('l:omni_syntax_group_include_'.filetype)
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200282 let syntax_group_include_{filetype} =
Bram Moolenaar4c295022021-05-02 17:19:11 +0200283 \ substitute( l:omni_syntax_group_include_{filetype},'\s\+','','g')
284 let list_parms = split(l:omni_syntax_group_include_{filetype}, ',')
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200285 if syntax_group_include_{filetype} =~ '\w'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100286 let syntax_group_include_{filetype} =
287 \ substitute( syntax_group_include_{filetype},
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200288 \ '\s*,\s*', '\\|', 'g'
289 \ )
290 endif
291 endif
292 else
293 " A specific list was provided, use it
294 endif
295
Bram Moolenaar4770d092006-01-12 23:22:24 +0000296 " Loop through all the syntax groupnames, and build a
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100297 " syntax file which contains these names. This can
Bram Moolenaar4770d092006-01-12 23:22:24 +0000298 " work generically for any filetype that does not already
299 " have a plugin defined.
300 " This ASSUMES the syntax groupname BEGINS with the name
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100301 " of the filetype. From my casual viewing of the vim7\syntax
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200302 " 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 ...
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200307 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
Bram Moolenaar4770d092006-01-12 23:22:24 +0000320
Bram Moolenaarc06ac342006-03-02 22:43:39 +0000321 let syntax_full = "\n".@l
Bram Moolenaar4770d092006-01-12 23:22:24 +0000322 let @l = saveL
323
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100324 if syntax_full =~ 'E28'
Bram Moolenaarc06ac342006-03-02 22:43:39 +0000325 \ || syntax_full =~ 'E411'
326 \ || syntax_full =~ 'E415'
327 \ || syntax_full =~ 'No Syntax items'
328 return []
Bram Moolenaar4770d092006-01-12 23:22:24 +0000329 endif
330
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000331 let filetype = substitute(&filetype, '\.', '_', 'g')
332
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200333 let list_exclude_groups = []
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100334 if a:0 > 0
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200335 " 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} = ''
Bram Moolenaar4c295022021-05-02 17:19:11 +0200339
340 " Allow user to override per buffer
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200341 if exists('g:omni_syntax_group_exclude_'.filetype)
Bram Moolenaar4c295022021-05-02 17:19:11 +0200342 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)
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200350 let syntax_group_exclude_{filetype} =
Bram Moolenaar4c295022021-05-02 17:19:11 +0200351 \ substitute( l:omni_syntax_group_exclude_{filetype},'\s\+','','g')
352 let list_exclude_groups = split(l:omni_syntax_group_exclude_{filetype}, ',')
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100353 if syntax_group_exclude_{filetype} =~ '\w'
354 let syntax_group_exclude_{filetype} =
355 \ substitute( syntax_group_exclude_{filetype},
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200356 \ '\s*,\s*', '\\|', 'g'
357 \ )
358 endif
Bram Moolenaarc06ac342006-03-02 22:43:39 +0000359 endif
360 endif
361
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200362 if empty(list_parms)
363 let list_parms = [&filetype.'\w\+']
364 endif
365
Bram Moolenaar4770d092006-01-12 23:22:24 +0000366 let syn_list = ''
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200367 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)
Bram Moolenaar4770d092006-01-12 23:22:24 +0000374
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200375 " while ftindex > -1
376 " let ft_part_name = matchstr( syntax_full, '\w\+', ftindex )
Bram Moolenaar4770d092006-01-12 23:22:24 +0000377
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200378 " 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.
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200383 let next_group_regex = '\n' .
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200384 \ '\zs'.group_regex.'\ze'.
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100385 \ '\s\+xxx\s\+'
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200386 let index = match(syntax_full, next_group_regex, index)
Bram Moolenaar40af4e32010-07-29 22:33:18 +0200387
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200388 " 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)
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000407 endif
408
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200409 while index > -1
410 let group_name = matchstr( syntax_full, '\w\+', index )
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000411
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200412 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
Bram Moolenaar4770d092006-01-12 23:22:24 +0000523
Bram Moolenaarc06ac342006-03-02 22:43:39 +0000524 " 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
Bram Moolenaar4770d092006-01-12 23:22:24 +0000544endfunction
545
Bram Moolenaare2f98b92006-03-29 21:18:24 +0000546function! s:SyntaxCSyntaxGroupItems( group_name, syntax_full )
Bram Moolenaar4770d092006-01-12 23:22:24 +0000547
Bram Moolenaar4c295022021-05-02 17:19:11 +0200548 " 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
Bram Moolenaarc06ac342006-03-02 22:43:39 +0000572 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
Bram Moolenaar6dfc28b2010-02-11 14:19:15 +0100583 " \( - start a group or 2 potential matches
Bram Moolenaarc06ac342006-03-02 22:43:39 +0000584 " \n\w - at the first newline starting with a character
Bram Moolenaar6dfc28b2010-02-11 14:19:15 +0100585 " \| - 2nd potential match
586 " \%$ - matches end of the file or string
587 " \) - end a group
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100588 let syntax_group = matchstr(a:syntax_full,
Bram Moolenaar6dfc28b2010-02-11 14:19:15 +0100589 \ "\n".a:group_name.'\s\+xxx\s\+\zs.\{-}\ze\(\n\w\|\%$\)'
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000590 \ )
Bram Moolenaarc06ac342006-03-02 22:43:39 +0000591
592 if syntax_group != ""
Bram Moolenaar4770d092006-01-12 23:22:24 +0000593 " let syn_list = substitute( @l, '^.*xxx\s*\%(contained\s*\)\?', "", '' )
Bram Moolenaarc06ac342006-03-02 22:43:39 +0000594 " let syn_list = substitute( @l, '^.*xxx\s*', "", '' )
Bram Moolenaar4770d092006-01-12 23:22:24 +0000595
Bram Moolenaar9faec4e2021-02-27 16:38:07 +0100596 " We only want the words for the lines beginning with
Bram Moolenaar4770d092006-01-12 23:22:24 +0000597 " containedin, but there could be other items.
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100598
Bram Moolenaar4770d092006-01-12 23:22:24 +0000599 " 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.
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100604 let syn_list = substitute(
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000605 \ syntax_group, '\<\('.
606 \ substitute(
607 \ escape(s:syn_remove_words, '\\/.*$^~[]')
608 \ , ',', '\\|', 'g'
609 \ ).
610 \ '\).\{-}\%($\|'."\n".'\)'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100611 \ , "\n", 'g'
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000612 \ )
Bram Moolenaar4770d092006-01-12 23:22:24 +0000613
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200614 " 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' )
Bram Moolenaar56c860c2019-08-17 20:09:31 +0200645 " Do this by using the outer substitute() call to gather all
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200646 " 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
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100667 " Now strip off the newline + blank space + contained.
668 " Also include lines with nextgroup=@someName skip_key_words syntax_element
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200669 " \ syn_list, '\%(^\|\n\)\@<=\s*\<\(contained\|nextgroup=\)'
670 " \ syn_list, '\%(^\|\n\)\@<=\s*\<\(contained\|nextgroup=[@a-zA-Z,]*\)'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100671 let syn_list = substitute(
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200672 \ syn_list, '\<\(contained\|nextgroup=[@a-zA-Z,]*\)'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100673 \ , "", 'g'
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100674 \ )
675
676 " This can leave lines like this
677 " =@vimMenuList skipwhite onoremenu
678 " Strip the special option keywords first
679 " :h :syn-skipwhite*
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100680 let syn_list = substitute(
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100681 \ syn_list, '\<\(skipwhite\|skipnl\|skipempty\)\>'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100682 \ , "", 'g'
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100683 \ )
684
685 " Now remove the remainder of the nextgroup=@someName lines
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100686 let syn_list = substitute(
Bram Moolenaarf1568ec2011-12-14 21:17:39 +0100687 \ syn_list, '\%(^\|\n\)\@<=\s*\(@\w\+\)'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100688 \ , "", 'g'
Bram Moolenaar97e8f352006-05-06 21:40:45 +0000689 \ )
Bram Moolenaar4c295022021-05-02 17:19:11 +0200690
691 if l:omni_syntax_use_iskeyword == 0
Bram Moolenaar9964e462007-05-05 17:54:07 +0000692 " 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.
Bram Moolenaar4c295022021-05-02 17:19:11 +0200695 " 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
Bram Moolenaar9964e462007-05-05 17:54:07 +0000704 let syn_list = substitute( syn_list, '[^0-9A-Za-z_ ]', ' ', 'g' )
705 else
Bram Moolenaar4c295022021-05-02 17:19:11 +0200706 if l:omni_syntax_use_iskeyword_numeric == 1
Bram Moolenaar97d62492012-11-15 21:28:22 +0100707 " 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
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100712 " * 42
Bram Moolenaar97d62492012-11-15 21:28:22 +0100713 " + 43
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100714 " - 45
Bram Moolenaar97d62492012-11-15 21:28:22 +0100715 " ^ 94
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100716 " Iterate through all numeric specifications and convert those
Bram Moolenaar97d62492012-11-15 21:28:22 +0100717 " 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, ',')
Bram Moolenaarad3b3662013-05-17 18:14:19 +0200721 if item =~ '\d-\d'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100722 " This is a character range (ie 47-58),
Bram Moolenaar97d62492012-11-15 21:28:22 +0100723 " 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 )
Bram Moolenaar4c295022021-05-02 17:19:11 +0200726 if range_item <= 127 || l:omni_syntax_use_single_byte == 0
Bram Moolenaar97d62492012-11-15 21:28:22 +0100727 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
Bram Moolenaar4c295022021-05-02 17:19:11 +0200734 if item < 127 || l:omni_syntax_use_single_byte == 0
Bram Moolenaar97d62492012-11-15 21:28:22 +0100735 if nr2char(item) =~ '\p'
736 let accepted_chars = accepted_chars . nr2char(item)
737 endif
738 endif
739 else
Bram Moolenaar4c295022021-05-02 17:19:11 +0200740 if char2nr(item) < 127 || l:omni_syntax_use_single_byte == 0
Bram Moolenaar97d62492012-11-15 21:28:22 +0100741 if item =~ '\p'
742 let accepted_chars = accepted_chars . item
743 endif
744 endif
745 endif
746 endfor
747 " Escape special regex characters
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100748 " 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, ']\-^' )
Bram Moolenaar97d62492012-11-15 21:28:22 +0100753 " 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
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100766 " 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, ']\-^' )
Bram Moolenaar97d62492012-11-15 21:28:22 +0100771 " Remove all characters that are not acceptable
772 let syn_list = substitute( syn_list, '[^0-9A-Za-z_'.accept_chars.']', ' ', 'g' )
773 endif
Bram Moolenaar9964e462007-05-05 17:54:07 +0000774 endif
775
Bram Moolenaar4c295022021-05-02 17:19:11 +0200776 if l:omni_syntax_minimum_length > 0
Bram Moolenaar9964e462007-05-05 17:54:07 +0000777 " If the user specified a minimum length, enforce it
Bram Moolenaar4c295022021-05-02 17:19:11 +0200778 let syn_list = substitute(' '.syn_list.' ', ' \S\{,'.l:omni_syntax_minimum_length.'}\ze ', ' ', 'g')
Bram Moolenaar9964e462007-05-05 17:54:07 +0000779 endif
Bram Moolenaar4770d092006-01-12 23:22:24 +0000780 else
781 let syn_list = ''
782 endif
783
Bram Moolenaar4770d092006-01-12 23:22:24 +0000784 return syn_list
785endfunction
Bram Moolenaar97d62492012-11-15 21:28:22 +0100786
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
Bram Moolenaar4c295022021-05-02 17:19:11 +0200808
Bram Moolenaar97d62492012-11-15 21:28:22 +0100809let &cpo = s:cpo_save
810unlet s:cpo_save