On 02/04/20 09:09AM, Christian Brabandt wrote: > [I did not receive the original mail, so answering to Tonys mail, please > keep the list on CC]
Strange. I did keep the list in Cc ([email protected], but now I've also included [email protected]). I think my emails are being held up by something because I noticed that when I sent the first email it took a while (multiple hours) to show up in the Google groups archive. And now I see that my reply doesn't show up in the archive even though my mail client shows [email protected] in Cc. > On Mi, 01 Apr 2020, Tony Mechelynck wrote: > > > > Yes, the tags file is sorted and vim is built with +tag_binary and > > > 'tagbsearch' is on. The tags file wasn't case-folded sorted, but I tried > > > with that too and I see similar performance. > > > > > > Anyway, just to remove any potential confusion, jumping to tags via > > > 'CTRL-]' is blazing fast. So is listing all alternatives with 'g]'. Does > > > ccomplete use the same mechanism for searching tags file as those two? > > > If so, then I wonder why it is so much slower. > > Hm, I had a quick look at ccomplete.vim. It not only does a tag search, > but also searches the current file and more importantly, it might call > :vimgrep and :vimgrep is known to be slow if many files have to be > searched. Not sure if there is anything to improve, perhaps adding a > switch to only do tag completion would already help? > > Anyhow, first please create a vimscript profile, so we can exactly see > when it is slow. See :h :profile and this stackoverflow answer: > https://stackoverflow.com/a/12216578/789222 > > Perhaps this can share some more light on the slowness. The profile log is pretty big (~3500 lines) since I use multiple plugins. Trace of ccomplete#Complete and StructMembers() is pasted below. Let me know if you need any more info, like traces of other functions in the call chain. The major time consumer looks like: 21 130.867568 exe 'silent! keepj noautocmd ' . n . 'vimgrep /\t' . typename . '\(\t\|$\)/j ' . fnames inside StructMembers(). FUNCTIONS SORTED ON TOTAL TIME count total (s) self (s) function 2 130.920294 0.013774 ccomplete#Complete() 21 130.873054 <SNR>77_StructMembers() 2 124.341230 0.001711 <SNR>77_Nextitem() 129 6.548978 0.004060 <SNR>77_Tagline2item() 129 6.544918 0.002094 <SNR>77_GetAddition() 128 6.542824 0.009213 <SNR>77_SearchMembers() 14 0.024376 0.001583 airline#check_mode() 2 0.022166 0.004144 airline#highlighter#highlight() 128 0.016388 0.003802 <SNR>77_Tag2item() 76 0.013935 0.003591 airline#highlighter#exec() 14 0.011462 0.000464 airline#extensions#branch#get_head() 14 0.010636 0.000383 airline#extensions#branch#head() 14 0.010169 0.000242 airline#extensions#wordcount#get() 6 0.009927 0.000111 <SNR>61_update_wordcount() 6 0.009742 <SNR>61_get_wordcount() 128 0.009439 <SNR>77_Dict2info() 116 0.009389 0.004537 airline#highlighter#get_highlight() 14 0.008767 0.000787 <SNR>57_update_branch() 20 0.007623 0.000636 <SNR>55_exec_separator() 14 0.007164 0.000748 <SNR>57_update_git_branch() FUNCTIONS SORTED ON SELF TIME count total (s) self (s) function 21 130.873054 <SNR>77_StructMembers() 2 130.920294 0.013774 ccomplete#Complete() 6 0.009742 <SNR>61_get_wordcount() 128 0.009439 <SNR>77_Dict2info() 128 6.542824 0.009213 <SNR>77_SearchMembers() 116 0.009389 0.004537 airline#highlighter#get_highlight() 232 0.004197 <SNR>55_get_syn() 2 0.022166 0.004144 airline#highlighter#highlight() 129 6.548978 0.004060 <SNR>77_Tagline2item() 128 0.016388 0.003802 <SNR>77_Tag2item() 76 0.013935 0.003591 airline#highlighter#exec() 128 0.003147 <SNR>77_Tagcmd2extra() 14 0.004693 0.003079 fugitive#Find() 34 0.002095 <SNR>55_GetHiCmd() 129 6.544918 0.002094 <SNR>77_GetAddition() 14 0.001898 <SNR>75_generate_names() 2 124.341230 0.001711 <SNR>77_Nextitem() 76 0.001710 <SNR>55_CheckDefined() 14 0.024376 0.001583 airline#check_mode() 14 0.001486 0.001300 <SNR>57_update_untracked() FUNCTION ccomplete#Complete() Defined: /usr/share/vim/vim82/autoload/ccomplete.vim:10 Called 2 times Total time: 130.920294 Self time: 0.013774 count total (s) self (s) 2 0.000004 if a:findstart " Locate the start of the item, including ".", "->" and "[...]". 1 0.000003 let line = getline('.') 1 0.000003 let start = col('.') - 1 1 0.000001 let lastword = -1 4 0.000005 while start > 0 4 0.000012 if line[start - 1] =~ '\w' 3 0.000003 let start -= 1 1 0.000002 elseif line[start - 1] =~ '\.' if lastword == -1 let lastword = start endif let start -= 1 1 0.000002 elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>' if lastword == -1 let lastword = start endif let start -= 2 1 0.000001 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 1 0.000000 else 1 0.000001 break 3 0.000001 endif 4 0.000002 endwhile " Return the column of the last word, which is going to be changed. " Remember the text that comes before it in s:prepended. 1 0.000001 if lastword == -1 1 0.000002 let s:prepended = '' 1 0.000001 return start endif let s:prepended = strpart(line, start, lastword - start) return lastword 1 0.000001 endif " Return list of matches. 1 0.000002 let base = s:prepended . a:base " Don't do anything for an empty base, would result in all the tags in the " tags file. 1 0.000001 if base == '' return [] 1 0.000000 endif " init cache for vimgrep to empty 1 0.000001 let s: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. 1 0.000001 let items = [] 1 0.000001 let s = 0 1 0.000001 let arrays = 0 1 0.000001 while 1 1 0.000005 let e = match(base, '\.\|->\|\[', s) 1 0.000001 if e < 0 1 0.000002 if s == 0 || base[s - 1] != ']' 1 0.000003 call add(items, strpart(base, s)) 1 0.000000 endif 1 0.000001 break endif if s == 0 || base[s - 1] != ']' call add(items, strpart(base, s, e - s)) endif if base[e] == '.' let s = e + 1 " skip over '.' elseif base[e] == '-' let s = e + 2 " skip over '->' else " Skip over [...]. let n = 0 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 endwhile let e += 1 call add(items, strpart(base, s, e - s)) let arrays += 1 let s = e endif 1 0.000001 endwhile " 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") 1 0.000001 let res = [] 1 0.000027 if searchdecl(items[0], 0, 1) == 0 " Found, now figure out the type. " TODO: join previous line if it makes sense 1 0.000002 let line = getline('.') 1 0.000002 let col = col('.') 1 0.000003 if stridx(strpart(line, 0, col), ';') != -1 " Handle multiple declarations on the same line. let col2 = col - 1 while line[col2] != ';' let col2 -= 1 endwhile let line = strpart(line, col2 + 1) let col -= col2 1 0.000000 endif 1 0.000003 if stridx(strpart(line, 0, col), ',') != -1 " Handle multiple declarations on the same line in a function " declaration. let col2 = col - 1 while line[col2] != ',' let col2 -= 1 endwhile if strpart(line, col2 + 1, col - col2 - 1) =~ ' *[^ ][^ ]* *[^ ]' let line = strpart(line, col2 + 1) let col -= col2 endif 1 0.000001 endif 1 0.000001 if len(items) == 1 " Completing one word and it's a local variable: May add '[', '.' or " '->'. 1 0.000001 let match = items[0] 1 0.000001 let kind = 'v' 1 0.000005 if match(line, '\<' . match . '\s*\[') > 0 let match .= '[' 1 0.000001 else 1 124.341163 0.000009 let res = s:Nextitem(strpart(line, 0, col), [''], 0, 1) 1 0.000001 if len(res) > 0 " There are members, thus add "." or "->". 1 0.001138 if match(line, '\*[ \t(]*' . match . '\>') > 0 1 0.000003 let match .= '->' else let match .= '.' 1 0.000000 endif 1 0.000000 endif 1 0.000001 endif 1 0.000011 let res = [{'match': match, 'tagline' : '', 'kind' : kind, 'info' : line}] elseif len(items) == arrays + 1 " Completing one word and it's a local array variable: build tagline " from declaration line let match = items[0] let kind = 'v' let tagline = "\t/^" . line . '$/' let res = [{'match': match, 'tagline' : tagline, 'kind' : kind, 'info' : line}] else " Completing "var.", "var.something", etc. let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1) 1 0.000000 endif 1 0.000001 endif 1 0.000002 if len(items) == 1 || len(items) == arrays + 1 " Only one part, no "." or "->": complete from tags file. 1 0.000001 if len(items) == 1 1 0.002090 let tags = taglist('^' . base) else let tags = taglist('^' . items[0] . '$') 1 0.000001 endif " Remove members, these can't appear without something in front. 1 0.000605 call filter(tags, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1') " Remove static matches in other files. 1 0.008299 call filter(tags, '!has_key(v:val, "static") || !v:val["static"] || bufnr("%") == bufnr(v:val["filename"])') 1 0.017006 0.000618 call extend(res, map(tags, 's:Tag2item(v:val)')) 1 0.000000 endif 1 0.000001 if len(res) == 0 " Find the variable in the tags file(s) let diclist = taglist('^' . items[0] . '$') " Remove members, these can't appear without something in front. call filter(diclist, 'has_key(v:val, "kind") ? v:val["kind"] != "m" : 1') let res = [] for i in range(len(diclist)) " 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)) elseif has_key(diclist[i], 'typeref') 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 endif endfor 1 0.000000 endif 1 0.000002 if len(res) == 0 && searchdecl(items[0], 1) == 0 " Found, now figure out the type. " TODO: join previous line if it makes sense let line = getline('.') let col = col('.') let res = s:Nextitem(strpart(line, 0, col), items[1:], 0, 1) 1 0.000000 endif " If the last item(s) are [...] they need to be added to the matches. 1 0.000002 let last = len(items) - 1 1 0.000001 let brackets = '' 1 0.000001 while last >= 0 1 0.000003 if items[last][0] != '[' 1 0.000001 break endif let brackets = items[last] . brackets let last -= 1 1 0.000001 endwhile 1 6.549648 0.000670 return map(res, 's:Tagline2item(v:val, brackets)') FUNCTION <SNR>77_StructMembers() Defined: /usr/share/vim/vim82/autoload/ccomplete.vim:496 Called 21 times Total time: 130.873054 Self time: 130.873054 count total (s) self (s) " Todo: What about local structures? 21 0.002335 let fnames = join(map(tagfiles(), 'escape(v:val, " \\#%")')) 21 0.000034 if fnames == '' return [] 21 0.000007 endif 21 0.000030 let typename = a:typename 21 0.000021 let qflist = [] 21 0.000021 let cached = 0 21 0.000022 if a:all == 0 1 0.000001 let n = '1' " stop at first found match 1 0.000002 if has_key(s:grepCache, a:typename) let qflist = s:grepCache[a:typename] let cached = 1 1 0.000000 endif 20 0.000010 else 20 0.000019 let n = '' 21 0.000010 endif 21 0.000020 if !cached 21 0.000019 while 1 21 130.867568 exe 'silent! keepj noautocmd ' . n . 'vimgrep /\t' . typename . '\(\t\|$\)/j ' . fnames 21 0.000335 let qflist = getqflist() 21 0.000279 if len(qflist) > 0 || match(typename, "::") < 0 21 0.000043 break endif " No match for "struct:context::name", remove "context::" and try again. let typename = substitute(typename, ':[^:]*::', ':', '') 21 0.000029 endwhile 21 0.000040 if a:all == 0 " Store the result to be able to use it again later. 1 0.000003 let s:grepCache[a:typename] = qflist 21 0.000014 endif 21 0.000031 endif " Skip over [...] items 21 0.000035 let idx = 0 21 0.000019 while 1 21 0.000053 if idx >= len(a:items) let target = '' " No further items, matching all members break 21 0.000010 endif 21 0.000083 if a:items[idx][0] != '[' 21 0.000039 let target = a:items[idx] 21 0.000006 break endif let idx += 1 21 0.000034 endwhile " Put matching members in matches[]. 21 0.000026 let matches = [] 45 0.000051 for l in qflist 24 0.000103 let memb = matchstr(l['text'], '[^\t]*') 24 0.000042 if memb =~ '^' . target " Skip matches local to another file. 24 0.000097 if match(l['text'], "\tfile:") < 0 || bufnr('%') == bufnr(matchstr(l['text'], '\t\zs[^\t]*')) 24 0.000048 let item = {'match': memb, 'tagline': l['text']} " Add the kind of item. 24 0.000127 let s = matchstr(l['text'], '\t\(kind:\)\=\zs\S\ze\(\t\|$\)') 24 0.000021 if s != '' 24 0.000026 let item['kind'] = s 24 0.000018 if s == 'f' let item['match'] = memb . '(' 24 0.000012 endif 24 0.000007 endif 24 0.000036 call add(matches, item) 24 0.000009 endif 24 0.000007 endif 45 0.000035 endfor 21 0.000039 if len(matches) > 0 " Skip over next [...] items 1 0.000002 let idx += 1 1 0.000000 while 1 1 0.000002 if idx >= len(a:items) 1 0.000003 return matches " No further items, return the result. endif if a:items[idx][0] != '[' break endif let idx += 1 endwhile " More items following. For each of the possible members find the " matching following members. return s:SearchMembers(matches, a:items[idx :], a:all) 20 0.000011 endif " Failed to find anything. 20 0.000018 return [] -- Regards, Pratyush Yadav -- -- You received this message from the "vim_use" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_use" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/vim_use/20200402090645.wmiurwe4remde6za%40yadavpratyush.com.
