blob: c8e258d0530e9ac06a1091db2b83a1b2f245e08c [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 Moolenaardcca87b2005-09-10 19:24:59 +00004" Last Change: 2005 Sep 10
Bram Moolenaare344bea2005-09-01 20:46:49 +00005
Bram Moolenaara4a08382005-09-09 19:52:02 +00006
7" This function is used for the 'occultfunc' option.
Bram Moolenaare344bea2005-09-01 20:46:49 +00008function! ccomplete#Complete(findstart, base)
9 if a:findstart
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +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
13 while start > 0
14 if line[start - 1] =~ '\w\|\.'
15 let start -= 1
16 elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>'
17 let start -= 2
18 else
19 break
20 endif
21 endwhile
22 return start
23 endif
24
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000025 " Return list of matches.
26
27 " Split item in words, keep empty word after "." or "->".
28 " "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc.
29 let items = split(a:base, '\.\|->', 1)
30 if len(items) <= 1
Bram Moolenaare344bea2005-09-01 20:46:49 +000031 " Only one part, no "." or "->": complete from tags file.
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000032 " When local completion is wanted CTRL-N would have been used.
33 return map(taglist('^' . a:base), 'v:val["name"]')
Bram Moolenaare344bea2005-09-01 20:46:49 +000034 endif
Bram Moolenaardd2436f2005-09-05 22:14:46 +000035
Bram Moolenaara4a08382005-09-09 19:52:02 +000036 " Find the variable items[0].
37 " 1. in current function (like with "gd")
38 " 2. in tags file(s) (like with ":tag")
39 " 3. in current file (like with "gD")
40 let res = []
41 if searchdecl(items[0]) == 0
Bram Moolenaardd2436f2005-09-05 22:14:46 +000042 " Found, now figure out the type.
43 " TODO: join previous line if it makes sense
44 let line = getline('.')
45 let col = col('.')
Bram Moolenaara4a08382005-09-09 19:52:02 +000046 let res = ccomplete#Nextitem(strpart(line, 0, col), items[1:])
47 endif
48
49 if len(res) == 0
50 " Find the variable in the tags file(s)
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000051 let diclist = taglist('^' . items[0] . '$')
52
53 let res = []
Bram Moolenaardd2436f2005-09-05 22:14:46 +000054 for i in range(len(diclist))
Bram Moolenaara4a08382005-09-09 19:52:02 +000055 " New ctags has the "typename" field.
56 if has_key(diclist[i], 'typename')
57 call extend(res, ccomplete#StructMembers(diclist[i]['typename'], items[1:]))
58 endif
59
60 " For a variable use the command, which must be a search pattern that
61 " shows the declaration of the variable.
Bram Moolenaardd2436f2005-09-05 22:14:46 +000062 if diclist[i]['kind'] == 'v'
63 let line = diclist[i]['cmd']
64 if line[0] == '/' && line[1] == '^'
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000065 let col = match(line, items[0])
Bram Moolenaara4a08382005-09-09 19:52:02 +000066 call extend(res, ccomplete#Nextitem(strpart(line, 2, col - 2), items[1:])
Bram Moolenaardd2436f2005-09-05 22:14:46 +000067 endif
Bram Moolenaardd2436f2005-09-05 22:14:46 +000068 endif
69 endfor
70 endif
71
Bram Moolenaara4a08382005-09-09 19:52:02 +000072 if len(res) == 0 && searchdecl(items[0], 1) == 0
73 " Found, now figure out the type.
74 " TODO: join previous line if it makes sense
75 let line = getline('.')
76 let col = col('.')
77 let res = ccomplete#Nextitem(strpart(line, 0, col), items[1:])
78 endif
79
80 " The basetext is up to the last "." or "->" and won't be changed. The
81 " matching members are concatenated to this.
82 let basetext = matchstr(a:base, '.*\(\.\|->\)')
83 return map(res, 'basetext . v:val')
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000084endfunc
Bram Moolenaardd2436f2005-09-05 22:14:46 +000085
Bram Moolenaara4a08382005-09-09 19:52:02 +000086" Find composing type in "lead" and match items[0] with it.
87" Repeat this recursively for items[1], if it's there.
88" Return the list of matches.
89function! ccomplete#Nextitem(lead, items)
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000090
91 " Use the text up to the variable name and split it in tokens.
92 let tokens = split(a:lead, '\s\+\|\<')
93
94 " Try to recognize the type of the variable. This is rough guessing...
Bram Moolenaara4a08382005-09-09 19:52:02 +000095 let res = []
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +000096 for tidx in range(len(tokens))
97
Bram Moolenaara4a08382005-09-09 19:52:02 +000098 " Recognize "struct foobar" and "union foobar".
99 if (tokens[tidx] == 'struct' || tokens[tidx] == 'union') && tidx + 1 < len(tokens)
100 let res = ccomplete#StructMembers(tokens[tidx] . ':' . tokens[tidx + 1], a:items)
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000101 break
102 endif
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000103
Bram Moolenaara4a08382005-09-09 19:52:02 +0000104 " TODO: add more reserved words
105 if index(['int', 'float', 'static', 'unsigned', 'extern'], tokens[tidx]) >= 0
106 continue
107 endif
108
109 " Use the tags file to find out if this is a typedef.
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000110 let diclist = taglist('^' . tokens[tidx] . '$')
111 for i in range(len(diclist))
Bram Moolenaara4a08382005-09-09 19:52:02 +0000112 " New ctags has the "typename" field.
113 if has_key(diclist[i], 'typename')
114 call extend(res, ccomplete#StructMembers(diclist[i]['typename'], a:items))
115 continue
116 endif
117
118 " For old ctags we only recognize "typedef struct foobar" in the tags
119 " file command.
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000120 let cmd = diclist[i]['cmd']
121 let ci = matchend(cmd, 'typedef\s\+struct\s\+')
122 if ci > 1
123 let name = matchstr(cmd, '\w*', ci)
Bram Moolenaara4a08382005-09-09 19:52:02 +0000124 call extend(res, ccomplete#StructMembers('struct:' . name, a:items))
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000125 endif
126 endfor
Bram Moolenaara4a08382005-09-09 19:52:02 +0000127 if len(res) > 0
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000128 break
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000129 endif
Bram Moolenaara4a08382005-09-09 19:52:02 +0000130 endfor
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000131
Bram Moolenaara4a08382005-09-09 19:52:02 +0000132 return res
133endfunction
134
135
136" Return a list with resulting matches
137function! ccomplete#StructMembers(typename, items)
138 " Todo: What about local structures?
139 let fnames = join(map(tagfiles(), 'escape(v:val, " \\")'))
140 if fnames == ''
141 return [[], []]
142 endif
143
144 let typename = a:typename
145 let qflist = []
146 while 1
Bram Moolenaardcca87b2005-09-10 19:24:59 +0000147 exe 'silent! vimgrep /\t' . typename . '\(\t\|$\)/j ' . fnames
Bram Moolenaara4a08382005-09-09 19:52:02 +0000148 let qflist = getqflist()
149 if len(qflist) > 0 || match(typename, "::") < 0
150 break
151 endif
152 " No match for "struct:context::name", remove "context::" and try again.
153 let typename = substitute(typename, ':[^:]*::', ':', '')
154 endwhile
155
156 let members = []
157 let taglines = []
158 for l in qflist
159 let memb = matchstr(l['text'], '[^\t]*')
160 if memb =~ '^' . a:items[0]
161 call add(members, memb)
162 call add(taglines, l['text'])
163 endif
Bram Moolenaardd2436f2005-09-05 22:14:46 +0000164 endfor
165
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000166 if len(members) > 0
Bram Moolenaara4a08382005-09-09 19:52:02 +0000167 " No further items, return the result.
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000168 if len(a:items) == 1
Bram Moolenaara4a08382005-09-09 19:52:02 +0000169 return members
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000170 endif
171
172 " More items following. For each of the possible members find the
173 " matching following members.
174 let res = []
175 for i in range(len(members))
176 let line = taglines[i]
Bram Moolenaara4a08382005-09-09 19:52:02 +0000177 let e = matchend(line, '\ttypename:')
178 if e > 0
179 " Use typename field
180 let name = matchstr(line, '[^\t]*', e)
181 call extend(res, ccomplete#StructMembers(name, a:items[1:]))
182 else
183 let s = match(line, '\t\zs/^')
184 if s > 0
185 let e = match(line, members[i], s)
186 if e > 0
187 call extend(res, ccomplete#Nextitem(strpart(line, s, e - s), a:items[1:]))
188 endif
Bram Moolenaarcaa0fcf2005-09-07 21:21:14 +0000189 endif
190 endif
191 endfor
192 return res
193 endif
194
195 " Failed to find anything.
196 return []
Bram Moolenaare344bea2005-09-01 20:46:49 +0000197endfunction