vim-patch:89712b9: runtime(ccomplete): handle structs from tags file (#37956)

fixes: vim/vim#7292

89712b9f0e

Co-authored-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq
2026-02-19 08:18:55 +08:00
committed by GitHub
parent ac84a3f3b6
commit 6877fef972

View File

@@ -1,7 +1,7 @@
" Vim completion script
" Language: C
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2020 Nov 14
" Last Change: 2026 Feb 18
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
let s:cpo_save = &cpo
set cpo&vim
@@ -15,34 +15,34 @@ func ccomplete#Complete(findstart, base)
let lastword = -1
while start > 0
if line[start - 1] =~ '\w'
let start -= 1
let start -= 1
elseif line[start - 1] =~ '\.'
if lastword == -1
let lastword = start
endif
let start -= 1
if lastword == -1
let lastword = start
endif
let start -= 1
elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>'
if lastword == -1
let lastword = start
endif
let start -= 2
if lastword == -1
let lastword = start
endif
let start -= 2
elseif line[start - 1] == ']'
" Skip over [...].
let n = 0
let start -= 1
while start > 0
let start -= 1
if line[start] == '['
if n == 0
break
endif
let n -= 1
elseif line[start] == ']' " nested []
let n += 1
endif
endwhile
" Skip over [...].
let n = 0
let start -= 1
while start > 0
let start -= 1
if line[start] == '['
if n == 0
break
endif
let n -= 1
elseif line[start] == ']' " nested []
let n += 1
endif
endwhile
else
break
break
endif
endwhile
@@ -80,7 +80,7 @@ func ccomplete#Complete(findstart, base)
let e = match(base, '\.\|->\|\[', s)
if e < 0
if s == 0 || base[s - 1] != ']'
call add(items, strpart(base, s))
call add(items, strpart(base, s))
endif
break
endif
@@ -97,15 +97,15 @@ func ccomplete#Complete(findstart, base)
let s = e
let e += 1
while e < len(base)
if base[e] == ']'
if n == 0
break
endif
let n -= 1
elseif base[e] == '[' " nested [...]
let n += 1
endif
let e += 1
if base[e] == ']'
if n == 0
break
endif
let n -= 1
elseif base[e] == '[' " nested [...]
let n += 1
endif
let e += 1
endwhile
let e += 1
call add(items, strpart(base, s, e - s))
@@ -136,7 +136,7 @@ func ccomplete#Complete(findstart, base)
if complete_check()
return res
endif
let col2 -= 1
let col2 -= 1
endwhile
let line = strpart(line, col2 + 1)
let col -= col2
@@ -149,11 +149,11 @@ func ccomplete#Complete(findstart, base)
if complete_check()
return res
endif
let col2 -= 1
let col2 -= 1
endwhile
if strpart(line, col2 + 1, col - col2 - 1) =~ ' *[^ ][^ ]* *[^ ]'
let line = strpart(line, col2 + 1)
let col -= col2
let line = strpart(line, col2 + 1)
let col -= col2
endif
endif
if len(items) == 1
@@ -162,17 +162,17 @@ func ccomplete#Complete(findstart, base)
let match = items[0]
let kind = 'v'
if match(line, '\<' . match . '\s*\[') > 0
let match .= '['
let match .= '['
else
let res = s:Nextitem(strpart(line, 0, col), [''], 0, 1)
if len(res) > 0
" There are members, thus add "." or "->".
if match(line, '\*[ \t(]*' . match . '\>') > 0
let match .= '->'
else
let match .= '.'
endif
endif
let res = s:Nextitem(strpart(line, 0, col), [''], 0, 1)
if len(res) > 0
" There are members, thus add "." or "->".
if match(line, '\*[ \t(]*' . match . '\>') > 0
let match .= '->'
else
let match .= '.'
endif
endif
endif
let res = [{'match': match, 'tagline' : '', 'kind' : kind, 'info' : line}]
elseif len(items) == arrays + 1
@@ -219,19 +219,19 @@ func ccomplete#Complete(findstart, base)
endif
" New ctags has the "typeref" field. Patched version has "typename".
if has_key(diclist[i], 'typename')
call extend(res, s:StructMembers(diclist[i]['typename'], items[1:], 1))
call extend(res, s:StructMembers(diclist[i]['typename'], items[1:], 1))
elseif has_key(diclist[i], 'typeref')
call extend(res, s:StructMembers(diclist[i]['typeref'], items[1:], 1))
call extend(res, s:StructMembers(diclist[i]['typeref'], items[1:], 1))
endif
" For a variable use the command, which must be a search pattern that
" shows the declaration of the variable.
if diclist[i]['kind'] == 'v'
let line = diclist[i]['cmd']
if line[0] == '/' && line[1] == '^'
let col = match(line, '\<' . items[0] . '\>')
call extend(res, s:Nextitem(strpart(line, 2, col - 2), items[1:], 0, 1))
endif
let line = diclist[i]['cmd']
if line[0] == '/' && line[1] == '^'
let col = match(line, '\<' . items[0] . '\>')
call extend(res, s:Nextitem(strpart(line, 2, col - 2), items[1:], 0, 1))
endif
endif
endfor
endif
@@ -338,8 +338,8 @@ func s:ParseTagline(line)
if l[2] =~ '^/'
" Find end of cmd, it may contain Tabs.
while n < len(l) && l[n] !~ '/;"$'
let n += 1
let d['cmd'] .= " " . l[n]
let n += 1
let d['cmd'] .= " " . l[n]
endwhile
endif
for i in range(n + 1, len(l) - 1)
@@ -347,11 +347,11 @@ func s:ParseTagline(line)
return d
endif
if l[i] == 'file:'
let d['static'] = 1
let d['static'] = 1
elseif l[i] !~ ':'
let d['kind'] = l[i]
let d['kind'] = l[i]
else
let d[matchstr(l[i], '[^:]*')] = matchstr(l[i], ':\zs.*')
let d[matchstr(l[i], '[^:]*')] = matchstr(l[i], ':\zs.*')
endif
endfor
endif
@@ -454,7 +454,7 @@ func s:Nextitem(lead, items, depth, all)
continue
endif
" Use the tags file to find out if this is a typedef.
" Use the tags file to find out if this is a typedef or struct
let diclist = taglist('^' . tokens[tidx] . '$')
for tagidx in range(len(diclist))
@@ -466,22 +466,29 @@ func s:Nextitem(lead, items, depth, all)
" New ctags has the "typeref" field. Patched version has "typename".
if has_key(item, 'typeref')
call extend(res, s:StructMembers(item['typeref'], a:items, a:all))
continue
call extend(res, s:StructMembers(item['typeref'], a:items, a:all))
continue
endif
if has_key(item, 'typename')
call extend(res, s:StructMembers(item['typename'], a:items, a:all))
continue
call extend(res, s:StructMembers(item['typename'], a:items, a:all))
continue
endif
" handle struct
if item['kind'] == 's'
let res = s:StructMembers('struct:' .. tokens[tidx], a:items, a:all)
break
endif
" Only handle typedefs here.
if item['kind'] != 't'
continue
continue
endif
" Skip matches local to another file.
if has_key(item, 'static') && item['static'] && bufnr('%') != bufnr(item['filename'])
continue
continue
endif
" For old ctags we recognize "typedef struct aaa" and
@@ -489,25 +496,25 @@ func s:Nextitem(lead, items, depth, all)
let cmd = item['cmd']
let ei = matchend(cmd, 'typedef\s\+')
if ei > 1
let cmdtokens = split(strpart(cmd, ei), '\s\+\|\<')
if len(cmdtokens) > 1
if cmdtokens[0] == 'struct' || cmdtokens[0] == 'union' || cmdtokens[0] == 'class'
let name = ''
" Use the first identifier after the "struct" or "union"
for ti in range(len(cmdtokens) - 1)
if cmdtokens[ti] =~ '^\w'
let name = cmdtokens[ti]
break
endif
endfor
if name != ''
call extend(res, s:StructMembers(cmdtokens[0] . ':' . name, a:items, a:all))
endif
elseif a:depth < 10
" Could be "typedef other_T some_T".
call extend(res, s:Nextitem(cmdtokens[0], a:items, a:depth + 1, a:all))
endif
endif
let cmdtokens = split(strpart(cmd, ei), '\s\+\|\<')
if len(cmdtokens) > 1
if cmdtokens[0] == 'struct' || cmdtokens[0] == 'union' || cmdtokens[0] == 'class'
let name = ''
" Use the first identifier after the "struct" or "union"
for ti in range(len(cmdtokens) - 1)
if cmdtokens[ti] =~ '^\w'
let name = cmdtokens[ti]
break
endif
endfor
if name != ''
call extend(res, s:StructMembers(cmdtokens[0] . ':' . name, a:items, a:all))
endif
elseif a:depth < 10
" Could be "typedef other_T some_T".
call extend(res, s:Nextitem(cmdtokens[0], a:items, a:depth + 1, a:all))
endif
endif
endif
endfor
if len(res) > 0
@@ -535,7 +542,7 @@ func s:StructMembers(typename, items, all)
let qflist = []
let cached = 0
if a:all == 0
let n = '1' " stop at first found match
let n = '1' " stop at first found match
if has_key(s:grepCache, a:typename)
let qflist = s:grepCache[a:typename]
let cached = 1
@@ -552,7 +559,7 @@ func s:StructMembers(typename, items, all)
let qflist = getqflist()
if len(qflist) > 0 || match(typename, "::") < 0
break
break
endif
" No match for "struct:context::name", remove "context::" and try again.
let typename = substitute(typename, ':[^:]*::', ':', '')
@@ -571,7 +578,7 @@ func s:StructMembers(typename, items, all)
return []
endif
if idx >= len(a:items)
let target = '' " No further items, matching all members
let target = '' " No further items, matching all members
break
endif
if a:items[idx][0] != '['
@@ -587,18 +594,18 @@ func s:StructMembers(typename, items, all)
if memb =~ '^' . target
" Skip matches local to another file.
if match(l['text'], "\tfile:") < 0 || bufnr('%') == bufnr(matchstr(l['text'], '\t\zs[^\t]*'))
let item = {'match': memb, 'tagline': l['text']}
let item = {'match': memb, 'tagline': l['text']}
" Add the kind of item.
let s = matchstr(l['text'], '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
if s != ''
let item['kind'] = s
if s == 'f'
let item['match'] = memb . '('
endif
endif
" Add the kind of item.
let s = matchstr(l['text'], '\t\(kind:\)\=\zs\S\ze\(\t\|$\)')
if s != ''
let item['kind'] = s
if s == 'f'
let item['match'] = memb . '('
endif
endif
call add(matches, item)
call add(matches, item)
endif
endif
endfor
@@ -611,10 +618,10 @@ func s:StructMembers(typename, items, all)
return matches
endif
if idx >= len(a:items)
return matches " No further items, return the result.
return matches " No further items, return the result.
endif
if a:items[idx][0] != '['
break
break
endif
let idx += 1
endwhile
@@ -640,20 +647,20 @@ func s:SearchMembers(matches, items, all)
let typename = ''
if has_key(a:matches[i], 'dict')
if has_key(a:matches[i].dict, 'typename')
let typename = a:matches[i].dict['typename']
let typename = a:matches[i].dict['typename']
elseif has_key(a:matches[i].dict, 'typeref')
let typename = a:matches[i].dict['typeref']
let typename = a:matches[i].dict['typeref']
endif
let line = "\t" . a:matches[i].dict['cmd']
else
let line = a:matches[i]['tagline']
let e = matchend(line, '\ttypename:')
if e < 0
let e = matchend(line, '\ttyperef:')
let e = matchend(line, '\ttyperef:')
endif
if e > 0
" Use typename field
let typename = matchstr(line, '[^\t]*', e)
" Use typename field
let typename = matchstr(line, '[^\t]*', e)
endif
endif
@@ -663,10 +670,10 @@ func s:SearchMembers(matches, items, all)
" Use the search command (the declaration itself).
let s = match(line, '\t\zs/^')
if s > 0
let e = match(line, '\<' . a:matches[i]['match'] . '\>', s)
if e > 0
call extend(res, s:Nextitem(strpart(line, s, e - s), a:items, 0, a:all))
endif
let e = match(line, '\<' . a:matches[i]['match'] . '\>', s)
if e > 0
call extend(res, s:Nextitem(strpart(line, s, e - s), a:items, 0, a:all))
endif
endif
endif
if a:all == 0 && len(res) > 0
@@ -679,4 +686,4 @@ endfunc
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: noet sw=2 sts=2
" vim: et sw=2 sts=2