diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2015-10-16 01:54:07 -0400 |
|---|---|---|
| committer | Justin M. Keyes <justinkz@gmail.com> | 2015-10-16 01:54:07 -0400 |
| commit | 3a970e57dfd48f090f8ccc21567b7974e13d4c68 (patch) | |
| tree | 5aeaf1cd7a85c17b29276eee88e9881f56ea134c /src | |
| parent | a3f048ee06dea15490d7b874d295c3fc850cdc51 (diff) | |
| parent | db6cba7d5759e02379005702c7a9d760137f4389 (diff) | |
| download | rneovim-3a970e57dfd48f090f8ccc21567b7974e13d4c68.tar.gz rneovim-3a970e57dfd48f090f8ccc21567b7974e13d4c68.tar.bz2 rneovim-3a970e57dfd48f090f8ccc21567b7974e13d4c68.zip | |
Merge pull request #2506 from ZyX-I/shada
Replace viminfo with ShaDa files
Diffstat (limited to 'src')
47 files changed, 5986 insertions, 2158 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 0485fbacd2..7a0b5191d7 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -597,7 +597,7 @@ static void init_type_metadata(Dictionary *metadata) } /// Creates a deep clone of an object -static Object copy_object(Object obj) +Object copy_object(Object obj) { switch (obj.type) { case kObjectTypeNil: diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index f29deb53f9..a0f14ac7a4 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -69,6 +69,8 @@ #define ADD(array, item) \ kv_push(Object, array, item) +#define STATIC_CSTR_AS_STRING(s) ((String) {.data = s, .size = sizeof(s) - 1}) + // Helpers used by the generated msgpack-rpc api wrappers #define api_init_boolean #define api_init_integer diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index af801c6f1a..3d8a75febd 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -84,7 +84,7 @@ return { 'User', -- user defined autocommand 'VimEnter', -- after starting Vim 'VimLeave', -- before exiting Vim - 'VimLeavePre', -- before exiting Vim and writing .viminfo + 'VimLeavePre', -- before exiting Vim and writing ShaDa file 'VimResized', -- after Vim window was resized 'WinEnter', -- after entering a window 'WinLeave', -- before leaving a window diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index b212e75283..b3eba4f5f6 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -73,6 +73,7 @@ #include "nvim/undo.h" #include "nvim/version.h" #include "nvim/window.h" +#include "nvim/shada.h" #include "nvim/os/os.h" #include "nvim/os/time.h" #include "nvim/os/input.h" @@ -555,9 +556,21 @@ static void free_buffer(buf_T *buf) free_buffer_stuff(buf, TRUE); unref_var_dict(buf->b_vars); aubuflocal_remove(buf); + dict_unref(buf->additional_data); + clear_fmark(&buf->b_last_cursor); + clear_fmark(&buf->b_last_insert); + clear_fmark(&buf->b_last_change); + for (size_t i = 0; i < NMARKS; i++) { + free_fmark(buf->b_namedm[i]); + } + for (int i = 0; i < buf->b_changelistlen; i++) { + free_fmark(buf->b_changelist[i]); + } if (autocmd_busy) { // Do not free the buffer structure while autocommands are executing, // it's still needed. Free it when autocmd_busy is reset. + memset(&buf->b_namedm[0], 0, sizeof(buf->b_namedm)); + memset(&buf->b_changelist[0], 0, sizeof(buf->b_changelist)); buf->b_next = au_pending_free_buf; au_pending_free_buf = buf; } else { @@ -1978,12 +1991,18 @@ buflist_nr2name ( fullname ? buf->b_ffname : buf->b_fname); } -/* - * Set the "lnum" and "col" for the buffer "buf" and the current window. - * When "copy_options" is TRUE save the local window option values. - * When "lnum" is 0 only do the options. - */ -static void buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options) +/// Set the line and column numbers for the given buffer and window +/// +/// @param[in,out] buf Buffer for which line and column are set. +/// @param[in,out] win Window for which line and column are set. +/// @param[in] lnum Line number to be set. If it is zero then only +/// options are touched. +/// @param[in] col Column number to be set. +/// @param[in] copy_options If true save the local window option values. +void buflist_setfpos(buf_T *const buf, win_T *const win, + linenr_T lnum, colnr_T col, + bool copy_options) + FUNC_ATTR_NONNULL_ALL { wininfo_T *wip; @@ -4164,93 +4183,6 @@ chk_modeline ( return retval; } -int read_viminfo_bufferlist(vir_T *virp, int writing) -{ - char_u *tab; - linenr_T lnum; - colnr_T col; - buf_T *buf; - char_u *sfname; - char_u *xline; - - /* Handle long line and escaped characters. */ - xline = viminfo_readstring(virp, 1, FALSE); - - /* don't read in if there are files on the command-line or if writing: */ - if (xline != NULL && !writing && ARGCOUNT == 0 - && find_viminfo_parameter('%') != NULL) { - /* Format is: <fname> Tab <lnum> Tab <col>. - * Watch out for a Tab in the file name, work from the end. */ - lnum = 0; - col = 0; - tab = vim_strrchr(xline, '\t'); - if (tab != NULL) { - *tab++ = '\0'; - col = (colnr_T)atoi((char *)tab); - tab = vim_strrchr(xline, '\t'); - if (tab != NULL) { - *tab++ = '\0'; - lnum = atol((char *)tab); - } - } - - /* Expand "~/" in the file name at "line + 1" to a full path. - * Then try shortening it by comparing with the current directory */ - expand_env(xline, NameBuff, MAXPATHL); - sfname = path_shorten_fname_if_possible(NameBuff); - - buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED); - if (buf != NULL) { /* just in case... */ - buf->b_last_cursor.lnum = lnum; - buf->b_last_cursor.col = col; - buflist_setfpos(buf, curwin, lnum, col, FALSE); - } - } - xfree(xline); - - return viminfo_readline(virp); -} - -void write_viminfo_bufferlist(FILE *fp) -{ - char_u *line; - int max_buffers; - - if (find_viminfo_parameter('%') == NULL) - return; - - /* Without a number -1 is returned: do all buffers. */ - max_buffers = get_viminfo_parameter('%'); - - /* Allocate room for the file name, lnum and col. */ -#define LINE_BUF_LEN (MAXPATHL + 40) - line = xmalloc(LINE_BUF_LEN); - - FOR_ALL_TAB_WINDOWS(tp, win) { - set_last_cursor(win); - } - - fputs(_("\n# Buffer list:\n"), fp); - FOR_ALL_BUFFERS(buf) { - if (buf->b_fname == NULL - || !buf->b_p_bl - || bt_quickfix(buf) - || removable(buf->b_ffname)) - continue; - - if (max_buffers-- == 0) - break; - putc('%', fp); - home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE); - vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%" PRId64 "\t%d", - (int64_t)buf->b_last_cursor.lnum, - buf->b_last_cursor.col); - viminfo_writestring(fp, line); - } - xfree(line); -} - - /* * Return special buffer name. * Returns NULL when the buffer has a normal file name. diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 98fbef9c87..3eabb7ee43 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -327,15 +327,6 @@ typedef struct { bool vc_fail; /* fail for invalid char, don't use '?' */ } vimconv_T; -/* - * Structure used for reading from the viminfo file. - */ -typedef struct { - char_u *vir_line; /* text of the current line */ - FILE *vir_fd; /* file descriptor */ - vimconv_T vir_conv; /* encoding conversion */ -} vir_T; - #define CONV_NONE 0 #define CONV_TO_UTF8 1 #define CONV_9_TO_UTF8 2 @@ -515,21 +506,21 @@ struct file_buffer { uint64_t b_orig_size; /* size of original file in bytes */ int b_orig_mode; /* mode of original file */ - pos_T b_namedm[NMARKS]; /* current named marks (mark.c) */ + fmark_T b_namedm[NMARKS]; /* current named marks (mark.c) */ /* These variables are set when VIsual_active becomes FALSE */ visualinfo_T b_visual; int b_visual_mode_eval; /* b_visual.vi_mode for visualmode() */ - pos_T b_last_cursor; /* cursor position when last unloading this - buffer */ - pos_T b_last_insert; /* where Insert mode was left */ - pos_T b_last_change; /* position of last change: '. mark */ + fmark_T b_last_cursor; // cursor position when last unloading this + // buffer + fmark_T b_last_insert; // where Insert mode was left + fmark_T b_last_change; // position of last change: '. mark /* * the changelist contains old change positions */ - pos_T b_changelist[JUMPLISTSIZE]; + fmark_T b_changelist[JUMPLISTSIZE]; int b_changelistlen; /* number of active entries */ bool b_new_change; /* set by u_savecommon() */ @@ -553,7 +544,7 @@ struct file_buffer { pos_T b_op_start_orig; // used for Insstart_orig pos_T b_op_end; - bool b_marks_read; /* Have we read viminfo marks yet? */ + bool b_marks_read; /* Have we read ShaDa marks yet? */ /* * The following only used in undo.c. @@ -757,6 +748,8 @@ struct file_buffer { signlist_T *b_signlist; /* list of signs to draw */ Terminal *terminal; // Terminal instance associated with the buffer + + dict_T *additional_data; // Additional data from shada file if any. }; /* diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 427623e052..310191ba06 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -60,6 +60,7 @@ #include "nvim/undo.h" #include "nvim/window.h" #include "nvim/event/loop.h" +#include "nvim/mark.h" #include "nvim/os/input.h" #include "nvim/os/time.h" @@ -6991,8 +6992,9 @@ ins_esc ( curwin->w_set_curswant = TRUE; /* Remember the last Insert position in the '^ mark. */ - if (!cmdmod.keepjumps) - curbuf->b_last_insert = curwin->w_cursor; + if (!cmdmod.keepjumps) { + RESET_FMARK(&curbuf->b_last_insert, curwin->w_cursor, curbuf->b_fnum); + } /* * The cursor should end up on the last inserted character. diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 65afd19bbe..d02348028a 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -108,18 +108,6 @@ function/variable names. */ /* - * In a hashtab item "hi_key" points to "di_key" in a dictitem. - * This avoids adding a pointer to the hashtab item. - * DI2HIKEY() converts a dictitem pointer to a hashitem key pointer. - * HIKEY2DI() converts a hashitem key pointer to a dictitem pointer. - * HI2DI() converts a hashitem pointer to a dictitem pointer. - */ -static dictitem_T dumdi; -#define DI2HIKEY(di) ((di)->di_key) -#define HIKEY2DI(p) ((dictitem_T *)(p - (dumdi.di_key - (char_u *)&dumdi))) -#define HI2DI(hi) HIKEY2DI((hi)->hi_key) - -/* * Structure returned by get_lval() and used by set_var_lval(). * For a plain name: * "name" points to the variable name. @@ -354,7 +342,7 @@ typedef struct { typedef enum { VAR_FLAVOUR_DEFAULT, /* doesn't start with uppercase */ VAR_FLAVOUR_SESSION, /* starts with uppercase, some lower */ - VAR_FLAVOUR_VIMINFO /* all uppercase */ + VAR_FLAVOUR_SHADA /* all uppercase */ } var_flavour_T; /* values for vv_flags: */ @@ -5352,7 +5340,7 @@ static int list_concat(list_T *l1, list_T *l2, typval_T *tv) return FAIL; /* make a copy of the first list. */ - l = list_copy(l1, FALSE, 0); + l = list_copy(NULL, l1, false, 0); if (l == NULL) return FAIL; tv->v_type = VAR_LIST; @@ -5363,13 +5351,20 @@ static int list_concat(list_T *l1, list_T *l2, typval_T *tv) return OK; } -/* - * Make a copy of list "orig". Shallow if "deep" is FALSE. - * The refcount of the new list is set to 1. - * See item_copy() for "copyID". - * Returns NULL if orig is NULL or some failure happens. - */ -static list_T *list_copy(list_T *orig, int deep, int copyID) +/// Make a copy of list +/// +/// @param[in] conv If non-NULL, then all internal strings will be converted. +/// @param[in] orig Original list to copy. +/// @param[in] deep If false, then shallow copy will be done. +/// @param[in] copyID See var_item_copy(). +/// +/// @return Copied list. May be NULL in case original list is NULL or some +/// failure happens. The refcount of the new list is set to 1. +static list_T *list_copy(const vimconv_T *const conv, + list_T *const orig, + const bool deep, + const int copyID) + FUNC_ATTR_WARN_UNUSED_RESULT { listitem_T *item; listitem_T *ni; @@ -5388,7 +5383,7 @@ static list_T *list_copy(list_T *orig, int deep, int copyID) item = item->li_next) { ni = listitem_alloc(); if (deep) { - if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL) { + if (var_item_copy(conv, &item->li_tv, &ni->li_tv, deep, copyID) == FAIL) { xfree(ni); break; } @@ -5546,6 +5541,7 @@ static int list_join(garray_T *const gap, list_T *const l, bool garbage_collect(void) { bool abort = false; +#define ABORTING(func) abort = abort || func // Only do this once. want_garbage_collect = false; @@ -5564,45 +5560,117 @@ bool garbage_collect(void) // referenced through previous_funccal. This must be first, because if // the item is referenced elsewhere the funccal must not be freed. for (funccall_T *fc = previous_funccal; fc != NULL; fc = fc->caller) { - abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL); - abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL); + ABORTING(set_ref_in_ht)(&fc->l_vars.dv_hashtab, copyID + 1, NULL); + ABORTING(set_ref_in_ht)(&fc->l_avars.dv_hashtab, copyID + 1, NULL); } // script-local variables for (int i = 1; i <= ga_scripts.ga_len; ++i) { - abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL); + ABORTING(set_ref_in_ht)(&SCRIPT_VARS(i), copyID, NULL); } - // buffer-local variables FOR_ALL_BUFFERS(buf) { - abort = abort || set_ref_in_item(&buf->b_bufvar.di_tv, copyID, NULL, NULL); + // buffer-local variables + ABORTING(set_ref_in_item)(&buf->b_bufvar.di_tv, copyID, NULL, NULL); + // buffer marks (ShaDa additional data) + ABORTING(set_ref_in_fmark)(buf->b_last_cursor, copyID); + ABORTING(set_ref_in_fmark)(buf->b_last_insert, copyID); + ABORTING(set_ref_in_fmark)(buf->b_last_change, copyID); + for (size_t i = 0; i < NMARKS; i++) { + ABORTING(set_ref_in_fmark)(buf->b_namedm[i], copyID); + } + // buffer change list (ShaDa additional data) + for (int i = 0; i < buf->b_changelistlen; i++) { + ABORTING(set_ref_in_fmark)(buf->b_changelist[i], copyID); + } + // buffer ShaDa additional data + ABORTING(set_ref_dict)(buf->additional_data, copyID); } - // window-local variables FOR_ALL_TAB_WINDOWS(tp, wp) { - abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID, NULL, NULL); + // window-local variables + ABORTING(set_ref_in_item)(&wp->w_winvar.di_tv, copyID, NULL, NULL); + // window jump list (ShaDa additional data) + for (int i = 0; i < wp->w_jumplistlen; i++) { + ABORTING(set_ref_in_fmark)(wp->w_jumplist[i].fmark, copyID); + } } if (aucmd_win != NULL) { - abort = abort || - set_ref_in_item(&aucmd_win->w_winvar.di_tv, copyID, NULL, NULL); + ABORTING(set_ref_in_item)(&aucmd_win->w_winvar.di_tv, copyID, NULL, NULL); + } + + // registers (ShaDa additional data) + { + const void *reg_iter = NULL; + do { + yankreg_T reg; + char name = NUL; + reg_iter = op_register_iter(reg_iter, &name, ®); + if (name != NUL) { + ABORTING(set_ref_dict)(reg.additional_data, copyID); + } + } while (reg_iter != NULL); + } + + // global marks (ShaDa additional data) + { + const void *mark_iter = NULL; + do { + xfmark_T fm; + char name = NUL; + mark_iter = mark_global_iter(mark_iter, &name, &fm); + if (name != NUL) { + ABORTING(set_ref_dict)(fm.fmark.additional_data, copyID); + } + } while (mark_iter != NULL); } // tabpage-local variables FOR_ALL_TABS(tp) { - abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID, NULL, NULL); + ABORTING(set_ref_in_item)(&tp->tp_winvar.di_tv, copyID, NULL, NULL); } // global variables - abort = abort || set_ref_in_ht(&globvarht, copyID, NULL); + ABORTING(set_ref_in_ht)(&globvarht, copyID, NULL); // function-local variables for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->caller) { - abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL); - abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL); + ABORTING(set_ref_in_ht)(&fc->l_vars.dv_hashtab, copyID, NULL); + ABORTING(set_ref_in_ht)(&fc->l_avars.dv_hashtab, copyID, NULL); } // v: vars - abort = abort || set_ref_in_ht(&vimvarht, copyID, NULL); + ABORTING(set_ref_in_ht)(&vimvarht, copyID, NULL); + + // history items (ShaDa additional elements) + if (p_hi) { + for (uint8_t i = 0; i < HIST_COUNT; i++) { + const void *iter = NULL; + do { + histentry_T hist; + iter = hist_iter(iter, i, false, &hist); + if (hist.hisstr != NULL) { + ABORTING(set_ref_list)(hist.additional_elements, copyID); + } + } while (iter != NULL); + } + } + + // previously used search/substitute patterns (ShaDa additional data) + { + SearchPattern pat; + get_search_pattern(&pat); + ABORTING(set_ref_dict)(pat.additional_data, copyID); + get_substitute_pattern(&pat); + ABORTING(set_ref_dict)(pat.additional_data, copyID); + } + + // previously used replacement string + { + SubReplacementString sub; + sub_get_replacement(&sub); + ABORTING(set_ref_list)(sub.additional_elements, copyID); + } bool did_free = false; if (!abort) { @@ -5631,6 +5699,7 @@ bool garbage_collect(void) verb_msg((char_u *)_( "Not enough memory to set references, garbage collection aborted!")); } +#undef ABORTING return did_free; } @@ -5690,6 +5759,7 @@ static int free_unref_items(int copyID) /// /// @returns true if setting references failed somehow. bool set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack) + FUNC_ATTR_WARN_UNUSED_RESULT { bool abort = false; ht_stack_T *ht_stack = NULL; @@ -5732,6 +5802,7 @@ bool set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack) /// /// @returns true if setting references failed somehow. bool set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack) + FUNC_ATTR_WARN_UNUSED_RESULT { bool abort = false; list_stack_T *list_stack = NULL; @@ -5772,6 +5843,7 @@ bool set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack) /// @returns true if setting references failed somehow. bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack) + FUNC_ATTR_WARN_UNUSED_RESULT { bool abort = false; @@ -5821,6 +5893,52 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, return abort; } +/// Mark all lists and dicts referenced in given mark +/// +/// @returns true if setting references failed somehow. +static inline bool set_ref_in_fmark(fmark_T fm, int copyID) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (fm.additional_data != NULL + && fm.additional_data->dv_copyID != copyID) { + fm.additional_data->dv_copyID = copyID; + return set_ref_in_ht(&fm.additional_data->dv_hashtab, copyID, NULL); + } + return false; +} + +/// Mark all lists and dicts referenced in given list and the list itself +/// +/// @returns true if setting references failed somehow. +static inline bool set_ref_list(list_T *list, int copyID) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (list != NULL) { + typval_T tv = (typval_T) { + .v_type = VAR_LIST, + .vval = { .v_list = list } + }; + return set_ref_in_item(&tv, copyID, NULL, NULL); + } + return false; +} + +/// Mark all lists and dicts referenced in given dict and the dict itself +/// +/// @returns true if setting references failed somehow. +static inline bool set_ref_dict(dict_T *dict, int copyID) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (dict != NULL) { + typval_T tv = (typval_T) { + .v_type = VAR_DICT, + .vval = { .v_dict = dict } + }; + return set_ref_in_item(&tv, copyID, NULL, NULL); + } + return false; +} + /* * Allocate an empty header for a dictionary. */ @@ -5964,13 +6082,20 @@ void dictitem_free(dictitem_T *item) xfree(item); } -/* - * Make a copy of dict "d". Shallow if "deep" is FALSE. - * The refcount of the new dict is set to 1. - * See item_copy() for "copyID". - * Returns NULL if orig is NULL or some other failure. - */ -static dict_T *dict_copy(dict_T *orig, int deep, int copyID) +/// Make a copy of dictionary +/// +/// @param[in] conv If non-NULL, then all internal strings will be converted. +/// @param[in] orig Original dictionary to copy. +/// @param[in] deep If false, then shallow copy will be done. +/// @param[in] copyID See var_item_copy(). +/// +/// @return Copied dictionary. May be NULL in case original dictionary is NULL +/// or some failure happens. The refcount of the new dictionary is set +/// to 1. +static dict_T *dict_copy(const vimconv_T *const conv, + dict_T *const orig, + const bool deep, + const int copyID) { dictitem_T *di; int todo; @@ -5990,10 +6115,21 @@ static dict_T *dict_copy(dict_T *orig, int deep, int copyID) if (!HASHITEM_EMPTY(hi)) { --todo; - di = dictitem_alloc(hi->hi_key); + if (conv == NULL || conv->vc_type == CONV_NONE) { + di = dictitem_alloc(hi->hi_key); + } else { + char *const key = (char *) string_convert((vimconv_T *) conv, + hi->hi_key, NULL); + if (key == NULL) { + di = dictitem_alloc(hi->hi_key); + } else { + di = dictitem_alloc((char_u *) key); + xfree(key); + } + } if (deep) { - if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep, - copyID) == FAIL) { + if (var_item_copy(conv, &HI2DI(hi)->di_tv, &di->di_tv, deep, + copyID) == FAIL) { xfree(di); break; } @@ -6305,7 +6441,7 @@ failret: /// the results. /// @param firstargname Name of the first argument. /// @param name Name of the target converter. -#define DEFINE_VIML_CONV_FUNCTIONS(name, firstargtype, firstargname) \ +#define DEFINE_VIML_CONV_FUNCTIONS(scope, name, firstargtype, firstargname) \ static int name##_convert_one_value(firstargtype firstargname, \ MPConvStack *const mpstack, \ typval_T *const tv, \ @@ -6543,7 +6679,7 @@ name##_convert_one_value_regular_dict: \ return OK; \ } \ \ -static int vim_to_##name(firstargtype firstargname, typval_T *const tv) \ +scope int vim_to_##name(firstargtype firstargname, typval_T *const tv) \ FUNC_ATTR_WARN_UNUSED_RESULT \ { \ current_copyID += COPYID_INC; \ @@ -6739,7 +6875,7 @@ vim_to_msgpack_error_ret: \ #define CONV_ALLOW_SPECIAL false -DEFINE_VIML_CONV_FUNCTIONS(str |