blob: 42e7240989b2f762c6952ce433a9026079b254ab [file] [log] [blame]
Bram Moolenaare344bea2005-09-01 20:46:49 +00001" Vim completion script
2" Language: C
3" Maintainer: Bram Moolenaar <Bram@vim.org>
Bram Moolenaareb94e552006-03-11 21:35:11 +00004" Last Change: 2006 Mar 11
Bram Moolenaare344bea2005-09-01 20:46:49 +00005
Bram Moolenaara4a08382005-09-09 19:52:02 +00006
Bram Moolenaarf75a9632005-09-13 21:20:47 +00007" This function is used for the 'omnifunc' option.
Bram Moolenaare344bea2005-09-01 20:46:49 +00008function! ccomplete#Complete(findstart, base)
9 if a:findstart
Bram Moolenaar0e5bd962006-02-04 00:59:56 +000010 " Locate the start of the item, including ".", "->" and "[...]".
Bram Moolenaare344bea2005-09-01 20:46:49 +000011 let line = getline('.')
12 let start = col('.') - 1
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000013 let lastword = -1
Bram Moolenaare344bea2005-09-01 20:46:49 +000014 while start > 0
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000015 if line[start - 1] =~ '\w'
16 let start -= 1
17 elseif line[start - 1] =~ '\.'
18 if lastword == -1
19 let lastword = start
20 endif
Bram Moolenaare344bea2005-09-01 20:46:49 +000021 let start -= 1
22 elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>'
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000023 if lastword == -1
24 let lastword = start
25 endif
Bram Moolenaare344bea2005-09-01 20:46:49 +000026 let start -= 2
Bram Moolenaar0e5bd962006-02-04 00:59:56 +000027 elseif line[start - 1] == ']'
28 " Skip over [...].
29 let n = 0
30 let start -= 1
31 while start > 0
32 let start -= 1
33 if line[start] == '['
34 if n == 0
35 break
36 endif
37 let n -= 1
38 elseif line[start] == ']' " nested []
39 let n += 1
40 endif
41 endwhile
Bram Moolenaare344bea2005-09-01 20:46:49 +000042 else
43 break
44 endif
45 endwhile
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000046
47 " Return the column of the last word, which is going to be changed.
48 " Remember the text that comes before it in s:prepended.
49 if lastword == -1
50 let s:prepended = ''
51 return start
52 endif
53 let s:prepended = strpart(line, start, lastword - start)
54 return lastword
Bram Moolenaare344bea2005-09-01 20:46:49 +000055 endif
56
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000057 " Return list of matches.
58
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000059 let base = s:prepended . a:base
60
Bram Moolenaar0e5bd962006-02-04 00:59:56 +000061 " Don't do anything for an empty base, would result in all the tags in the
62 " tags file.
63 if base == ''
64 return []
65 endif
66
Bram Moolenaar1056d982006-03-09 22:37:52 +000067 " init cache for vimgrep to empty
68 let s:grepCache = {}
69
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000070 " Split item in words, keep empty word after "." or "->".
71 " "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc.
Bram Moolenaar0e5bd962006-02-04 00:59:56 +000072 " We can't use split, because we need to skip nested [...].
73 let items = []
74 let s = 0
75 while 1
76 let e = match(base, '\.\|->\|\[', s)
77 if e < 0
78 if s == 0 || base[s - 1] != ']'
79 call add(items, strpart(base, s))
80 endif
81 break
Bram Moolenaard5cdbeb2005-10-10 20:59:28 +000082 endif
Bram Moolenaar0e5bd962006-02-04 00:59:56 +000083 if s == 0 || base[s - 1] != ']'
84 call add(items, strpart(base, s, e - s))
85 endif
86 if base[e] == '.'
87 let s = e + 1 " skip over '.'
88 elseif base[e] == '-'
89 let s = e + 2 " skip over '->'
90 else
91 " Skip over [...].
92 let n = 0
93 let s = e
94 let e += 1
95 while e < len(base)
96 if base[e] == ']'
97 if n == 0
98 break
99 endif
100 let n -= 1
101 elseif base[e] == '[' " nested [...]
102 let n += 1
103 endif
104 let e += 1
105 endwhile
106 let e += 1
107 call add(items, strpart(base, s, e - s))
108 let s = e
109 endif
110 endwhile
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000111
Bram Moolenaara4a08382005-09-09 19:52:02 +0000112 " Find the variable items[0].
113 " 1. in current function (like with "gd")
114 " 2. in tags file(s) (like with ":tag")
115 " 3. in current file (like with "gD")
116 let res = []
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000117 if searchdecl(items[0], 0, 1) == 0
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000118 " Found, now figure out the type.
119 " TODO: join previous line if it makes sense
120 let line = getline('.')
121 let col = col('.')
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000122 if len(items) == 1
123 " Completing one word and it's a local variable: May add '[', '.' or
124 " '->'.
125 let match = items[0]
Bram Moolenaareb94e552006-03-11 21:35:11 +0000126 let kind = 'v'
127 if match(line, '\<' . match . '\s*\[') > 0
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000128 let match .= '['
129 else
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000130 let res = s:Nextitem(strpart(line, 0, col), [''], 0, 1)
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000131 if len(res) > 0
132 " There are members, thus add "." or "->".
133 if match(line, '\*[ \t(]*' . match . '\>') > 0
134 let match .= '->'
135 else
136 let match .= '.'
137 endif
138 endif
139 endif
Bram Moolenaareb94e552006-03-11 21:35:11 +0000140 let res = [{'match': match, 'tagline' : '', 'kind' : kind, 'info' : line}]
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000141 else
142 " Completing "var.", "var.something", etc.
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000143 let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1)
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000144 endif
145 endif
146
147 if len(items) == 1
148 " Only one part, no "." or "->": complete from tags file.
Bram Moolenaareb94e552006-03-11 21:35:11 +0000149 let tags = taglist('^' . base)
150
151 " Remove members, these can't appear without something in front.
152 call filter(tags, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1')
153
154 " Remove static matches in other files.
155 call filter(tags, '!has_key(v:val, "static") || !v:val["static"] || bufnr("%") == bufnr(v:val["filename"])')
156
157 call extend(res, map(tags, 's:Tag2item(v:val)'))
Bram Moolenaara4a08382005-09-09 19:52:02 +0000158 endif
159
160 if len(res) == 0
161 " Find the variable in the tags file(s)
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000162 let diclist = taglist('^' . items[0] . '$')
163
Bram Moolenaareb94e552006-03-11 21:35:11 +0000164 " Remove members, these can't appear without something in front.
165 call filter(diclist, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1')
166
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000167 let res = []
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000168 for i in range(len(diclist))
Bram Moolenaara4a08382005-09-09 19:52:02 +0000169 " New ctags has the "typename" field.
170 if has_key(diclist[i], 'typename')
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000171 call extend(res, s:StructMembers(diclist[i]['typename'], items[1:], 1))
Bram Moolenaara4a08382005-09-09 19:52:02 +0000172 endif
173
174 " For a variable use the command, which must be a search pattern that
175 " shows the declaration of the variable.
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000176 if diclist[i]['kind'] == 'v'
177 let line = diclist[i]['cmd']
178 if line[0] == '/' && line[1] == '^'
Bram Moolenaare3226be2005-12-18 22:10:00 +0000179 let col = match(line, '\<' . items[0] . '\>')
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000180 call extend(res, s:Nextitem(strpart(line, 2, col - 2), items[1:], 0, 1))
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000181 endif
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000182 endif
183 endfor
184 endif
185
Bram Moolenaara4a08382005-09-09 19:52:02 +0000186 if len(res) == 0 && searchdecl(items[0], 1) == 0
187 " Found, now figure out the type.
188 " TODO: join previous line if it makes sense
189 let line = getline('.')
190 let col = col('.')
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000191 let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1)
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000192 endif
193
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000194 " If the last item(s) are [...] they need to be added to the matches.
195 let last = len(items) - 1
196 let brackets = ''
197 while last >= 0
198 if items[last][0] != '['
199 break
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000200 endif
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000201 let brackets = items[last] . brackets
202 let last -= 1
203 endwhile
Bram Moolenaara4a08382005-09-09 19:52:02 +0000204
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000205 return map(res, 's:Tagline2item(v:val, brackets)')
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000206endfunc
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000207
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000208function! s:GetAddition(line, match, memarg, bracket)
209 " Guess if the item is an array.
210 if a:bracket && match(a:line, a:match . '\s*\[') > 0
211 return '['
212 endif
213
214 " Check if the item has members.
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000215 if len(s:SearchMembers(a:memarg, [''], 0)) > 0
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000216 " If there is a '*' before the name use "->".
217 if match(a:line, '\*[ \t(]*' . a:match . '\>') > 0
218 return '->'
219 else
220 return '.'
Bram Moolenaar280f1262006-01-30 00:14:18 +0000221 endif
222 endif
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000223 return ''
224endfunction
225
226" Turn the tag info "val" into an item for completion.
227" "val" is is an item in the list returned by taglist().
228" If it is a variable we may add "." or "->". Don't do it for other types,
229" such as a typedef, by not including the info that s:GetAddition() uses.
230function! s:Tag2item(val)
Bram Moolenaareb94e552006-03-11 21:35:11 +0000231 let res = {'match': a:val['name']}
Bram Moolenaarf52c7252006-02-10 23:23:57 +0000232
Bram Moolenaareb94e552006-03-11 21:35:11 +0000233 let res['extra'] = s:Tagcmd2extra(a:val['cmd'], a:val['name'], a:val['filename'])
234
235 " Use the whole search command as the "info" entry.
236 let s = matchstr(a:val['cmd'], '/^\s*\zs.*\ze$/')
237 if s != ''
238 let res['info'] = substitute(s, '\\\(.\)', '\1', 'g')
239 endif
240
241 let res['tagline'] = ''
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000242 if has_key(a:val, "kind")
Bram Moolenaareb94e552006-03-11 21:35:11 +0000243 let kind = a:val['kind']
244 let res['kind'] = kind
245 if kind == 'v'
246 let res['tagline'] = "\t" . a:val['cmd']
247 let res['dict'] = a:val
248 elseif kind == 'f'
249 let res['match'] = a:val['name'] . '('
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000250 endif
251 endif
Bram Moolenaareb94e552006-03-11 21:35:11 +0000252
253 return res
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000254endfunction
255
256" Turn a match item "val" into an item for completion.
257" "val['match']" is the matching item.
258" "val['tagline']" is the tagline in which the last part was found.
259function! s:Tagline2item(val, brackets)
Bram Moolenaarf52c7252006-02-10 23:23:57 +0000260 let line = a:val['tagline']
Bram Moolenaareb94e552006-03-11 21:35:11 +0000261 let add = s:GetAddition(line, a:val['match'], [a:val], a:brackets == '')
262 let res = {'word': a:val['match'] . a:brackets . add }
263
264 if has_key(a:val, 'info')
265 " Use info from Tag2item().
266 let res['info'] = a:val['info']
267 else
268 " Use the whole search command as the "info" entry.
269 let s = matchstr(line, '\t/^\s*\zs.*\ze$/')
270 if s != ''
271 let res['info'] = substitute(s, '\\\(.\)', '\1', 'g')
272 endif
273 endif
274
275 if has_key(a:val, 'kind')
276 let res['kind'] = a:val['kind']
277 elseif add == '('
278 let res['kind'] = 'f'
279 else
280 let s = matchstr(line, '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
281 if s != ''
282 let res['kind'] = s
283 endif
284 endif
285
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000286 if has_key(a:val, 'extra')
Bram Moolenaareb94e552006-03-11 21:35:11 +0000287 let res['menu'] = a:val['extra']
288 return res
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000289 endif
Bram Moolenaarf52c7252006-02-10 23:23:57 +0000290
291 " Isolate the command after the tag and filename.
292 let s = matchstr(line, '[^\t]*\t[^\t]*\t\zs\(/^.*$/\|[^\t]*\)\ze\(;"\t\|\t\|$\)')
293 if s != ''
Bram Moolenaareb94e552006-03-11 21:35:11 +0000294 let res['menu'] = s:Tagcmd2extra(s, a:val['match'], matchstr(line, '[^\t]*\t\zs[^\t]*\ze\t'))
Bram Moolenaarf52c7252006-02-10 23:23:57 +0000295 endif
Bram Moolenaareb94e552006-03-11 21:35:11 +0000296 return res
Bram Moolenaar280f1262006-01-30 00:14:18 +0000297endfunction
298
Bram Moolenaarf52c7252006-02-10 23:23:57 +0000299" Turn a command from a tag line to something that is useful in the menu
300function! s:Tagcmd2extra(cmd, name, fname)
301 if a:cmd =~ '^/^'
302 " The command is a search command, useful to see what it is.
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000303 let x = matchstr(a:cmd, '^/^\s*\zs.*\ze$/')
304 let x = substitute(x, '\<' . a:name . '\>', '@@', '')
Bram Moolenaarf52c7252006-02-10 23:23:57 +0000305 let x = substitute(x, '\\\(.\)', '\1', 'g')
306 let x = x . ' - ' . a:fname
307 elseif a:cmd =~ '^\d*$'
308 " The command is a line number, the file name is more useful.
309 let x = a:fname . ' - ' . a:cmd
310 else
311 " Not recognized, use command and file name.
312 let x = a:cmd . ' - ' . a:fname
313 endif
314 return x
315endfunction
Bram Moolenaar280f1262006-01-30 00:14:18 +0000316
Bram Moolenaara4a08382005-09-09 19:52:02 +0000317" Find composing type in "lead" and match items[0] with it.
318" Repeat this recursively for items[1], if it's there.
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000319" When resolving typedefs "depth" is used to avoid infinite recursion.
Bram Moolenaara4a08382005-09-09 19:52:02 +0000320" Return the list of matches.
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000321function! s:Nextitem(lead, items, depth, all)
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000322
323 " Use the text up to the variable name and split it in tokens.
324 let tokens = split(a:lead, '\s\+\|\<')
325
326 " Try to recognize the type of the variable. This is rough guessing...
Bram Moolenaara4a08382005-09-09 19:52:02 +0000327 let res = []
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000328 for tidx in range(len(tokens))
329
Bram Moolenaar1056d982006-03-09 22:37:52 +0000330 " Skip tokens starting with a non-ID character.
331 if tokens[tidx] !~ '^\h'
332 continue
333 endif
334
Bram Moolenaara4a08382005-09-09 19:52:02 +0000335 " Recognize "struct foobar" and "union foobar".
336 if (tokens[tidx] == 'struct' || tokens[tidx] == 'union') && tidx + 1 < len(tokens)
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000337 let res = s:StructMembers(tokens[tidx] . ':' . tokens[tidx + 1], a:items, a:all)
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000338 break
339 endif
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000340
Bram Moolenaara4a08382005-09-09 19:52:02 +0000341 " TODO: add more reserved words
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000342 if index(['int', 'short', 'char', 'float', 'double', 'static', 'unsigned', 'extern'], tokens[tidx]) >= 0
Bram Moolenaara4a08382005-09-09 19:52:02 +0000343 continue
344 endif
345
346 " Use the tags file to find out if this is a typedef.
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000347 let diclist = taglist('^' . tokens[tidx] . '$')
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000348 for tagidx in range(len(diclist))
Bram Moolenaareb94e552006-03-11 21:35:11 +0000349 let item = diclist[tagidx]
350
Bram Moolenaara4a08382005-09-09 19:52:02 +0000351 " New ctags has the "typename" field.
Bram Moolenaareb94e552006-03-11 21:35:11 +0000352 if has_key(item, 'typename')
353 call extend(res, s:StructMembers(item['typename'], a:items, a:all))
Bram Moolenaara4a08382005-09-09 19:52:02 +0000354 continue
355 endif
356
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000357 " Only handle typedefs here.
Bram Moolenaareb94e552006-03-11 21:35:11 +0000358 if item['kind'] != 't'
359 continue
360 endif
361
362 " Skip matches local to another file.
363 if has_key(item, 'static') && item['static'] && bufnr('%') != bufnr(item['filename'])
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000364 continue
365 endif
366
367 " For old ctags we recognize "typedef struct aaa" and
368 " "typedef union bbb" in the tags file command.
Bram Moolenaareb94e552006-03-11 21:35:11 +0000369 let cmd = item['cmd']
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000370 let ei = matchend(cmd, 'typedef\s\+')
371 if ei > 1
372 let cmdtokens = split(strpart(cmd, ei), '\s\+\|\<')
373 if len(cmdtokens) > 1
374 if cmdtokens[0] == 'struct' || cmdtokens[0] == 'union'
375 let name = ''
376 " Use the first identifier after the "struct" or "union"
377 for ti in range(len(cmdtokens) - 1)
378 if cmdtokens[ti] =~ '^\w'
379 let name = cmdtokens[ti]
380 break
381 endif
382 endfor
383 if name != ''
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000384 call extend(res, s:StructMembers(cmdtokens[0] . ':' . name, a:items, a:all))
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000385 endif
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000386 elseif a:depth < 10
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000387 " Could be "typedef other_T some_T".
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000388 call extend(res, s:Nextitem(cmdtokens[0], a:items, a:depth + 1, a:all))
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000389 endif
390 endif
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000391 endif
392 endfor
Bram Moolenaara4a08382005-09-09 19:52:02 +0000393 if len(res) > 0
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000394 break
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000395 endif
Bram Moolenaara4a08382005-09-09 19:52:02 +0000396 endfor
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000397
Bram Moolenaara4a08382005-09-09 19:52:02 +0000398 return res
399endfunction
400
401
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000402" Search for members of structure "typename" in tags files.
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000403" Return a list with resulting matches.
404" Each match is a dictionary with "match" and "tagline" entries.
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000405" When "all" is non-zero find all, otherwise just return 1 if there is any
406" member.
407function! s:StructMembers(typename, items, all)
Bram Moolenaara4a08382005-09-09 19:52:02 +0000408 " Todo: What about local structures?
409 let fnames = join(map(tagfiles(), 'escape(v:val, " \\")'))
410 if fnames == ''
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000411 return []
Bram Moolenaara4a08382005-09-09 19:52:02 +0000412 endif
413
414 let typename = a:typename
415 let qflist = []
Bram Moolenaar1056d982006-03-09 22:37:52 +0000416 let cached = 0
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000417 if a:all == 0
418 let n = '1' " stop at first found match
Bram Moolenaar1056d982006-03-09 22:37:52 +0000419 if has_key(s:grepCache, a:typename)
420 let qflist = s:grepCache[a:typename]
421 let cached = 1
422 endif
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000423 else
424 let n = ''
425 endif
Bram Moolenaar1056d982006-03-09 22:37:52 +0000426 if !cached
427 while 1
428 exe 'silent! ' . n . 'vimgrep /\t' . typename . '\(\t\|$\)/j ' . fnames
429
430 let qflist = getqflist()
431 if len(qflist) > 0 || match(typename, "::") < 0
432 break
433 endif
434 " No match for "struct:context::name", remove "context::" and try again.
435 let typename = substitute(typename, ':[^:]*::', ':', '')
436 endwhile
437
438 if a:all == 0
439 " Store the result to be able to use it again later.
440 let s:grepCache[a:typename] = qflist
Bram Moolenaara4a08382005-09-09 19:52:02 +0000441 endif
Bram Moolenaar1056d982006-03-09 22:37:52 +0000442 endif
Bram Moolenaara4a08382005-09-09 19:52:02 +0000443
Bram Moolenaareb94e552006-03-11 21:35:11 +0000444 " Put matching members in matches[].
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000445 let matches = []
Bram Moolenaara4a08382005-09-09 19:52:02 +0000446 for l in qflist
447 let memb = matchstr(l['text'], '[^\t]*')
448 if memb =~ '^' . a:items[0]
Bram Moolenaareb94e552006-03-11 21:35:11 +0000449 " Skip matches local to another file.
450 if match(l['text'], "\tfile:") < 0 || bufnr('%') == bufnr(matchstr(l['text'], '\t\zs[^\t]*'))
451 let item = {'match': memb, 'tagline': l['text']}
452
453 " Add the kind of item.
454 let s = matchstr(l['text'], '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
455 if s != ''
456 let item['kind'] = s
457 if s == 'f'
458 let item['match'] = memb . '('
459 endif
460 endif
461
462 call add(matches, item)
463 endif
Bram Moolenaara4a08382005-09-09 19:52:02 +0000464 endif
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000465 endfor
466
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000467 if len(matches) > 0
Bram Moolenaar0e5bd962006-02-04 00:59:56 +0000468 " Skip over [...] items
469 let idx = 1
470 while 1
471 if idx >= len(a:items)
472 return matches " No further items, return the result.
473 endif
474 if a:items[idx][0] != '['
475 break
476 endif
477 let idx += 1
478 endwhile
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000479
480 " More items following. For each of the possible members find the
481 " matching following members.
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000482 return s:SearchMembers(matches, a:items[idx :], a:all)
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000483 endif
484
485 " Failed to find anything.
486 return []
Bram Moolenaare344bea2005-09-01 20:46:49 +0000487endfunction
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000488
489" For matching members, find matches for following items.
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000490" When "all" is non-zero find all, otherwise just return 1 if there is any
491" member.
492function! s:SearchMembers(matches, items, all)
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000493 let res = []
494 for i in range(len(a:matches))
Bram Moolenaar280f1262006-01-30 00:14:18 +0000495 let typename = ''
496 if has_key(a:matches[i], 'dict')
Bram Moolenaar280f1262006-01-30 00:14:18 +0000497 if has_key(a:matches[i].dict, 'typename')
498 let typename = a:matches[i].dict['typename']
499 endif
500 let line = "\t" . a:matches[i].dict['cmd']
501 else
502 let line = a:matches[i]['tagline']
503 let e = matchend(line, '\ttypename:')
504 if e > 0
505 " Use typename field
506 let typename = matchstr(line, '[^\t]*', e)
507 endif
508 endif
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000509
Bram Moolenaar280f1262006-01-30 00:14:18 +0000510 if typename != ''
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000511 call extend(res, s:StructMembers(typename, a:items, a:all))
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000512 else
513 " Use the search command (the declaration itself).
514 let s = match(line, '\t\zs/^')
515 if s > 0
Bram Moolenaar280f1262006-01-30 00:14:18 +0000516 let e = match(line, '\<' . a:matches[i]['match'] . '\>', s)
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000517 if e > 0
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000518 call extend(res, s:Nextitem(strpart(line, s, e - s), a:items, 0, a:all))
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000519 endif
520 endif
521 endif
Bram Moolenaar1f35bf92006-03-07 22:38:47 +0000522 if a:all == 0 && len(res) > 0
523 break
524 endif
Bram Moolenaarf75a9632005-09-13 21:20:47 +0000525 endfor
526 return res
527endfunc