1" Vim completion script 2" Language: C 3" Maintainer: Bram Moolenaar <[email protected]> 4" Last Change: 2005 Sep 07 5 6function! ccomplete#Complete(findstart, base) 7 if a:findstart 8 " Locate the start of the item, including "." and "->". 9 let line = getline('.') 10 let start = col('.') - 1 11 while start > 0 12 if line[start - 1] =~ '\w\|\.' 13 let start -= 1 14 elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>' 15 let start -= 2 16 else 17 break 18 endif 19 endwhile 20 return start 21 endif 22 23 " Return list of matches. 24 25 " Split item in words, keep empty word after "." or "->". 26 " "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc. 27 let items = split(a:base, '\.\|->', 1) 28 if len(items) <= 1 29 " Only one part, no "." or "->": complete from tags file. 30 " When local completion is wanted CTRL-N would have been used. 31 return map(taglist('^' . a:base), 'v:val["name"]') 32 endif 33 34 let basetext = matchstr(a:base, '.*\(\.\|->\)') 35 36 " Find variable locally in current function, current file or tags file. 37 if searchdecl(items[0]) == 0 || searchdecl(items[0], 1) == 0 38 " Found, now figure out the type. 39 " TODO: join previous line if it makes sense 40 let line = getline('.') 41 let col = col('.') 42 let res = ccomplete#Nextitem(strpart(line, 0, col), items[1:], basetext) 43 else 44 " Find the variable in the tags file 45 let diclist = taglist('^' . items[0] . '$') 46 47 let res = [] 48 for i in range(len(diclist)) 49 " For now we only recognize a variable. 50 " The command in the tags file must be a search pattern that shows the 51 " declaration of the variable. 52 if diclist[i]['kind'] == 'v' 53 let line = diclist[i]['cmd'] 54 if line[0] == '/' && line[1] == '^' 55 let line = strpart(line, 2) " Remove /^ from the cmd 56 let col = match(line, items[0]) 57 call extend(res, ccomplete#Nextitem(strpart(line, 0, col), items[1:], basetext) 58 endif 59 endif 60 endfor 61 endif 62 63 return res 64endfunc 65 66function! ccomplete#Nextitem(lead, items, basetext) 67 68 " Use the text up to the variable name and split it in tokens. 69 let tokens = split(a:lead, '\s\+\|\<') 70 71 " Try to recognize the type of the variable. This is rough guessing... 72 let members = [] 73 let taglines = [] 74 for tidx in range(len(tokens)) 75 76 " Recognize 'struct foobar'. 77 if tokens[tidx] == 'struct' && tidx + 1 < len(tokens) 78 let [members, taglines] = ccomplete#StructMembers(tokens[tidx + 1], a:items[0]) 79 break 80 endif 81 82 " Recognize a typedef: 'foobar_t'. 83 let diclist = taglist('^' . tokens[tidx] . '$') 84 for i in range(len(diclist)) 85 " For now we only recognize "typedef struct foobar". 86 " The command in the tags file must be a search pattern that shows the 87 " typedef. 88 let cmd = diclist[i]['cmd'] 89 let ci = matchend(cmd, 'typedef\s\+struct\s\+') 90 if ci > 1 91 let name = matchstr(cmd, '\w*', ci) 92 let [m, l] = ccomplete#StructMembers(name, a:items[0]) 93 call extend(members, m) 94 call extend(taglines, l) 95 endif 96 endfor 97 if len(members) > 0 98 break 99 endif 100 101 endfor 102 103 if len(members) > 0 104 if len(a:items) == 1 105 return map(members, 'a:basetext . v:val') 106 endif 107 108 " More items following. For each of the possible members find the 109 " matching following members. 110 let res = [] 111 for i in range(len(members)) 112 let line = taglines[i] 113 let memb = members[i] 114 let s = match(line, '\t\zs/^') 115 if s > 0 116 let e = match(line, members[i], s) 117 if e > 0 118 call extend(res, ccomplete#Nextitem(strpart(line, s, e - s), a:items[1:], a:basetext)) 119 endif 120 endif 121 endfor 122 return res 123 endif 124 125 " Failed to find anything. 126 return [] 127endfunction 128 129 130" Return a list with two lists: 131" - a list of members of structure "name" starting with string "item". 132" - a list of the tag lines where the member is defined. 133function! ccomplete#StructMembers(name, item) 134 " Todo: Use all tags files; What about local structures? 135 exe 'vimgrep /\<struct:' . a:name . '\>/j tags' 136 137 let members = [] 138 let taglines = [] 139 for l in getqflist() 140 let memb = matchstr(l['text'], '[^\t]*') 141 if memb =~ '^' . a:item 142 call add(members, memb) 143 call add(taglines, l['text']) 144 endif 145 endfor 146 return [members, taglines] 147endfunction 148