11" Vim completion script
22" Language: C
33" Maintainer: Bram Moolenaar <Bram@vim.org>
4- " Last Change: 2005 Sep 10
4+ " Last Change: 2005 Sep 13
55
66
7- " This function is used for the 'occultfunc ' option.
7+ " This function is used for the 'omnifunc ' option.
88function ! ccomplete#Complete (findstart, base)
99 if a: findstart
1010 " Locate the start of the item, including "." and "->".
@@ -38,12 +38,12 @@ function! ccomplete#Complete(findstart, base)
3838 " 2. in tags file(s) (like with ":tag")
3939 " 3. in current file (like with "gD")
4040 let res = []
41- if searchdecl (items [0 ]) == 0
41+ if searchdecl (items [0 ], 0 , 1 ) == 0
4242 " Found, now figure out the type.
4343 " TODO: join previous line if it makes sense
4444 let line = getline (' .' )
4545 let col = col (' .' )
46- let res = ccomplete# Nextitem (strpart (line , 0 , col ), items [1 :])
46+ let res = s: Nextitem (strpart (line , 0 , col ), items [1 :])
4747 endif
4848
4949 if len (res ) == 0
@@ -54,7 +54,7 @@ function! ccomplete#Complete(findstart, base)
5454 for i in range (len (diclist))
5555 " New ctags has the "typename" field.
5656 if has_key (diclist[i ], ' typename' )
57- call extend (res , ccomplete# StructMembers (diclist[i ][' typename' ], items [1 :]))
57+ call extend (res , s: StructMembers (diclist[i ][' typename' ], items [1 :]))
5858 endif
5959
6060 " For a variable use the command, which must be a search pattern that
@@ -63,7 +63,7 @@ function! ccomplete#Complete(findstart, base)
6363 let line = diclist[i ][' cmd' ]
6464 if line [0 ] == ' /' && line [1 ] == ' ^'
6565 let col = match (line , items [0 ])
66- call extend (res , ccomplete# Nextitem (strpart (line , 2 , col - 2 ), items [1 :])
66+ call extend (res , s: Nextitem (strpart (line , 2 , col - 2 ), items [1 :]) )
6767 endif
6868 endif
6969 endfor
@@ -74,19 +74,30 @@ function! ccomplete#Complete(findstart, base)
7474 " TODO: join previous line if it makes sense
7575 let line = getline (' .' )
7676 let col = col (' .' )
77- let res = ccomplete#Nextitem (strpart (line , 0 , col ), items [1 :])
77+ let res = s: Nextitem (strpart (line , 0 , col ), items [1 :])
78+ endif
79+
80+ " If the one and only match was what's already there and it is a composite
81+ " type, add a "." or "->".
82+ if len (res ) == 1 && res [0 ][' match' ] == items [-1 ] && len (s: SearchMembers (res , [' ' ])) > 0
83+ " If there is a '*' before the name use "->".
84+ if match (res [0 ][' tagline' ], ' \*\s*' . res [0 ][' match' ]) > 0
85+ let res [0 ][' match' ] .= ' ->'
86+ else
87+ let res [0 ][' match' ] .= ' .'
88+ endif
7889 endif
7990
8091 " The basetext is up to the last "." or "->" and won't be changed. The
8192 " matching members are concatenated to this.
8293 let basetext = matchstr (a: base , ' .*\(\.\|->\)' )
83- return map (res , ' basetext . v:val' )
94+ return map (res , ' basetext . v:val["match"] ' )
8495endfunc
8596
8697" Find composing type in "lead" and match items[0] with it.
8798" Repeat this recursively for items[1], if it's there.
8899" Return the list of matches.
89- function ! ccomplete# Nextitem (lead, items )
100+ function ! s: Nextitem (lead, items )
90101
91102 " Use the text up to the variable name and split it in tokens.
92103 let tokens = split (a: lead , ' \s\+\|\<' )
@@ -97,7 +108,7 @@ function! ccomplete#Nextitem(lead, items)
97108
98109 " Recognize "struct foobar" and "union foobar".
99110 if (tokens[tidx] == ' struct' || tokens[tidx] == ' union' ) && tidx + 1 < len (tokens)
100- let res = ccomplete# StructMembers (tokens[tidx] . ' :' . tokens[tidx + 1 ], a: items )
111+ let res = s: StructMembers (tokens[tidx] . ' :' . tokens[tidx + 1 ], a: items )
101112 break
102113 endif
103114
@@ -108,20 +119,42 @@ function! ccomplete#Nextitem(lead, items)
108119
109120 " Use the tags file to find out if this is a typedef.
110121 let diclist = taglist (' ^' . tokens[tidx] . ' $' )
111- for i in range (len (diclist))
122+ for tagidx in range (len (diclist))
112123 " New ctags has the "typename" field.
113- if has_key (diclist[i ], ' typename' )
114- call extend (res , ccomplete#StructMembers (diclist[i ][' typename' ], a: items ))
124+ if has_key (diclist[tagidx], ' typename' )
125+ call extend (res , s: StructMembers (diclist[tagidx][' typename' ], a: items ))
126+ continue
127+ endif
128+
129+ " Only handle typedefs here.
130+ if diclist[tagidx][' kind' ] != ' t'
115131 continue
116132 endif
117133
118- " For old ctags we only recognize "typedef struct foobar" in the tags
119- " file command.
120- 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 )
124- call extend (res , ccomplete#StructMembers (' struct:' . name, a: items ))
134+ " For old ctags we recognize "typedef struct aaa" and
135+ " "typedef union bbb" in the tags file command.
136+ let cmd = diclist[tagidx][' cmd' ]
137+ let ei = matchend (cmd, ' typedef\s\+' )
138+ if ei > 1
139+ let cmdtokens = split (strpart (cmd, ei ), ' \s\+\|\<' )
140+ if len (cmdtokens) > 1
141+ if cmdtokens[0 ] == ' struct' || cmdtokens[0 ] == ' union'
142+ let name = ' '
143+ " Use the first identifier after the "struct" or "union"
144+ for ti in range (len (cmdtokens) - 1 )
145+ if cmdtokens[ti] = ~ ' ^\w'
146+ let name = cmdtokens[ti]
147+ break
148+ endif
149+ endfor
150+ if name != ' '
151+ call extend (res , s: StructMembers (cmdtokens[0 ] . ' :' . name, a: items ))
152+ endif
153+ else
154+ " Could be "typedef other_T some_T".
155+ call extend (res , s: Nextitem (cmdtokens[0 ], a: items ))
156+ endif
157+ endif
125158 endif
126159 endfor
127160 if len (res ) > 0
@@ -133,12 +166,13 @@ function! ccomplete#Nextitem(lead, items)
133166endfunction
134167
135168
136- " Return a list with resulting matches
137- function ! ccomplete#StructMembers (typename , items )
169+ " Return a list with resulting matches.
170+ " Each match is a dictionary with "match" and "tagline" entries.
171+ function ! s: StructMembers (typename , items )
138172 " Todo: What about local structures?
139173 let fnames = join (map (tagfiles (), ' escape(v:val, " \\")' ))
140174 if fnames == ' '
141- return [[], [] ]
175+ return []
142176 endif
143177
144178 let typename = a: typename
@@ -153,45 +187,49 @@ function! ccomplete#StructMembers(typename, items)
153187 let typename = substitute (typename , ' :[^:]*::' , ' :' , ' ' )
154188 endwhile
155189
156- let members = []
157- let taglines = []
190+ let matches = []
158191 for l in qflist
159192 let memb = matchstr (l [' text' ], ' [^\t]*' )
160193 if memb = ~ ' ^' . a: items [0 ]
161- call add (members, memb)
162- call add (taglines, l [' text' ])
194+ call add (matches, {' match' : memb, ' tagline' : l [' text' ]})
163195 endif
164196 endfor
165197
166- if len (members ) > 0
198+ if len (matches ) > 0
167199 " No further items, return the result.
168200 if len (a: items ) == 1
169- return members
201+ return matches
170202 endif
171203
172204 " More items following. For each of the possible members find the
173205 " matching following members.
174- let res = []
175- for i in range (len (members))
176- let line = taglines[i ]
177- 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
189- endif
190- endif
191- endfor
192- return res
206+ return s: SearchMembers (matches, a: items [1 :])
193207 endif
194208
195209 " Failed to find anything.
196210 return []
197211endfunction
212+
213+ " For matching members, find matches for following items.
214+ function ! s: SearchMembers (matches, items )
215+ let res = []
216+ for i in range (len (a: matches ))
217+ let line = a: matches [i ][' tagline' ]
218+ let e = matchend (line , ' \ttypename:' )
219+ if e > 0
220+ " Use typename field
221+ let name = matchstr (line , ' [^\t]*' , e )
222+ call extend (res , s: StructMembers (name, a: items ))
223+ else
224+ " Use the search command (the declaration itself).
225+ let s = match (line , ' \t\zs/^' )
226+ if s > 0
227+ let e = match (line , a: matches [i ][' match' ], s )
228+ if e > 0
229+ call extend (res , s: Nextitem (strpart (line , s , e - s ), a: items ))
230+ endif
231+ endif
232+ endif
233+ endfor
234+ return res
235+ endfunc
0 commit comments