Mercurial > vim
comparison src/scriptfile.c @ 27043:15f40772e10a v8.2.4050
patch 8.2.4050: Vim9: need to prefix every item in an autoload script
Commit: https://github.com/vim/vim/commit/dc4451df61a6aa12a0661817b7094fb32f09e11d
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jan 9 21:36:37 2022 +0000
patch 8.2.4050: Vim9: need to prefix every item in an autoload script
Problem: Vim9: need to prefix every item in an autoload script.
Solution: First step in supporting "vim9script autoload" and "import
autoload".
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 09 Jan 2022 22:45:04 +0100 |
parents | c9474ae175f4 |
children | d31bd8607975 |
comparison
equal
deleted
inserted
replaced
27042:8fc14d120630 | 27043:15f40772e10a |
---|---|
237 source_callback(char_u *fname, void *cookie) | 237 source_callback(char_u *fname, void *cookie) |
238 { | 238 { |
239 (void)do_source(fname, FALSE, DOSO_NONE, cookie); | 239 (void)do_source(fname, FALSE, DOSO_NONE, cookie); |
240 } | 240 } |
241 | 241 |
242 #ifdef FEAT_EVAL | |
243 /* | |
244 * Find an already loaded script "name". | |
245 * If found returns its script ID. If not found returns -1. | |
246 */ | |
247 static int | |
248 find_script_by_name(char_u *name) | |
249 { | |
250 int sid; | |
251 scriptitem_T *si; | |
252 | |
253 for (sid = script_items.ga_len; sid > 0; --sid) | |
254 { | |
255 // We used to check inode here, but that doesn't work: | |
256 // - If a script is edited and written, it may get a different | |
257 // inode number, even though to the user it is the same script. | |
258 // - If a script is deleted and another script is written, with a | |
259 // different name, the inode may be re-used. | |
260 si = SCRIPT_ITEM(sid); | |
261 if (si->sn_name != NULL && fnamecmp(si->sn_name, name) == 0) | |
262 return sid; | |
263 } | |
264 return -1; | |
265 } | |
266 | |
267 /* | |
268 * Add a new scriptitem with all items initialized. | |
269 * When running out of memory "error" is set to FAIL. | |
270 * Returns the script ID. | |
271 */ | |
272 static int | |
273 get_new_scriptitem(int *error) | |
274 { | |
275 static scid_T last_current_SID = 0; | |
276 int sid = ++last_current_SID; | |
277 scriptitem_T *si; | |
278 | |
279 if (ga_grow(&script_items, (int)(sid - script_items.ga_len)) == FAIL) | |
280 { | |
281 *error = FAIL; | |
282 return sid; | |
283 } | |
284 while (script_items.ga_len < sid) | |
285 { | |
286 si = ALLOC_CLEAR_ONE(scriptitem_T); | |
287 if (si == NULL) | |
288 { | |
289 *error = FAIL; | |
290 return sid; | |
291 } | |
292 ++script_items.ga_len; | |
293 SCRIPT_ITEM(script_items.ga_len) = si; | |
294 si->sn_name = NULL; | |
295 si->sn_version = 1; | |
296 | |
297 // Allocate the local script variables to use for this script. | |
298 new_script_vars(script_items.ga_len); | |
299 ga_init2(&si->sn_var_vals, sizeof(svar_T), 10); | |
300 hash_init(&si->sn_all_vars.dv_hashtab); | |
301 ga_init2(&si->sn_imports, sizeof(imported_T), 10); | |
302 ga_init2(&si->sn_type_list, sizeof(type_T), 10); | |
303 # ifdef FEAT_PROFILE | |
304 si->sn_prof_on = FALSE; | |
305 # endif | |
306 } | |
307 | |
308 // Used to check script variable index is still valid. | |
309 si->sn_script_seq = current_sctx.sc_seq; | |
310 | |
311 return sid; | |
312 } | |
313 | |
314 static void | |
315 find_script_callback(char_u *fname, void *cookie) | |
316 { | |
317 int sid; | |
318 int error = OK; | |
319 int *ret_sid = cookie; | |
320 | |
321 sid = find_script_by_name(fname); | |
322 if (sid < 0) | |
323 { | |
324 // script does not exist yet, create a new scriptitem | |
325 sid = get_new_scriptitem(&error); | |
326 if (error == OK) | |
327 { | |
328 scriptitem_T *si = SCRIPT_ITEM(sid); | |
329 | |
330 si->sn_name = vim_strsave(fname); | |
331 si->sn_state = SN_STATE_NOT_LOADED; | |
332 } | |
333 } | |
334 *ret_sid = sid; | |
335 } | |
336 #endif | |
337 | |
242 /* | 338 /* |
243 * Find the file "name" in all directories in "path" and invoke | 339 * Find the file "name" in all directories in "path" and invoke |
244 * "callback(fname, cookie)". | 340 * "callback(fname, cookie)". |
245 * "name" can contain wildcards. | 341 * "name" can contain wildcards. |
246 * When "flags" has DIP_ALL: source all files, otherwise only the first one. | 342 * When "flags" has DIP_ALL: source all files, otherwise only the first one. |
453 { | 549 { |
454 return source_in_path(p_rtp, name, flags, NULL); | 550 return source_in_path(p_rtp, name, flags, NULL); |
455 } | 551 } |
456 | 552 |
457 /* | 553 /* |
458 * Just like source_runtime(), but use "path" instead of 'runtimepath'. | 554 * Just like source_runtime(), but use "path" instead of 'runtimepath' |
555 * and return the script ID in "ret_sid". | |
459 */ | 556 */ |
460 int | 557 int |
461 source_in_path(char_u *path, char_u *name, int flags, int *ret_sid) | 558 source_in_path(char_u *path, char_u *name, int flags, int *ret_sid) |
462 { | 559 { |
463 return do_in_path_and_pp(path, name, flags, source_callback, ret_sid); | 560 return do_in_path_and_pp(path, name, flags, source_callback, ret_sid); |
464 } | 561 } |
465 | 562 |
466 | |
467 #if defined(FEAT_EVAL) || defined(PROTO) | 563 #if defined(FEAT_EVAL) || defined(PROTO) |
564 | |
565 /* | |
566 * Find "name" in 'runtimepath'. If found a new scriptitem is created for it | |
567 * and it's script ID is returned. | |
568 * If not found returns -1. | |
569 */ | |
570 int | |
571 find_script_in_rtp(char_u *name) | |
572 { | |
573 int sid = -1; | |
574 | |
575 (void)do_in_path_and_pp(p_rtp, name, DIP_NOAFTER, | |
576 find_script_callback, &sid); | |
577 return sid; | |
578 } | |
468 | 579 |
469 /* | 580 /* |
470 * Expand wildcards in "pat" and invoke do_source() for each match. | 581 * Expand wildcards in "pat" and invoke do_source() for each match. |
471 */ | 582 */ |
472 static void | 583 static void |
1125 char_u *fname_exp; | 1236 char_u *fname_exp; |
1126 char_u *firstline = NULL; | 1237 char_u *firstline = NULL; |
1127 int retval = FAIL; | 1238 int retval = FAIL; |
1128 sctx_T save_current_sctx; | 1239 sctx_T save_current_sctx; |
1129 #ifdef FEAT_EVAL | 1240 #ifdef FEAT_EVAL |
1130 static scid_T last_current_SID = 0; | |
1131 static int last_current_SID_seq = 0; | 1241 static int last_current_SID_seq = 0; |
1132 funccal_entry_T funccalp_entry; | 1242 funccal_entry_T funccalp_entry; |
1133 int save_debug_break_level = debug_break_level; | 1243 int save_debug_break_level = debug_break_level; |
1134 int sid; | 1244 int sid; |
1135 scriptitem_T *si = NULL; | 1245 scriptitem_T *si = NULL; |
1159 } | 1269 } |
1160 #ifdef FEAT_EVAL | 1270 #ifdef FEAT_EVAL |
1161 estack_compiling = FALSE; | 1271 estack_compiling = FALSE; |
1162 | 1272 |
1163 // See if we loaded this script before. | 1273 // See if we loaded this script before. |
1164 for (sid = script_items.ga_len; sid > 0; --sid) | 1274 sid = find_script_by_name(fname_exp); |
1165 { | |
1166 // We used to check inode here, but that doesn't work: | |
1167 // - If a script is edited and written, it may get a different | |
1168 // inode number, even though to the user it is the same script. | |
1169 // - If a script is deleted and another script is written, with a | |
1170 // different name, the inode may be re-used. | |
1171 si = SCRIPT_ITEM(sid); | |
1172 if (si->sn_name != NULL && fnamecmp(si->sn_name, fname_exp) == 0) | |
1173 // Found it! | |
1174 break; | |
1175 } | |
1176 if (sid > 0 && ret_sid != NULL) | 1275 if (sid > 0 && ret_sid != NULL) |
1177 { | 1276 { |
1178 // Already loaded and no need to load again, return here. | 1277 // Already loaded and no need to load again, return here. |
1179 *ret_sid = sid; | 1278 *ret_sid = sid; |
1180 retval = OK; | 1279 retval = OK; |
1316 int todo; | 1415 int todo; |
1317 hashitem_T *hi; | 1416 hashitem_T *hi; |
1318 dictitem_T *di; | 1417 dictitem_T *di; |
1319 | 1418 |
1320 // loading the same script again | 1419 // loading the same script again |
1321 si->sn_state = SN_STATE_RELOAD; | |
1322 current_sctx.sc_sid = sid; | 1420 current_sctx.sc_sid = sid; |
1323 | 1421 si = SCRIPT_ITEM(sid); |
1324 // Script-local variables remain but "const" can be set again. | 1422 if (si->sn_state == SN_STATE_NOT_LOADED) |
1325 // In Vim9 script variables will be cleared when "vim9script" is | 1423 { |
1326 // encountered without the "noclear" argument. | 1424 // this script was found but not loaded yet |
1327 ht = &SCRIPT_VARS(sid); | 1425 si->sn_state = SN_STATE_NEW; |
1328 todo = (int)ht->ht_used; | 1426 } |
1329 for (hi = ht->ht_array; todo > 0; ++hi) | 1427 else |
1330 if (!HASHITEM_EMPTY(hi)) | 1428 { |
1331 { | 1429 si->sn_state = SN_STATE_RELOAD; |
1332 --todo; | 1430 |
1333 di = HI2DI(hi); | 1431 // Script-local variables remain but "const" can be set again. |
1334 di->di_flags |= DI_FLAGS_RELOAD; | 1432 // In Vim9 script variables will be cleared when "vim9script" is |
1335 } | 1433 // encountered without the "noclear" argument. |
1336 // imports can be redefined once | 1434 ht = &SCRIPT_VARS(sid); |
1337 mark_imports_for_reload(sid); | 1435 todo = (int)ht->ht_used; |
1338 | 1436 for (hi = ht->ht_array; todo > 0; ++hi) |
1339 // reset version, "vim9script" may have been added or removed. | 1437 if (!HASHITEM_EMPTY(hi)) |
1340 si->sn_version = 1; | 1438 { |
1439 --todo; | |
1440 di = HI2DI(hi); | |
1441 di->di_flags |= DI_FLAGS_RELOAD; | |
1442 } | |
1443 // imports can be redefined once | |
1444 mark_imports_for_reload(sid); | |
1445 | |
1446 // reset version, "vim9script" may have been added or removed. | |
1447 si->sn_version = 1; | |
1448 } | |
1341 } | 1449 } |
1342 else | 1450 else |
1343 { | 1451 { |
1344 // It's new, generate a new SID. | 1452 int error = OK; |
1345 current_sctx.sc_sid = ++last_current_SID; | 1453 |
1346 if (ga_grow(&script_items, | 1454 // It's new, generate a new SID and initialize the scriptitem. |
1347 (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL) | 1455 current_sctx.sc_sid = get_new_scriptitem(&error); |
1456 if (error == FAIL) | |
1348 goto almosttheend; | 1457 goto almosttheend; |
1349 while (script_items.ga_len < current_sctx.sc_sid) | |
1350 { | |
1351 si = ALLOC_CLEAR_ONE(scriptitem_T); | |
1352 if (si == NULL) | |
1353 goto almosttheend; | |
1354 ++script_items.ga_len; | |
1355 SCRIPT_ITEM(script_items.ga_len) = si; | |
1356 si->sn_name = NULL; | |
1357 si->sn_version = 1; | |
1358 | |
1359 // Allocate the local script variables to use for this script. | |
1360 new_script_vars(script_items.ga_len); | |
1361 ga_init2(&si->sn_var_vals, sizeof(svar_T), 10); | |
1362 hash_init(&si->sn_all_vars.dv_hashtab); | |
1363 ga_init2(&si->sn_imports, sizeof(imported_T), 10); | |
1364 ga_init2(&si->sn_type_list, sizeof(type_T), 10); | |
1365 # ifdef FEAT_PROFILE | |
1366 si->sn_prof_on = FALSE; | |
1367 # endif | |
1368 } | |
1369 si = SCRIPT_ITEM(current_sctx.sc_sid); | 1458 si = SCRIPT_ITEM(current_sctx.sc_sid); |
1370 si->sn_name = fname_exp; | 1459 si->sn_name = fname_exp; |
1371 fname_exp = vim_strsave(si->sn_name); // used for autocmd | 1460 fname_exp = vim_strsave(si->sn_name); // used for autocmd |
1372 if (ret_sid != NULL) | 1461 if (ret_sid != NULL) |
1373 *ret_sid = current_sctx.sc_sid; | 1462 *ret_sid = current_sctx.sc_sid; |
1374 | 1463 |
1375 // Remember the "is_vimrc" flag for when the file is sourced again. | 1464 // Remember the "is_vimrc" flag for when the file is sourced again. |
1376 si->sn_is_vimrc = is_vimrc; | 1465 si->sn_is_vimrc = is_vimrc; |
1377 | |
1378 // Used to check script variable index is still valid. | |
1379 si->sn_script_seq = current_sctx.sc_seq; | |
1380 } | 1466 } |
1381 | 1467 |
1382 # ifdef FEAT_PROFILE | 1468 # ifdef FEAT_PROFILE |
1383 if (do_profiling == PROF_YES) | 1469 if (do_profiling == PROF_YES) |
1384 { | 1470 { |
2029 && ((source_cookie_T *)getline_cookie( | 2115 && ((source_cookie_T *)getline_cookie( |
2030 fgetline, cookie))->finished); | 2116 fgetline, cookie))->finished); |
2031 } | 2117 } |
2032 | 2118 |
2033 /* | 2119 /* |
2120 * Find the path of a script below the "autoload" directory. | |
2121 * Returns NULL if there is no "/autoload/" in the script name. | |
2122 */ | |
2123 char_u * | |
2124 script_name_after_autoload(scriptitem_T *si) | |
2125 { | |
2126 char_u *p = si->sn_name; | |
2127 char_u *res = NULL; | |
2128 | |
2129 for (;;) | |
2130 { | |
2131 char_u *n = (char_u *)strstr((char *)p, "autoload"); | |
2132 | |
2133 if (n == NULL) | |
2134 break; | |
2135 if (n > p && vim_ispathsep(n[-1]) && vim_ispathsep(n[8])) | |
2136 res = n + 9; | |
2137 p = n + 8; | |
2138 } | |
2139 return res; | |
2140 } | |
2141 | |
2142 /* | |
2143 * If in a Vim9 autoload script return "name" with the autoload prefix for the | |
2144 * script. If successful "name" is freed, the returned name is allocated. | |
2145 * Otherwise it returns "name" unmodified. | |
2146 */ | |
2147 char_u * | |
2148 may_prefix_autoload(char_u *name) | |
2149 { | |
2150 if (SCRIPT_ID_VALID(current_sctx.sc_sid)) | |
2151 { | |
2152 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); | |
2153 | |
2154 if (si->sn_is_autoload) | |
2155 { | |
2156 char_u *p = script_name_after_autoload(si); | |
2157 | |
2158 if (p != NULL) | |
2159 { | |
2160 char_u *tail = vim_strsave(p); | |
2161 | |
2162 if (tail != NULL) | |
2163 { | |
2164 for (p = tail; *p != NUL; p += mb_ptr2len(p)) | |
2165 { | |
2166 if (vim_ispathsep(*p)) | |
2167 *p = '#'; | |
2168 else if (STRCMP(p, ".vim")) | |
2169 { | |
2170 size_t len = (p - tail) + STRLEN(name) + 2; | |
2171 char_u *res = alloc(len); | |
2172 | |
2173 if (res == NULL) | |
2174 break; | |
2175 *p = NUL; | |
2176 vim_snprintf((char *)res, len, "%s#%s", tail, name); | |
2177 vim_free(name); | |
2178 vim_free(tail); | |
2179 return res; | |
2180 } | |
2181 } | |
2182 } | |
2183 // did not find ".vim" at the end | |
2184 vim_free(tail); | |
2185 } | |
2186 } | |
2187 } | |
2188 return name; | |
2189 } | |
2190 | |
2191 /* | |
2034 * Return the autoload script name for a function or variable name. | 2192 * Return the autoload script name for a function or variable name. |
2035 * Returns NULL when out of memory. | 2193 * Returns NULL when out of memory. |
2036 * Caller must make sure that "name" contains AUTOLOAD_CHAR. | 2194 * Caller must make sure that "name" contains AUTOLOAD_CHAR. |
2037 */ | 2195 */ |
2038 char_u * | 2196 char_u * |