Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 1 | vim9script noclear |
Bram Moolenaar | e344bea | 2005-09-01 20:46:49 +0000 | [diff] [blame] | 2 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 3 | # Vim completion script |
Christian Brabandt | e978b45 | 2023-08-13 10:33:05 +0200 | [diff] [blame] | 4 | # Language: C |
| 5 | # Maintainer: The Vim Project <https://github.com/vim/vim> |
Lars T. Kyllingstad | d9ec676 | 2024-06-06 18:37:08 +0200 | [diff] [blame] | 6 | # Last Change: 2024 Jun 06 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 7 | # Rewritten in Vim9 script by github user lacygoill |
Christian Brabandt | e978b45 | 2023-08-13 10:33:05 +0200 | [diff] [blame] | 8 | # Former Maintainer: Bram Moolenaar <Bram@vim.org> |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 9 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 10 | var prepended: string |
| 11 | var grepCache: dict<list<dict<any>>> |
| 12 | |
| 13 | # This function is used for the 'omnifunc' option. |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 14 | export def Complete(findstart: bool, abase: string): any # {{{1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 15 | if findstart |
| 16 | # Locate the start of the item, including ".", "->" and "[...]". |
| 17 | var line: string = getline('.') |
| 18 | var start: number = charcol('.') - 1 |
| 19 | var lastword: number = -1 |
Bram Moolenaar | e344bea | 2005-09-01 20:46:49 +0000 | [diff] [blame] | 20 | while start > 0 |
Bram Moolenaar | d5cdbeb | 2005-10-10 20:59:28 +0000 | [diff] [blame] | 21 | if line[start - 1] =~ '\w' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 22 | --start |
Bram Moolenaar | d5cdbeb | 2005-10-10 20:59:28 +0000 | [diff] [blame] | 23 | elseif line[start - 1] =~ '\.' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 24 | if lastword == -1 |
| 25 | lastword = start |
| 26 | endif |
| 27 | --start |
| 28 | elseif start > 1 && line[start - 2] == '-' |
| 29 | && line[start - 1] == '>' |
| 30 | if lastword == -1 |
| 31 | lastword = start |
| 32 | endif |
| 33 | start -= 2 |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 34 | elseif line[start - 1] == ']' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 35 | # Skip over [...]. |
| 36 | var n: number = 0 |
| 37 | --start |
| 38 | while start > 0 |
| 39 | --start |
| 40 | if line[start] == '[' |
| 41 | if n == 0 |
| 42 | break |
| 43 | endif |
| 44 | --n |
| 45 | elseif line[start] == ']' # nested [] |
| 46 | ++n |
| 47 | endif |
| 48 | endwhile |
Bram Moolenaar | e344bea | 2005-09-01 20:46:49 +0000 | [diff] [blame] | 49 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 50 | break |
Bram Moolenaar | e344bea | 2005-09-01 20:46:49 +0000 | [diff] [blame] | 51 | endif |
| 52 | endwhile |
Bram Moolenaar | d5cdbeb | 2005-10-10 20:59:28 +0000 | [diff] [blame] | 53 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 54 | # Return the column of the last word, which is going to be changed. |
| 55 | # Remember the text that comes before it in prepended. |
Bram Moolenaar | d5cdbeb | 2005-10-10 20:59:28 +0000 | [diff] [blame] | 56 | if lastword == -1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 57 | prepended = '' |
| 58 | return byteidx(line, start) |
Bram Moolenaar | d5cdbeb | 2005-10-10 20:59:28 +0000 | [diff] [blame] | 59 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 60 | prepended = line[start : lastword - 1] |
| 61 | return byteidx(line, lastword) |
Bram Moolenaar | e344bea | 2005-09-01 20:46:49 +0000 | [diff] [blame] | 62 | endif |
| 63 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 64 | # Return list of matches. |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 65 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 66 | var base: string = prepended .. abase |
Bram Moolenaar | d5cdbeb | 2005-10-10 20:59:28 +0000 | [diff] [blame] | 67 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 68 | # Don't do anything for an empty base, would result in all the tags in the |
| 69 | # tags file. |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 70 | if base == '' |
| 71 | return [] |
| 72 | endif |
| 73 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 74 | # init cache for vimgrep to empty |
| 75 | grepCache = {} |
Bram Moolenaar | 1056d98 | 2006-03-09 22:37:52 +0000 | [diff] [blame] | 76 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 77 | # Split item in words, keep empty word after "." or "->". |
| 78 | # "aa" -> ['aa'], "aa." -> ['aa', ''], "aa.bb" -> ['aa', 'bb'], etc. |
| 79 | # We can't use split, because we need to skip nested [...]. |
| 80 | # "aa[...]" -> ['aa', '[...]'], "aa.bb[...]" -> ['aa', 'bb', '[...]'], etc. |
| 81 | var items: list<string> |
| 82 | var s: number = 0 |
| 83 | var arrays: number = 0 |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 84 | while 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 85 | var e: number = base->charidx(match(base, '\.\|->\|\[', s)) |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 86 | if e < 0 |
| 87 | if s == 0 || base[s - 1] != ']' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 88 | items->add(base[s :]) |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 89 | endif |
| 90 | break |
Bram Moolenaar | d5cdbeb | 2005-10-10 20:59:28 +0000 | [diff] [blame] | 91 | endif |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 92 | if s == 0 || base[s - 1] != ']' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 93 | items->add(base[s : e - 1]) |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 94 | endif |
| 95 | if base[e] == '.' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 96 | # skip over '.' |
| 97 | s = e + 1 |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 98 | elseif base[e] == '-' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 99 | # skip over '->' |
| 100 | s = e + 2 |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 101 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 102 | # Skip over [...]. |
| 103 | var n: number = 0 |
| 104 | s = e |
| 105 | ++e |
| 106 | while e < strcharlen(base) |
| 107 | if base[e] == ']' |
| 108 | if n == 0 |
| 109 | break |
| 110 | endif |
| 111 | --n |
| 112 | elseif base[e] == '[' # nested [...] |
| 113 | ++n |
| 114 | endif |
| 115 | ++e |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 116 | endwhile |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 117 | ++e |
| 118 | items->add(base[s : e - 1]) |
| 119 | ++arrays |
| 120 | s = e |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 121 | endif |
| 122 | endwhile |
Bram Moolenaar | dd2436f | 2005-09-05 22:14:46 +0000 | [diff] [blame] | 123 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 124 | # Find the variable items[0]. |
| 125 | # 1. in current function (like with "gd") |
| 126 | # 2. in tags file(s) (like with ":tag") |
| 127 | # 3. in current file (like with "gD") |
| 128 | var res: list<dict<any>> |
| 129 | if items[0]->searchdecl(false, true) == 0 |
| 130 | # Found, now figure out the type. |
| 131 | # TODO: join previous line if it makes sense |
| 132 | var line: string = getline('.') |
| 133 | var col: number = charcol('.') |
| 134 | if line[: col - 1]->stridx(';') >= 0 |
| 135 | # Handle multiple declarations on the same line. |
| 136 | var col2: number = col - 1 |
Bram Moolenaar | 8c8de83 | 2008-06-24 22:58:06 +0000 | [diff] [blame] | 137 | while line[col2] != ';' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 138 | --col2 |
Bram Moolenaar | 8c8de83 | 2008-06-24 22:58:06 +0000 | [diff] [blame] | 139 | endwhile |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 140 | line = line[col2 + 1 :] |
| 141 | col -= col2 |
Bram Moolenaar | 8c8de83 | 2008-06-24 22:58:06 +0000 | [diff] [blame] | 142 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 143 | if line[: col - 1]->stridx(',') >= 0 |
| 144 | # Handle multiple declarations on the same line in a function |
| 145 | # declaration. |
| 146 | var col2: number = col - 1 |
Bram Moolenaar | 8c8de83 | 2008-06-24 22:58:06 +0000 | [diff] [blame] | 147 | while line[col2] != ',' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 148 | --col2 |
Bram Moolenaar | 8c8de83 | 2008-06-24 22:58:06 +0000 | [diff] [blame] | 149 | endwhile |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 150 | if line[col2 + 1 : col - 1] =~ ' *[^ ][^ ]* *[^ ]' |
| 151 | line = line[col2 + 1 :] |
| 152 | col -= col2 |
Bram Moolenaar | 8c8de83 | 2008-06-24 22:58:06 +0000 | [diff] [blame] | 153 | endif |
| 154 | endif |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 155 | if len(items) == 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 156 | # Completing one word and it's a local variable: May add '[', '.' or |
| 157 | # '->'. |
| 158 | var match: string = items[0] |
| 159 | var kind: string = 'v' |
| 160 | if match(line, '\<' .. match .. '\s*\[') > 0 |
| 161 | match ..= '[' |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 162 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 163 | res = line[: col - 1]->Nextitem([''], 0, true) |
| 164 | if len(res) > 0 |
| 165 | # There are members, thus add "." or "->". |
| 166 | if match(line, '\*[ \t(]*' .. match .. '\>') > 0 |
| 167 | match ..= '->' |
| 168 | else |
| 169 | match ..= '.' |
| 170 | endif |
| 171 | endif |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 172 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 173 | res = [{match: match, tagline: '', kind: kind, info: line}] |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 174 | elseif len(items) == arrays + 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 175 | # Completing one word and it's a local array variable: build tagline |
| 176 | # from declaration line |
| 177 | var match: string = items[0] |
| 178 | var kind: string = 'v' |
| 179 | var tagline: string = "\t/^" .. line .. '$/' |
| 180 | res = [{match: match, tagline: tagline, kind: kind, info: line}] |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 181 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 182 | # Completing "var.", "var.something", etc. |
| 183 | res = line[: col - 1]->Nextitem(items[1 :], 0, true) |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 184 | endif |
| 185 | endif |
| 186 | |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 187 | if len(items) == 1 || len(items) == arrays + 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 188 | # Only one part, no "." or "->": complete from tags file. |
| 189 | var tags: list<dict<any>> |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 190 | if len(items) == 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 191 | tags = taglist('^' .. base) |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 192 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 193 | tags = taglist('^' .. items[0] .. '$') |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 194 | endif |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 195 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 196 | tags |
| 197 | # Remove members, these can't appear without something in front. |
| 198 | ->filter((_, v: dict<any>): bool => |
| 199 | v->has_key('kind') ? v.kind != 'm' : true) |
| 200 | # Remove static matches in other files. |
| 201 | ->filter((_, v: dict<any>): bool => |
| 202 | !v->has_key('static') |
| 203 | || !v['static'] |
| 204 | || bufnr('%') == bufnr(v['filename'])) |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 205 | |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 206 | res = res->extend(tags->map((_, v: dict<any>) => Tag2item(v))) |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 207 | endif |
| 208 | |
| 209 | if len(res) == 0 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 210 | # Find the variable in the tags file(s) |
| 211 | var diclist: list<dict<any>> = taglist('^' .. items[0] .. '$') |
| 212 | # Remove members, these can't appear without something in front. |
Lars T. Kyllingstad | d9ec676 | 2024-06-06 18:37:08 +0200 | [diff] [blame] | 213 | ->filter((_, v: dict<any>): bool => |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 214 | v->has_key('kind') ? v.kind != 'm' : true) |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 215 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 216 | res = [] |
| 217 | for i: number in len(diclist)->range() |
| 218 | # New ctags has the "typeref" field. Patched version has "typename". |
| 219 | if diclist[i]->has_key('typename') |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 220 | res = res->extend(diclist[i]['typename']->StructMembers(items[1 :], true)) |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 221 | elseif diclist[i]->has_key('typeref') |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 222 | res = res->extend(diclist[i]['typeref']->StructMembers(items[1 :], true)) |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 223 | endif |
| 224 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 225 | # For a variable use the command, which must be a search pattern that |
| 226 | # shows the declaration of the variable. |
Bram Moolenaar | dd2436f | 2005-09-05 22:14:46 +0000 | [diff] [blame] | 227 | if diclist[i]['kind'] == 'v' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 228 | var line: string = diclist[i]['cmd'] |
| 229 | if line[: 1] == '/^' |
| 230 | var col: number = line->charidx(match(line, '\<' .. items[0] .. '\>')) |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 231 | res = res->extend(line[2 : col - 1]->Nextitem(items[1 :], 0, true)) |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 232 | endif |
Bram Moolenaar | dd2436f | 2005-09-05 22:14:46 +0000 | [diff] [blame] | 233 | endif |
| 234 | endfor |
| 235 | endif |
| 236 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 237 | if len(res) == 0 && items[0]->searchdecl(true) == 0 |
| 238 | # Found, now figure out the type. |
| 239 | # TODO: join previous line if it makes sense |
| 240 | var line: string = getline('.') |
| 241 | var col: number = charcol('.') |
| 242 | res = line[: col - 1]->Nextitem(items[1 :], 0, true) |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 243 | endif |
| 244 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 245 | # If the last item(s) are [...] they need to be added to the matches. |
| 246 | var last: number = len(items) - 1 |
| 247 | var brackets: string = '' |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 248 | while last >= 0 |
| 249 | if items[last][0] != '[' |
| 250 | break |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 251 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 252 | brackets = items[last] .. brackets |
| 253 | --last |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 254 | endwhile |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 255 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 256 | return res->map((_, v: dict<any>): dict<string> => Tagline2item(v, brackets)) |
| 257 | enddef |
Bram Moolenaar | dd2436f | 2005-09-05 22:14:46 +0000 | [diff] [blame] | 258 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 259 | def GetAddition( # {{{1 |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 260 | line: string, |
| 261 | match: string, |
| 262 | memarg: list<dict<any>>, |
| 263 | bracket: bool): string |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 264 | # Guess if the item is an array. |
| 265 | if bracket && match(line, match .. '\s*\[') > 0 |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 266 | return '[' |
| 267 | endif |
| 268 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 269 | # Check if the item has members. |
| 270 | if SearchMembers(memarg, [''], false)->len() > 0 |
| 271 | # If there is a '*' before the name use "->". |
| 272 | if match(line, '\*[ \t(]*' .. match .. '\>') > 0 |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 273 | return '->' |
| 274 | else |
| 275 | return '.' |
Bram Moolenaar | 280f126 | 2006-01-30 00:14:18 +0000 | [diff] [blame] | 276 | endif |
| 277 | endif |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 278 | return '' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 279 | enddef |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 280 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 281 | def Tag2item(val: dict<any>): dict<any> # {{{1 |
| 282 | # Turn the tag info "val" into an item for completion. |
| 283 | # "val" is is an item in the list returned by taglist(). |
| 284 | # If it is a variable we may add "." or "->". Don't do it for other types, |
| 285 | # such as a typedef, by not including the info that GetAddition() uses. |
| 286 | var res: dict<any> = {match: val['name']} |
Bram Moolenaar | f52c725 | 2006-02-10 23:23:57 +0000 | [diff] [blame] | 287 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 288 | res['extra'] = Tagcmd2extra(val['cmd'], val['name'], val['filename']) |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 289 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 290 | var s: string = Dict2info(val) |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 291 | if s != '' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 292 | res['info'] = s |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 293 | endif |
| 294 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 295 | res['tagline'] = '' |
| 296 | if val->has_key('kind') |
| 297 | var kind: string = val['kind'] |
| 298 | res['kind'] = kind |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 299 | if kind == 'v' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 300 | res['tagline'] = "\t" .. val['cmd'] |
| 301 | res['dict'] = val |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 302 | elseif kind == 'f' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 303 | res['match'] = val['name'] .. '(' |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 304 | endif |
| 305 | endif |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 306 | |
| 307 | return res |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 308 | enddef |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 309 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 310 | def Dict2info(dict: dict<any>): string # {{{1 |
| 311 | # Use all the items in dictionary for the "info" entry. |
| 312 | var info: string = '' |
| 313 | for k: string in dict->keys()->sort() |
| 314 | info ..= k .. repeat(' ', 10 - strlen(k)) |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 315 | if k == 'cmd' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 316 | info ..= dict['cmd'] |
| 317 | ->matchstr('/^\s*\zs.*\ze$/') |
| 318 | ->substitute('\\\(.\)', '\1', 'g') |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 319 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 320 | var dictk: any = dict[k] |
| 321 | if typename(dictk) != 'string' |
| 322 | info ..= dictk->string() |
| 323 | else |
| 324 | info ..= dictk |
| 325 | endif |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 326 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 327 | info ..= "\n" |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 328 | endfor |
| 329 | return info |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 330 | enddef |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 331 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 332 | def ParseTagline(line: string): dict<any> # {{{1 |
| 333 | # Parse a tag line and return a dictionary with items like taglist() |
| 334 | var l: list<string> = split(line, "\t") |
| 335 | var d: dict<any> |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 336 | if len(l) >= 3 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 337 | d['name'] = l[0] |
| 338 | d['filename'] = l[1] |
| 339 | d['cmd'] = l[2] |
| 340 | var n: number = 2 |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 341 | if l[2] =~ '^/' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 342 | # Find end of cmd, it may contain Tabs. |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 343 | while n < len(l) && l[n] !~ '/;"$' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 344 | ++n |
| 345 | d['cmd'] ..= ' ' .. l[n] |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 346 | endwhile |
| 347 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 348 | for i: number in range(n + 1, len(l) - 1) |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 349 | if l[i] == 'file:' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 350 | d['static'] = 1 |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 351 | elseif l[i] !~ ':' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 352 | d['kind'] = l[i] |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 353 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 354 | d[l[i]->matchstr('[^:]*')] = l[i]->matchstr(':\zs.*') |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 355 | endif |
| 356 | endfor |
| 357 | endif |
| 358 | |
| 359 | return d |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 360 | enddef |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 361 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 362 | def Tagline2item(val: dict<any>, brackets: string): dict<string> # {{{1 |
| 363 | # Turn a match item "val" into an item for completion. |
| 364 | # "val['match']" is the matching item. |
| 365 | # "val['tagline']" is the tagline in which the last part was found. |
| 366 | var line: string = val['tagline'] |
| 367 | var add: string = GetAddition(line, val['match'], [val], brackets == '') |
| 368 | var res: dict<string> = {word: val['match'] .. brackets .. add} |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 369 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 370 | if val->has_key('info') |
| 371 | # Use info from Tag2item(). |
| 372 | res['info'] = val['info'] |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 373 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 374 | # Parse the tag line and add each part to the "info" entry. |
| 375 | var s: string = ParseTagline(line)->Dict2info() |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 376 | if s != '' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 377 | res['info'] = s |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 378 | endif |
| 379 | endif |
| 380 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 381 | if val->has_key('kind') |
| 382 | res['kind'] = val['kind'] |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 383 | elseif add == '(' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 384 | res['kind'] = 'f' |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 385 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 386 | var s: string = line->matchstr('\t\(kind:\)\=\zs\S\ze\(\t\|$\)') |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 387 | if s != '' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 388 | res['kind'] = s |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 389 | endif |
| 390 | endif |
| 391 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 392 | if val->has_key('extra') |
| 393 | res['menu'] = val['extra'] |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 394 | return res |
Bram Moolenaar | 8b6144b | 2006-02-08 09:20:24 +0000 | [diff] [blame] | 395 | endif |
Bram Moolenaar | f52c725 | 2006-02-10 23:23:57 +0000 | [diff] [blame] | 396 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 397 | # Isolate the command after the tag and filename. |
| 398 | var s: string = line->matchstr('[^\t]*\t[^\t]*\t\zs\(/^.*$/\|[^\t]*\)\ze\(;"\t\|\t\|$\)') |
Bram Moolenaar | f52c725 | 2006-02-10 23:23:57 +0000 | [diff] [blame] | 399 | if s != '' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 400 | res['menu'] = s->Tagcmd2extra(val['match'], line->matchstr('[^\t]*\t\zs[^\t]*\ze\t')) |
Bram Moolenaar | f52c725 | 2006-02-10 23:23:57 +0000 | [diff] [blame] | 401 | endif |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 402 | return res |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 403 | enddef |
Bram Moolenaar | 280f126 | 2006-01-30 00:14:18 +0000 | [diff] [blame] | 404 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 405 | def Tagcmd2extra( # {{{1 |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 406 | cmd: string, |
| 407 | name: string, |
| 408 | fname: string): string |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 409 | # Turn a command from a tag line to something that is useful in the menu |
| 410 | var x: string |
| 411 | if cmd =~ '^/^' |
| 412 | # The command is a search command, useful to see what it is. |
| 413 | x = cmd |
| 414 | ->matchstr('^/^\s*\zs.*\ze$/') |
| 415 | ->substitute('\<' .. name .. '\>', '@@', '') |
| 416 | ->substitute('\\\(.\)', '\1', 'g') |
| 417 | .. ' - ' .. fname |
| 418 | elseif cmd =~ '^\d*$' |
| 419 | # The command is a line number, the file name is more useful. |
| 420 | x = fname .. ' - ' .. cmd |
Bram Moolenaar | f52c725 | 2006-02-10 23:23:57 +0000 | [diff] [blame] | 421 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 422 | # Not recognized, use command and file name. |
| 423 | x = cmd .. ' - ' .. fname |
Bram Moolenaar | f52c725 | 2006-02-10 23:23:57 +0000 | [diff] [blame] | 424 | endif |
| 425 | return x |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 426 | enddef |
Bram Moolenaar | 280f126 | 2006-01-30 00:14:18 +0000 | [diff] [blame] | 427 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 428 | def Nextitem( # {{{1 |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 429 | lead: string, |
| 430 | items: list<string>, |
| 431 | depth: number, |
| 432 | all: bool): list<dict<string>> |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 433 | # Find composing type in "lead" and match items[0] with it. |
| 434 | # Repeat this recursively for items[1], if it's there. |
| 435 | # When resolving typedefs "depth" is used to avoid infinite recursion. |
| 436 | # Return the list of matches. |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 437 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 438 | # Use the text up to the variable name and split it in tokens. |
| 439 | var tokens: list<string> = split(lead, '\s\+\|\<') |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 440 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 441 | # Try to recognize the type of the variable. This is rough guessing... |
| 442 | var res: list<dict<string>> |
| 443 | for tidx: number in len(tokens)->range() |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 444 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 445 | # Skip tokens starting with a non-ID character. |
Bram Moolenaar | 1056d98 | 2006-03-09 22:37:52 +0000 | [diff] [blame] | 446 | if tokens[tidx] !~ '^\h' |
| 447 | continue |
| 448 | endif |
| 449 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 450 | # Recognize "struct foobar" and "union foobar". |
| 451 | # Also do "class foobar" when it's C++ after all (doesn't work very well |
| 452 | # though). |
| 453 | if (tokens[tidx] == 'struct' |
| 454 | || tokens[tidx] == 'union' |
| 455 | || tokens[tidx] == 'class') |
| 456 | && tidx + 1 < len(tokens) |
| 457 | res = StructMembers(tokens[tidx] .. ':' .. tokens[tidx + 1], items, all) |
Bram Moolenaar | dd2436f | 2005-09-05 22:14:46 +0000 | [diff] [blame] | 458 | break |
| 459 | endif |
Bram Moolenaar | dd2436f | 2005-09-05 22:14:46 +0000 | [diff] [blame] | 460 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 461 | # TODO: add more reserved words |
| 462 | if ['int', 'short', 'char', 'float', |
| 463 | 'double', 'static', 'unsigned', 'extern']->index(tokens[tidx]) >= 0 |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 464 | continue |
| 465 | endif |
| 466 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 467 | # Use the tags file to find out if this is a typedef. |
| 468 | var diclist: list<dict<any>> = taglist('^' .. tokens[tidx] .. '$') |
| 469 | for tagidx: number in len(diclist)->range() |
| 470 | var item: dict<any> = diclist[tagidx] |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 471 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 472 | # New ctags has the "typeref" field. Patched version has "typename". |
| 473 | if item->has_key('typeref') |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 474 | res = res->extend(item['typeref']->StructMembers(items, all)) |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 475 | continue |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 476 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 477 | if item->has_key('typename') |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 478 | res = res->extend(item['typename']->StructMembers(items, all)) |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 479 | continue |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 480 | endif |
| 481 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 482 | # Only handle typedefs here. |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 483 | if item['kind'] != 't' |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 484 | continue |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 485 | endif |
| 486 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 487 | # Skip matches local to another file. |
| 488 | if item->has_key('static') && item['static'] |
| 489 | && bufnr('%') != bufnr(item['filename']) |
| 490 | continue |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 491 | endif |
| 492 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 493 | # For old ctags we recognize "typedef struct aaa" and |
| 494 | # "typedef union bbb" in the tags file command. |
| 495 | var cmd: string = item['cmd'] |
| 496 | var ei: number = cmd->charidx(matchend(cmd, 'typedef\s\+')) |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 497 | if ei > 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 498 | var cmdtokens: list<string> = cmd[ei :]->split('\s\+\|\<') |
| 499 | if len(cmdtokens) > 1 |
| 500 | if cmdtokens[0] == 'struct' |
| 501 | || cmdtokens[0] == 'union' |
| 502 | || cmdtokens[0] == 'class' |
| 503 | var name: string = '' |
| 504 | # Use the first identifier after the "struct" or "union" |
| 505 | for ti: number in (len(cmdtokens) - 1)->range() |
| 506 | if cmdtokens[ti] =~ '^\w' |
| 507 | name = cmdtokens[ti] |
| 508 | break |
| 509 | endif |
| 510 | endfor |
| 511 | if name != '' |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 512 | res = res->extend(StructMembers(cmdtokens[0] .. ':' .. name, items, all)) |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 513 | endif |
| 514 | elseif depth < 10 |
| 515 | # Could be "typedef other_T some_T". |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 516 | res = res->extend(cmdtokens[0]->Nextitem(items, depth + 1, all)) |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 517 | endif |
| 518 | endif |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 519 | endif |
| 520 | endfor |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 521 | if len(res) > 0 |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 522 | break |
Bram Moolenaar | dd2436f | 2005-09-05 22:14:46 +0000 | [diff] [blame] | 523 | endif |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 524 | endfor |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 525 | |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 526 | return res |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 527 | enddef |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 528 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 529 | def StructMembers( # {{{1 |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 530 | atypename: string, |
| 531 | items: list<string>, |
| 532 | all: bool): list<dict<string>> |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 533 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 534 | # Search for members of structure "typename" in tags files. |
| 535 | # Return a list with resulting matches. |
| 536 | # Each match is a dictionary with "match" and "tagline" entries. |
| 537 | # When "all" is true find all, otherwise just return 1 if there is any member. |
| 538 | |
| 539 | # Todo: What about local structures? |
| 540 | var fnames: string = tagfiles() |
| 541 | ->map((_, v: string) => escape(v, ' \#%')) |
| 542 | ->join() |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 543 | if fnames == '' |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 544 | return [] |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 545 | endif |
| 546 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 547 | var typename: string = atypename |
| 548 | var qflist: list<dict<any>> |
| 549 | var cached: number = 0 |
| 550 | var n: string |
| 551 | if !all |
| 552 | n = '1' # stop at first found match |
| 553 | if grepCache->has_key(typename) |
| 554 | qflist = grepCache[typename] |
| 555 | cached = 1 |
Bram Moolenaar | 1056d98 | 2006-03-09 22:37:52 +0000 | [diff] [blame] | 556 | endif |
Bram Moolenaar | 1f35bf9 | 2006-03-07 22:38:47 +0000 | [diff] [blame] | 557 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 558 | n = '' |
Bram Moolenaar | 1f35bf9 | 2006-03-07 22:38:47 +0000 | [diff] [blame] | 559 | endif |
Bram Moolenaar | 1056d98 | 2006-03-09 22:37:52 +0000 | [diff] [blame] | 560 | if !cached |
| 561 | while 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 562 | execute 'silent! keepjumps noautocmd ' |
| 563 | .. n .. 'vimgrep ' .. '/\t' .. typename .. '\(\t\|$\)/j ' |
| 564 | .. fnames |
Bram Moolenaar | 1056d98 | 2006-03-09 22:37:52 +0000 | [diff] [blame] | 565 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 566 | qflist = getqflist() |
| 567 | if len(qflist) > 0 || match(typename, '::') < 0 |
| 568 | break |
Bram Moolenaar | 1056d98 | 2006-03-09 22:37:52 +0000 | [diff] [blame] | 569 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 570 | # No match for "struct:context::name", remove "context::" and try again. |
| 571 | typename = typename->substitute(':[^:]*::', ':', '') |
Bram Moolenaar | 1056d98 | 2006-03-09 22:37:52 +0000 | [diff] [blame] | 572 | endwhile |
| 573 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 574 | if !all |
| 575 | # Store the result to be able to use it again later. |
| 576 | grepCache[typename] = qflist |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 577 | endif |
Bram Moolenaar | 1056d98 | 2006-03-09 22:37:52 +0000 | [diff] [blame] | 578 | endif |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 579 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 580 | # Skip over [...] items |
| 581 | var idx: number = 0 |
| 582 | var target: string |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 583 | while 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 584 | if idx >= len(items) |
| 585 | target = '' # No further items, matching all members |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 586 | break |
| 587 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 588 | if items[idx][0] != '[' |
| 589 | target = items[idx] |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 590 | break |
| 591 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 592 | ++idx |
Bram Moolenaar | 20aac6c | 2018-09-02 21:07:30 +0200 | [diff] [blame] | 593 | endwhile |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 594 | # Put matching members in matches[]. |
| 595 | var matches: list<dict<string>> |
| 596 | for l: dict<any> in qflist |
| 597 | var memb: string = l['text']->matchstr('[^\t]*') |
| 598 | if memb =~ '^' .. target |
| 599 | # Skip matches local to another file. |
| 600 | if match(l['text'], "\tfile:") < 0 |
| 601 | || bufnr('%') == l['text']->matchstr('\t\zs[^\t]*')->bufnr() |
| 602 | var item: dict<string> = {match: memb, tagline: l['text']} |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 603 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 604 | # Add the kind of item. |
| 605 | var s: string = l['text']->matchstr('\t\(kind:\)\=\zs\S\ze\(\t\|$\)') |
| 606 | if s != '' |
| 607 | item['kind'] = s |
| 608 | if s == 'f' |
| 609 | item['match'] = memb .. '(' |
| 610 | endif |
| 611 | endif |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 612 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 613 | matches->add(item) |
Bram Moolenaar | eb94e55 | 2006-03-11 21:35:11 +0000 | [diff] [blame] | 614 | endif |
Bram Moolenaar | a4a0838 | 2005-09-09 19:52:02 +0000 | [diff] [blame] | 615 | endif |
Bram Moolenaar | dd2436f | 2005-09-05 22:14:46 +0000 | [diff] [blame] | 616 | endfor |
| 617 | |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 618 | if len(matches) > 0 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 619 | # Skip over next [...] items |
| 620 | ++idx |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 621 | while 1 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 622 | if idx >= len(items) |
| 623 | return matches # No further items, return the result. |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 624 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 625 | if items[idx][0] != '[' |
| 626 | break |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 627 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 628 | ++idx |
Bram Moolenaar | 0e5bd96 | 2006-02-04 00:59:56 +0000 | [diff] [blame] | 629 | endwhile |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 630 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 631 | # More items following. For each of the possible members find the |
| 632 | # matching following members. |
| 633 | return SearchMembers(matches, items[idx :], all) |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 634 | endif |
| 635 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 636 | # Failed to find anything. |
Bram Moolenaar | caa0fcf | 2005-09-07 21:21:14 +0000 | [diff] [blame] | 637 | return [] |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 638 | enddef |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 639 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 640 | def SearchMembers( # {{{1 |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 641 | matches: list<dict<any>>, |
| 642 | items: list<string>, |
| 643 | all: bool): list<dict<string>> |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 644 | |
| 645 | # For matching members, find matches for following items. |
| 646 | # When "all" is true find all, otherwise just return 1 if there is any member. |
| 647 | var res: list<dict<string>> |
| 648 | for i: number in len(matches)->range() |
| 649 | var typename: string = '' |
| 650 | var line: string |
| 651 | if matches[i]->has_key('dict') |
| 652 | if matches[i]['dict']->has_key('typename') |
| 653 | typename = matches[i]['dict']['typename'] |
| 654 | elseif matches[i]['dict']->has_key('typeref') |
| 655 | typename = matches[i]['dict']['typeref'] |
Bram Moolenaar | 280f126 | 2006-01-30 00:14:18 +0000 | [diff] [blame] | 656 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 657 | line = "\t" .. matches[i]['dict']['cmd'] |
Bram Moolenaar | 280f126 | 2006-01-30 00:14:18 +0000 | [diff] [blame] | 658 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 659 | line = matches[i]['tagline'] |
| 660 | var eb: number = matchend(line, '\ttypename:') |
| 661 | var e: number = charidx(line, eb) |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 662 | if e < 0 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 663 | eb = matchend(line, '\ttyperef:') |
| 664 | e = charidx(line, eb) |
Bram Moolenaar | 76b92b2 | 2006-03-24 22:46:53 +0000 | [diff] [blame] | 665 | endif |
Bram Moolenaar | 280f126 | 2006-01-30 00:14:18 +0000 | [diff] [blame] | 666 | if e > 0 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 667 | # Use typename field |
| 668 | typename = line->matchstr('[^\t]*', eb) |
Bram Moolenaar | 280f126 | 2006-01-30 00:14:18 +0000 | [diff] [blame] | 669 | endif |
| 670 | endif |
Bram Moolenaar | 1f35bf9 | 2006-03-07 22:38:47 +0000 | [diff] [blame] | 671 | |
Bram Moolenaar | 280f126 | 2006-01-30 00:14:18 +0000 | [diff] [blame] | 672 | if typename != '' |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 673 | res = res->extend(StructMembers(typename, items, all)) |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 674 | else |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 675 | # Use the search command (the declaration itself). |
| 676 | var sb: number = line->match('\t\zs/^') |
| 677 | var s: number = charidx(line, sb) |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 678 | if s > 0 |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 679 | var e: number = line |
| 680 | ->charidx(match(line, '\<' .. matches[i]['match'] .. '\>', sb)) |
| 681 | if e > 0 |
Bram Moolenaar | c4573eb | 2022-01-31 15:40:56 +0000 | [diff] [blame] | 682 | res = res->extend(line[s : e - 1]->Nextitem(items, 0, all)) |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 683 | endif |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 684 | endif |
| 685 | endif |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 686 | if !all && len(res) > 0 |
Bram Moolenaar | 1f35bf9 | 2006-03-07 22:38:47 +0000 | [diff] [blame] | 687 | break |
| 688 | endif |
Bram Moolenaar | f75a963 | 2005-09-13 21:20:47 +0000 | [diff] [blame] | 689 | endfor |
| 690 | return res |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 691 | enddef |
| 692 | #}}}1 |
Bram Moolenaar | b6b046b | 2011-12-30 13:11:27 +0100 | [diff] [blame] | 693 | |
Bram Moolenaar | a4d131d | 2021-12-27 21:33:07 +0000 | [diff] [blame] | 694 | # vim: noet sw=2 sts=2 |