---------------------------------------- -- This file is generated via github.com/tjdevries/vim9jit -- For any bugs, please first consider reporting there. ---------------------------------------- -- Ignore "value assigned to a local variable is unused" because -- we can't guarantee that local variables will be used by plugins -- luacheck: ignore 311 local vim9 = require('_vim9script') local M = {} local prepended = nil local grepCache = nil local Complete = nil local GetAddition = nil local Tag2item = nil local Dict2info = nil local ParseTagline = nil local Tagline2item = nil local Tagcmd2extra = nil local Nextitem = nil local StructMembers = nil local SearchMembers = nil -- vim9script -- # Vim completion script -- # Language: C -- # Maintainer: The Vim Project -- # Last Change: 2023 Aug 10 -- # Rewritten in Vim9 script by github user lacygoill -- # Former Maintainer: Bram Moolenaar prepended = '' grepCache = vim.empty_dict() -- # This function is used for the 'omnifunc' option. Complete = function(findstart, abase) findstart = vim9.bool(findstart) if vim9.bool(findstart) then -- # Locate the start of the item, including ".", "->" and "[...]". local line = vim9.fn.getline('.') local start = vim9.fn.charcol('.') - 1 local lastword = -1 while start > 0 do if vim9.ops.RegexpMatches(vim9.index(line, vim9.ops.Minus(start, 1)), '\\w') then start = start - 1 elseif vim9.bool(vim9.ops.RegexpMatches(vim9.index(line, vim9.ops.Minus(start, 1)), '\\.')) then if lastword == -1 then lastword = start end start = start - 1 elseif vim9.bool( start > 1 and vim9.index(line, vim9.ops.Minus(start, 2)) == '-' and vim9.index(line, vim9.ops.Minus(start, 1)) == '>' ) then if lastword == -1 then lastword = start end start = vim9.ops.Minus(start, 2) elseif vim9.bool(vim9.index(line, vim9.ops.Minus(start, 1)) == ']') then -- # Skip over [...]. local n = 0 start = start - 1 while start > 0 do start = start - 1 if vim9.index(line, start) == '[' then if n == 0 then break end n = n - 1 elseif vim9.bool(vim9.index(line, start) == ']') then n = n + 1 end end else break end end -- # Return the column of the last word, which is going to be changed. -- # Remember the text that comes before it in prepended. if lastword == -1 then prepended = '' return vim9.fn.byteidx(line, start) end prepended = vim9.slice(line, start, vim9.ops.Minus(lastword, 1)) return vim9.fn.byteidx(line, lastword) end -- # Return list of matches. local base = prepended .. abase -- # Don't do anything for an empty base, would result in all the tags in the -- # tags file. if base == '' then return {} end -- # init cache for vimgrep to empty grepCache = {} -- # Split item in words, keep empty word after "." or "->". -- # "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc. -- # We can't use split, because we need to skip nested [...]. -- # "aa[...]" -> ['aa', '[...]'], "aa.bb[...]" -> ['aa', 'bb', '[...]'], etc. local items = {} local s = 0 local arrays = 0 while 1 do local e = vim9.fn.charidx(base, vim9.fn.match(base, '\\.\\|->\\|\\[', s)) if e < 0 then if s == 0 or vim9.index(base, vim9.ops.Minus(s, 1)) ~= ']' then vim9.fn.add(items, vim9.slice(base, s, nil)) end break end if s == 0 or vim9.index(base, vim9.ops.Minus(s, 1)) ~= ']' then vim9.fn.add(items, vim9.slice(base, s, vim9.ops.Minus(e, 1))) end if vim9.index(base, e) == '.' then -- # skip over '.' s = vim9.ops.Plus(e, 1) elseif vim9.bool(vim9.index(base, e) == '-') then -- # skip over '->' s = vim9.ops.Plus(e, 2) else -- # Skip over [...]. local n = 0 s = e e = e + 1 while e < vim9.fn.strcharlen(base) do if vim9.index(base, e) == ']' then if n == 0 then break end n = n - 1 elseif vim9.bool(vim9.index(base, e) == '[') then n = n + 1 end e = e + 1 end e = e + 1 vim9.fn.add(items, vim9.slice(base, s, vim9.ops.Minus(e, 1))) arrays = arrays + 1 s = e end end -- # Find the variable items[0]. -- # 1. in current function (like with "gd") -- # 2. in tags file(s) (like with ":tag") -- # 3. in current file (like with "gD") local res = {} if vim9.fn.searchdecl(vim9.index(items, 0), false, true) == 0 then -- # Found, now figure out the type. -- # TODO: join previous line if it makes sense local line = vim9.fn.getline('.') local col = vim9.fn.charcol('.') if vim9.fn.stridx(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), ';') >= 0 then -- # Handle multiple declarations on the same line. local col2 = vim9.ops.Minus(col, 1) while vim9.index(line, col2) ~= ';' do col2 = col2 - 1 end line = vim9.slice(line, vim9.ops.Plus(col2, 1), nil) col = vim9.ops.Minus(col, col2) end if vim9.fn.stridx(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), ',') >= 0 then -- # Handle multiple declarations on the same line in a function -- # declaration. local col2 = vim9.ops.Minus(col, 1) while vim9.index(line, col2) ~= ',' do col2 = col2 - 1 end if vim9.ops.RegexpMatches( vim9.slice(line, vim9.ops.Plus(col2, 1), vim9.ops.Minus(col, 1)), ' *[^ ][^ ]* *[^ ]' ) then line = vim9.slice(line, vim9.ops.Plus(col2, 1), nil) col = vim9.ops.Minus(col, col2) end end if vim9.fn.len(items) == 1 then -- # Completing one word and it's a local variable: May add '[', '.' or -- # '->'. local match = vim9.index(items, 0) local kind = 'v' if vim9.fn.match(line, '\\<' .. match .. '\\s*\\[') > 0 then match = match .. '[' else res = Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), { '' }, 0, true) if vim9.fn.len(res) > 0 then -- # There are members, thus add "." or "->". if vim9.fn.match(line, '\\*[ \\t(]*' .. match .. '\\>') > 0 then match = match .. '->' else match = match .. '.' end end end res = { { ['match'] = match, ['tagline'] = '', ['kind'] = kind, ['info'] = line } } elseif vim9.bool(vim9.fn.len(items) == vim9.ops.Plus(arrays, 1)) then -- # Completing one word and it's a local array variable: build tagline -- # from declaration line local match = vim9.index(items, 0) local kind = 'v' local tagline = '\t/^' .. line .. '$/' res = { { ['match'] = match, ['tagline'] = tagline, ['kind'] = kind, ['info'] = line } } else -- # Completing "var.", "var.something", etc. res = Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true) end end if vim9.fn.len(items) == 1 or vim9.fn.len(items) == vim9.ops.Plus(arrays, 1) then -- # Only one part, no "." or "->": complete from tags file. local tags = {} if vim9.fn.len(items) == 1 then tags = vim9.fn.taglist('^' .. base) else tags = vim9.fn.taglist('^' .. vim9.index(items, 0) .. '$') end vim9.fn_mut('filter', { vim9.fn_mut('filter', { tags, function(_, v) return vim9.ternary(vim9.fn.has_key(v, 'kind'), function() return v.kind ~= 'm' end, true) end, }, { replace = 0 }), function(_, v) return vim9.ops.Or( vim9.ops.Or( vim9.prefix['Bang'](vim9.fn.has_key(v, 'static')), vim9.prefix['Bang'](vim9.index(v, 'static')) ), vim9.fn.bufnr('%') == vim9.fn.bufnr(vim9.index(v, 'filename')) ) end, }, { replace = 0 }) res = vim9.fn.extend( res, vim9.fn.map(tags, function(_, v) return Tag2item(v) end) ) end if vim9.fn.len(res) == 0 then -- # Find the variable in the tags file(s) local diclist = vim9.fn.filter( vim9.fn.taglist('^' .. vim9.index(items, 0) .. '$'), function(_, v) return vim9.ternary(vim9.fn.has_key(v, 'kind'), function() return v.kind ~= 'm' end, true) end ) res = {} for _, i in vim9.iter(vim9.fn.range(vim9.fn.len(diclist))) do -- # New ctags has the "typeref" field. Patched version has "typename". if vim9.bool(vim9.fn.has_key(vim9.index(diclist, i), 'typename')) then res = vim9.fn.extend( res, StructMembers( vim9.index(vim9.index(diclist, i), 'typename'), vim9.slice(items, 1, nil), true ) ) elseif vim9.bool(vim9.fn.has_key(vim9.index(diclist, i), 'typeref')) then res = vim9.fn.extend( res, StructMembers( vim9.index(vim9.index(diclist, i), 'typeref'), vim9.slice(items, 1, nil), true ) ) end -- # For a variable use the command, which must be a search pattern that -- # shows the declaration of the variable. if vim9.index(vim9.index(diclist, i), 'kind') == 'v' then local line = vim9.index(vim9.index(diclist, i), 'cmd') if vim9.slice(line, nil, 1) == '/^' then local col = vim9.fn.charidx(line, vim9.fn.match(line, '\\<' .. vim9.index(items, 0) .. '\\>')) res = vim9.fn.extend( res, Nextitem( vim9.slice(line, 2, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true ) ) end end end end if vim9.fn.len(res) == 0 and vim9.fn.searchdecl(vim9.index(items, 0), true) == 0 then -- # Found, now figure out the type. -- # TODO: join previous line if it makes sense local line = vim9.fn.getline('.') local col = vim9.fn.charcol('.') res = Nextitem(vim9.slice(line, nil, vim9.ops.Minus(col, 1)), vim9.slice(items, 1, nil), 0, true) end -- # If the last item(s) are [...] they need to be added to the matches. local last = vim9.fn.len(items) - 1 local brackets = '' while last >= 0 do if vim9.index(vim9.index(items, last), 0) ~= '[' then break end brackets = vim9.index(items, last) .. brackets last = last - 1 end return vim9.fn.map(res, function(_, v) return Tagline2item(v, brackets) end) end M['Complete'] = Complete GetAddition = function(line, match, memarg, bracket) bracket = vim9.bool(bracket) -- # Guess if the item is an array. if vim9.bool(vim9.ops.And(bracket, vim9.fn.match(line, match .. '\\s*\\[') > 0)) then return '[' end -- # Check if the item has members. if vim9.fn.len(SearchMembers(memarg, { '' }, false)) > 0 then -- # If there is a '*' before the name use "->". if vim9.fn.match(line, '\\*[ \\t(]*' .. match .. '\\>') > 0 then return '->' else return '.' end end return '' end Tag2item = function(val) -- # Turn the tag info "val" into an item for completion. -- # "val" is is an item in the list returned by taglist(). -- # If it is a variable we may add "." or "->". Don't do it for other types, -- # such as a typedef, by not including the info that GetAddition() uses. local res = vim9.convert.decl_dict({ ['match'] = vim9.index(val, 'name') }) res[vim9.index_expr('extra')] = Tagcmd2extra(vim9.index(val, 'cmd'), vim9.index(val, 'name'), vim9.index(val, 'filename')) local s = Dict2info(val) if s ~= '' then res[vim9.index_expr('info')] = s end res[vim9.index_expr('tagline')] = '' if vim9.bool(vim9.fn.has_key(val, 'kind')) then local kind = vim9.index(val, 'kind') res[vim9.index_expr('kind')] = kind if kind == 'v' then res[vim9.index_expr('tagline')] = '\t' .. vim9.index(val, 'cmd') res[vim9.index_expr('dict')] = val elseif vim9.bool(kind == 'f') then res[vim9.index_expr('match')] = vim9.index(val, 'name') .. '(' end end return res end Dict2info = function(dict) -- # Use all the items in dictionary for the "info" entry. local info = '' for _, k in vim9.iter(vim9.fn_mut('sort', { vim9.fn.keys(dict) }, { replace = 0 })) do info = info .. k .. vim9.fn['repeat'](' ', 10 - vim9.fn.strlen(k)) if k == 'cmd' then info = info .. vim9.fn.substitute( vim9.fn.matchstr(vim9.index(dict, 'cmd'), '/^\\s*\\zs.*\\ze$/'), '\\\\\\(.\\)', '\\1', 'g' ) else local dictk = vim9.index(dict, k) if vim9.fn.typename(dictk) ~= 'string' then info = info .. vim9.fn.string(dictk) else info = info .. dictk end end info = info .. '\n' end return info end ParseTagline = function(line) -- # Parse a tag line and return a dictionary with items like taglist() local l = vim9.fn.split(line, '\t') local d = vim.empty_dict() if vim9.fn.len(l) >= 3 then d[vim9.index_expr('name')] = vim9.index(l, 0) d[vim9.index_expr('filename')] = vim9.index(l, 1) d[vim9.index_expr('cmd')] = vim9.index(l, 2) local n = 2 if vim9.ops.RegexpMatches(vim9.index(l, 2), '^/') then -- # Find end of cmd, it may contain Tabs. while n < vim9.fn.len(l) and vim9.ops.NotRegexpMatches(vim9.index(l, n), '/;"$') do n = n + 1 d[vim9.index_expr('cmd')] = vim9.index(d, 'cmd') .. ' ' .. vim9.index(l, n) end end for _, i in vim9.iter(vim9.fn.range(vim9.ops.Plus(n, 1), vim9.fn.len(l) - 1)) do if vim9.index(l, i) == 'file:' then d[vim9.index_expr('static')] = 1 elseif vim9.bool(vim9.ops.NotRegexpMatches(vim9.index(l, i), ':')) then d[vim9.index_expr('kind')] = vim9.index(l, i) else d[vim9.index_expr(vim9.fn.matchstr(vim9.index(l, i), '[^:]*'))] = vim9.fn.matchstr(vim9.index(l, i), ':\\zs.*') end end end return d end Tagline2item = function(val, brackets) -- # Turn a match item "val" into an item for completion. -- # "val['match']" is the matching item. -- # "val['tagline']" is the tagline in which the last part was found. local line = vim9.index(val, 'tagline') local add = GetAddition(line, vim9.index(val, 'match'), { val }, brackets == '') local res = vim9.convert.decl_dict({ ['word'] = vim9.index(val, 'match') .. brackets .. add }) if vim9.bool(vim9.fn.has_key(val, 'info')) then -- # Use info from Tag2item(). res[vim9.index_expr('info')] = vim9.index(val, 'info') else -- # Parse the tag line and add each part to the "info" entry. local s = Dict2info(ParseTagline(line)) if s ~= '' then res[vim9.index_expr('info')] = s end end if vim9.bool(vim9.fn.has_key(val, 'kind')) then res[vim9.index_expr('kind')] = vim9.index(val, 'kind') elseif vim9.bool(add == '(') then res[vim9.index_expr('kind')] = 'f' else local s = vim9.fn.matchstr(line, '\\t\\(kind:\\)\\=\\zs\\S\\ze\\(\\t\\|$\\)') if s ~= '' then res[vim9.index_expr('kind')] = s end end if vim9.bool(vim9.fn.has_key(val, 'extra')) then res[vim9.index_expr('menu')] = vim9.index(val, 'extra') return res end -- # Isolate the command after the tag and filename. local s = vim9.fn.matchstr( line, '[^\\t]*\\t[^\\t]*\\t\\zs\\(/^.*$/\\|[^\\t]*\\)\\ze\\(;"\\t\\|\\t\\|$\\)' ) if s ~= '' then res[vim9.index_expr('menu')] = Tagcmd2extra( s, vim9.index(val, 'match'), vim9.fn.matchstr(line, '[^\\t]*\\t\\zs[^\\t]*\\ze\\t') ) end return res end Tagcmd2extra = function(cmd, name, fname) -- # Turn a command from a tag line to something that is useful in the menu local x = '' if vim9.ops.RegexpMatches(cmd, '^/^') then -- # The command is a search command, useful to see what it is. x = vim9.fn.substitute( vim9.fn.substitute( vim9.fn.matchstr(cmd, '^/^\\s*\\zs.*\\ze$/'), '\\<' .. name .. '\\>', '@@', '' ), '\\\\\\(.\\)', '\\1', 'g' ) .. ' - ' .. fname elseif vim9.bool(vim9.ops.RegexpMatches(cmd, '^\\d*$')) then -- # The command is a line number, the file name is more useful. x = fname .. ' - ' .. cmd else -- # Not recognized, use command and file name. x = cmd .. ' - ' .. fname end return x end Nextitem = function(lead, items, depth, all) all = vim9.bool(all) -- # Find composing type in "lead" and match items[0] with it. -- # Repeat this recursively for items[1], if it's there. -- # When resolving typedefs "depth" is used to avoid infinite recursion. -- # Return the list of matches. -- # Use the text up to the variable name and split it in tokens. local tokens = vim9.fn.split(lead, '\\s\\+\\|\\<') -- # Try to recognize the type of the variable. This is rough guessing... local res = {} local body = function(_, tidx) -- # Skip tokens starting with a non-ID character. if vim9.ops.NotRegexpMatches(vim9.index(tokens, tidx), '^\\h') then return vim9.ITER_CONTINUE end -- # Recognize "struct foobar" and "union foobar". -- # Also do "class foobar" when it's C++ after all (doesn't work very well -- # though). if ( vim9.index(tokens, tidx) == 'struct' or vim9.index(tokens, tidx) == 'union' or vim9.index(tokens, tidx) == 'class' ) and vim9.ops.Plus(tidx, 1) < vim9.fn.len(tokens) then res = StructMembers( vim9.index(tokens, tidx) .. ':' .. vim9.index(tokens, vim9.ops.Plus(tidx, 1)), items, all ) return vim9.ITER_BREAK end -- # TODO: add more reserved words if vim9.fn.index( { 'int', 'short', 'char', 'float', 'double', 'static', 'unsigned', 'extern' }, vim9.index(tokens, tidx) ) >= 0 then return vim9.ITER_CONTINUE end -- # Use the tags file to find out if this is a typedef. local diclist = vim9.fn.taglist('^' .. vim9.index(tokens, tidx) .. '$') local body = function(_, tagidx) local item = vim9.convert.decl_dict(vim9.index(diclist, tagidx)) -- # New ctags has the "typeref" field. Patched version has "typename". if vim9.bool(vim9.fn.has_key(item, 'typeref')) then res = vim9.fn.extend(res, StructMembers(vim9.index(item, 'typeref'), items, all)) return vim9.ITER_CONTINUE end if vim9.bool(vim9.fn.has_key(item, 'typename')) then res = vim9.fn.extend(res, StructMembers(vim9.index(item, 'typename'), items, all)) return vim9.ITER_CONTINUE end -- # Only handle typedefs here. if vim9.index(item, 'kind') ~= 't' then return vim9.ITER_CONTINUE end -- # Skip matches local to another file. if vim9.bool( vim9.ops.And( vim9.ops.And(vim9.fn.has_key(item, 'static'), vim9.index(item, 'static')), vim9.fn.bufnr('%') ~= vim9.fn.bufnr(vim9.index(item, 'filename')) ) ) then return vim9.ITER_CONTINUE end -- # For old ctags we recognize "typedef struct aaa" and -- # "typedef union bbb" in the tags file command. local cmd = vim9.index(item, 'cmd') local ei = vim9.fn.charidx(cmd, vim9.fn.matchend(cmd, 'typedef\\s\\+')) if ei > 1 then local cmdtokens = vim9.fn.split(vim9.slice(cmd, ei, nil), '\\s\\+\\|\\<') if vim9.fn.len(cmdtokens) > 1 then if vim9.index(cmdtokens, 0) == 'struct' or vim9.index(cmdtokens, 0) == 'union' or vim9.index(cmdtokens, 0) == 'class' then local name = '' -- # Use the first identifier after the "struct" or "union" for _, ti in vim9.iter(vim9.fn.range((vim9.fn.len(cmdtokens) - 1))) do if vim9.ops.RegexpMatches(vim9.index(cmdtokens, ti), '^\\w') then name = vim9.index(cmdtokens, ti) break end end if name ~= '' then res = vim9.fn.extend( res, StructMembers(vim9.index(cmdtokens, 0) .. ':' .. name, items, all) ) end elseif vim9.bool(depth < 10) then -- # Could be "typedef other_T some_T". res = vim9.fn.extend( res, Nextitem(vim9.index(cmdtokens, 0), items, vim9.ops.Plus(depth, 1), all) ) end end end return vim9.ITER_DEFAULT end for _, tagidx in vim9.iter(vim9.fn.range(vim9.fn.len(diclist))) do local nvim9_status, nvim9_ret = body(_, tagidx) if nvim9_status == vim9.ITER_BREAK then break elseif nvim9_status == vim9.ITER_RETURN then return nvim9_ret end end if vim9.fn.len(res) > 0 then return vim9.ITER_BREAK end return vim9.ITER_DEFAULT end for _, tidx in vim9.iter(vim9.fn.range(vim9.fn.len(tokens))) do local nvim9_status, nvim9_ret = body(_, tidx) if nvim9_status == vim9.ITER_BREAK then break elseif nvim9_status == vim9.ITER_RETURN then return nvim9_ret end end return res end StructMembers = function(atypename, items, all) all = vim9.bool(all) -- # Search for members of structure "typename" in tags files. -- # Return a list with resulting matches. -- # Each match is a dictionary with "match" and "tagline" entries. -- # When "all" is true find all, otherwise just return 1 if there is any member. -- # Todo: What about local structures? local fnames = vim9.fn.join(vim9.fn.map(vim9.fn.tagfiles(), function(_, v) return vim9.fn.escape(v, ' \\#%') end)) if fnames == '' then return {} end local typename = atypename local qflist = {} local cached = 0 local n = '' if vim9.bool(vim9.prefix['Bang'](all)) then n = '1' if vim9.bool(vim9.fn.has_key(grepCache, typename)) then qflist = vim9.index(grepCache, typename) cached = 1 end else n = '' end if vim9.bool(vim9.prefix['Bang'](cached)) then while 1 do vim.api.nvim_command( 'silent! keepjumps noautocmd ' .. n .. 'vimgrep ' .. '/\\t' .. typename .. '\\(\\t\\|$\\)/j ' .. fnames ) qflist = vim9.fn.getqflist() if vim9.fn.len(qflist) > 0 or vim9.fn.match(typename, '::') < 0 then break end -- # No match for "struct:context::name", remove "context::" and try again. typename = vim9.fn.substitute(typename, ':[^:]*::', ':', '') end if vim9.bool(vim9.prefix['Bang'](all)) then -- # Store the result to be able to use it again later. grepCache[vim9.index_expr(typename)] = qflist end end -- # Skip over [...] items local idx = 0 local target = '' while 1 do if idx >= vim9.fn.len(items) then target = '' break end if vim9.index(vim9.index(items, idx), 0) ~= '[' then target = vim9.index(items, idx) break end idx = idx + 1 end -- # Put matching members in matches[]. local matches = {} for _, l in vim9.iter(qflist) do local memb = vim9.fn.matchstr(vim9.index(l, 'text'), '[^\\t]*') if vim9.ops.RegexpMatches(memb, '^' .. target) then -- # Skip matches local to another file. if vim9.fn.match(vim9.index(l, 'text'), '\tfile:') < 0 or vim9.fn.bufnr('%') == vim9.fn.bufnr(vim9.fn.matchstr(vim9.index(l, 'text'), '\\t\\zs[^\\t]*')) then local item = vim9.convert.decl_dict({ ['match'] = memb, ['tagline'] = vim9.index(l, 'text') }) -- # Add the kind of item. local s = vim9.fn.matchstr(vim9.index(l, 'text'), '\\t\\(kind:\\)\\=\\zs\\S\\ze\\(\\t\\|$\\)') if s ~= '' then item[vim9.index_expr('kind')] = s if s == 'f' then item[vim9.index_expr('match')] = memb .. '(' end end vim9.fn.add(matches, item) end end end if vim9.fn.len(matches) > 0 then -- # Skip over next [...] items idx = idx + 1 while 1 do if idx >= vim9.fn.len(items) then return matches end if vim9.index(vim9.index(items, idx), 0) ~= '[' then break end idx = idx + 1 end -- # More items following. For each of the possible members find the -- # matching following members. return SearchMembers(matches, vim9.slice(items, idx, nil), all) end -- # Failed to find anything. return {} end SearchMembers = function(matches, items, all) all = vim9.bool(all) -- # For matching members, find matches for following items. -- # When "all" is true find all, otherwise just return 1 if there is any member. local res = {} for _, i in vim9.iter(vim9.fn.range(vim9.fn.len(matches))) do local typename = '' local line = '' if vim9.bool(vim9.fn.has_key(vim9.index(matches, i), 'dict')) then if vim9.bool(vim9.fn.has_key(vim9.index(vim9.index(matches, i), 'dict'), 'typename')) then typename = vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'typename') elseif vim9.bool(vim9.fn.has_key(vim9.index(vim9.index(matches, i), 'dict'), 'typeref')) then typename = vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'typeref') end line = '\t' .. vim9.index(vim9.index(vim9.index(matches, i), 'dict'), 'cmd') else line = vim9.index(vim9.index(matches, i), 'tagline') local eb = vim9.fn.matchend(line, '\\ttypename:') local e = vim9.fn.charidx(line, eb) if e < 0 then eb = vim9.fn.matchend(line, '\\ttyperef:') e = vim9.fn.charidx(line, eb) end if e > 0 then -- # Use typename field typename = vim9.fn.matchstr(line, '[^\\t]*', eb) end end if typename ~= '' then res = vim9.fn.extend(res, StructMembers(typename, items, all)) else -- # Use the search command (the declaration itself). local sb = vim9.fn.match(line, '\\t\\zs/^') local s = vim9.fn.charidx(line, sb) if s > 0 then local e = vim9.fn.charidx( line, vim9.fn.match(line, '\\<' .. vim9.index(vim9.index(matches, i), 'match') .. '\\>', sb) ) if e > 0 then res = vim9.fn.extend(res, Nextitem(vim9.slice(line, s, vim9.ops.Minus(e, 1)), items, 0, all)) end end end if vim9.bool(vim9.ops.And(vim9.prefix['Bang'](all), vim9.fn.len(res) > 0)) then break end end return res end -- #}}}1 -- # vim: noet sw=2 sts=2 return M