From 06347a64cac5e33574713a59ace9d1d0ea4b6f82 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 05:19:46 +0800 Subject: vim-patch:9.1.0443: Can't use blockwise selection with width for getregion() (#28985) Problem: Can't use a blockwise selection with a width for getregion(). Solution: Add support for blockwise selection with width like the return value of getregtype() or the "regtype" value of TextYankPost (zeertzjq). closes: vim/vim#14842 https://github.com/vim/vim/commit/afc2295c2201ae87bfbb42d5f5315ad0583ccabf --- src/nvim/eval/funcs.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e4cb63eb8e..3cb6ef41c0 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2824,7 +2824,7 @@ static char *block_def2str(struct block_def *bd) } static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2, - bool *const inclusive, MotionType *region_type, oparg_T *oa) + bool *const inclusive, MotionType *region_type, oparg_T *oap) FUNC_ATTR_NONNULL_ALL { tv_list_alloc_ret(rettv, kListLenMayKnow); @@ -2858,11 +2858,17 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2 type = default_type; } + int block_width = 0; if (type[0] == 'v' && type[1] == NUL) { *region_type = kMTCharWise; } else if (type[0] == 'V' && type[1] == NUL) { *region_type = kMTLineWise; - } else if (type[0] == Ctrl_V && type[1] == NUL) { + } else if (type[0] == Ctrl_V) { + char *p = type + 1; + if (*p != NUL && ((block_width = getdigits_int(&p, false, 0)) <= 0 || *p != NUL)) { + semsg(_(e_invargNval), "type", type); + return FAIL; + } *region_type = kMTBlockWise; } else { semsg(_(e_invargNval), "type", type); @@ -2926,16 +2932,18 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2 colnr_T sc1, ec1, sc2, ec2; getvvcol(curwin, p1, &sc1, NULL, &ec1); getvvcol(curwin, p2, &sc2, NULL, &ec2); - oa->motion_type = kMTBlockWise; - oa->inclusive = true; - oa->op_type = OP_NOP; - oa->start = *p1; - oa->end = *p2; - oa->start_vcol = MIN(sc1, sc2); - if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { - oa->end_vcol = sc2 - 1; + oap->motion_type = kMTBlockWise; + oap->inclusive = true; + oap->op_type = OP_NOP; + oap->start = *p1; + oap->end = *p2; + oap->start_vcol = MIN(sc1, sc2); + if (block_width > 0) { + oap->end_vcol = oap->start_vcol + block_width - 1; + } else if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { + oap->end_vcol = sc2 - 1; } else { - oa->end_vcol = MAX(ec1, ec2); + oap->end_vcol = MAX(ec1, ec2); } } -- cgit From 22fe04452e12944b409c8ee92cf4069ac8026987 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 May 2024 05:50:49 +0800 Subject: vim-patch:9.1.0446: getregionpos() inconsistent for partly-selected multibyte char (#29032) Problem: getregionpos() behaves inconsistently for a partly-selected multibyte char. Solution: Always use column of the first byte for a partly-selected multibyte char (zeertzjq). closes: vim/vim#14851 https://github.com/vim/vim/commit/ef73374dc3e4bf8104ba31d5b22517f8028b467a --- src/nvim/eval/funcs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3cb6ef41c0..8b22c7a797 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3042,6 +3042,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) { pos_T ret_p1, ret_p2; + char *line = ml_get(lnum); colnr_T line_len = ml_get_len(lnum); if (region_type == kMTLineWise) { @@ -3060,7 +3061,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr if (bd.is_oneChar) { // selection entirely inside one char if (region_type == kMTBlockWise) { - ret_p1.col = bd.textcol; + ret_p1.col = (colnr_T)(mb_prevptr(line, bd.textstart) - line) + 1; ret_p1.coladd = bd.start_char_vcols - (bd.start_vcol - oa.start_vcol); } else { ret_p1.col = p1.col + 1; @@ -3072,7 +3073,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr ret_p1.coladd = oa.start_vcol - bd.start_vcol; bd.is_oneChar = true; } else if (bd.startspaces > 0) { - ret_p1.col = bd.textcol; + ret_p1.col = (colnr_T)(mb_prevptr(line, bd.textstart) - line) + 1; ret_p1.coladd = bd.start_char_vcols - bd.startspaces; } else { ret_p1.col = bd.textcol + 1; -- cgit From bb6190bec5f18c1f9e2c1d29ef1f7cf7912ea625 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 1 Jun 2024 08:19:41 -0700 Subject: refactor: move shared messages to errors.h #26214 --- src/nvim/eval/executor.c | 1 + src/nvim/eval/funcs.c | 1 + src/nvim/eval/typval.c | 1 + src/nvim/eval/userfunc.c | 1 + src/nvim/eval/vars.c | 1 + src/nvim/eval/window.c | 1 + 6 files changed, 6 insertions(+) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 1b8c057d7c..3255e78d09 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -1,6 +1,7 @@ #include #include +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/executor.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8b22c7a797..0165e4af60 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -38,6 +38,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/buffer.h" #include "nvim/eval/decode.h" diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index eb8c89c36e..1ea1fe46d2 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -10,6 +10,7 @@ #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/executor.h" diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 39bd63462c..00fb896797 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 1c15274acc..7b93a291c4 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -15,6 +15,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 68de40f983..d7485c12a3 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -10,6 +10,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" -- cgit From 0e49c3ad1a599376d0a5c229f304a06d48c56163 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 05:47:47 +0800 Subject: vim-patch:9.1.0456: Left shift is incorrect with vartabstop and shiftwidth=0 Problem: Left shift is incorrect with vartabstop and shiftwidth=0 Solution: make tabstop_at() function aware of shift direction (Gary Johnson) The problem was that with 'vartabstop' set and 'shiftwidth' equal 0, left shifts using << were shifting the line to the wrong column. The tabstop to the right of the first character in the line was being used as the shift amount instead of the tabstop to the left of that first character. The reason was that the tabstop_at() function always returned the value of the tabstop to the right of the given column and was not accounting for the direction of the shift. The solution was to make tabstop_at() aware of the direction of the shift and to choose the tabtop accordingly. A test was added to check this behavior and make sure it doesn't regress. While at it, also fix a few indentation/alignment issues. fixes: vim/vim#14864 closes: vim/vim#14887 https://github.com/vim/vim/commit/88d4f255b7b7a19bb4f6489e0ad0956e47d51fed Co-authored-by: Gary Johnson --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 0165e4af60..e704135366 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8302,7 +8302,7 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (col < 0) { return; // type error; errmsg already given } - rettv->vval.v_number = get_sw_value_col(curbuf, col); + rettv->vval.v_number = get_sw_value_col(curbuf, col, false); return; } rettv->vval.v_number = get_sw_value(curbuf); -- cgit From 200e7ad1578619e78c664bd0c6be024168433412 Mon Sep 17 00:00:00 2001 From: James Tirta Halim Date: Mon, 3 Jun 2024 11:10:30 +0700 Subject: fixup: apply the change on more files --- src/nvim/eval/encode.c | 6 +++--- src/nvim/eval/funcs.c | 6 +++--- src/nvim/eval/typval.c | 2 +- src/nvim/eval/window.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index d35ac4eb7b..e216dbdaa6 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -855,7 +855,7 @@ char *encode_tv2string(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } @@ -883,7 +883,7 @@ char *encode_tv2echo(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } @@ -908,7 +908,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) if (len != NULL) { *len = (size_t)ga.ga_len; } - ga_append(&ga, '\0'); + ga_append(&ga, NUL); return (char *)ga.ga_data; } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e704135366..666d46cdad 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -4318,7 +4318,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en // Set $NVIM (in the child process) to v:servername. #3118 char *nvim_addr = get_vim_var_str(VV_SEND_SERVER); - if (nvim_addr[0] != '\0') { + if (nvim_addr[0] != NUL) { dictitem_T *dv = tv_dict_find(env, S_LEN("NVIM")); if (dv) { tv_dict_item_remove(env, dv); @@ -9174,13 +9174,13 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true); // Trim slash. if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) { - IObuff[len - 1] = '\0'; + IObuff[len - 1] = NUL; } if (len == 1 && IObuff[0] == '/') { // Avoid ambiguity in the URI when CWD is root directory. IObuff[1] = '.'; - IObuff[2] = '\0'; + IObuff[2] = NUL; } // Terminal URI: "term://$CWD//$PID:$CMD" diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 1ea1fe46d2..13b31ab30f 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1824,7 +1824,7 @@ char *callback_to_string(Callback *cb, Arena *arena) snprintf(msg, msglen, "", cb->data.partial->pt_name); break; default: - *msg = '\0'; + *msg = NUL; break; } return msg; diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index d7485c12a3..86495f1cb6 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -272,7 +272,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar) // if count is not specified, default to 1 count = 1; } - if (endp != NULL && *endp != '\0') { + if (endp != NULL && *endp != NUL) { if (strequal(endp, "j")) { twin = win_vert_neighbor(tp, twin, false, count); } else if (strequal(endp, "k")) { -- cgit From bbd2f340a2895ed59785f952b2585e6590602cad Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 11 Jun 2024 10:25:32 +0200 Subject: refactor(memory): use builtin strcat() instead of STRCAT() The latter was mostly relevant with the past char_u madness. NOTE: STRCAT also functioned as a counterfeit "NOLINT" for clint apparently. But NOLINT-ing every usecase is just the same as disabling the check entirely. --- src/nvim/eval/userfunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 00fb896797..122a1ac8ab 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -265,7 +265,7 @@ static void set_ufunc_name(ufunc_T *fp, char *name) if ((uint8_t)name[0] == K_SPECIAL) { fp->uf_name_exp = xmalloc(strlen(name) + 3); STRCPY(fp->uf_name_exp, ""); - STRCAT(fp->uf_name_exp, fp->uf_name + 3); + strcat(fp->uf_name_exp, fp->uf_name + 3); } } @@ -2062,7 +2062,7 @@ char *get_scriptlocal_funcname(char *funcname) const int off = *funcname == 's' ? 2 : 5; char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1); STRCPY(newname, sid_buf); - STRCAT(newname, funcname + off); + strcat(newname, funcname + off); return newname; } -- cgit From c37695a5d5f2e8914fff86f3581bed70b4c85d3c Mon Sep 17 00:00:00 2001 From: James <89495599+IAKOBVS@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:40:24 +0700 Subject: refactor: use S_LEN(s) instead of s, n (#29219) --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 666d46cdad..9a1ed7dea9 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5095,7 +5095,7 @@ static void get_matches_in_str(const char *str, regmatch_T *rmp, list_T *mlist, // return a list with the submatches for (int i = 1; i < NSUBEXP; i++) { if (rmp->endp[i] == NULL) { - tv_list_append_string(sml, "", 0); + tv_list_append_string(sml, S_LEN("")); } else { tv_list_append_string(sml, rmp->startp[i], rmp->endp[i] - rmp->startp[i]); } -- cgit From 43d8435cf84468e776e0a6a98d05ae7bd62583b7 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 13 Jun 2024 22:20:06 +0100 Subject: revert: "refactor: use S_LEN macro" (#29319) revert: "refactor: use S_LEN(s) instead of s, n (#29219)" This reverts commit c37695a5d5f2e8914fff86f3581bed70b4c85d3c. --- src/nvim/eval/funcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 9a1ed7dea9..666d46cdad 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5095,7 +5095,7 @@ static void get_matches_in_str(const char *str, regmatch_T *rmp, list_T *mlist, // return a list with the submatches for (int i = 1; i < NSUBEXP; i++) { if (rmp->endp[i] == NULL) { - tv_list_append_string(sml, S_LEN("")); + tv_list_append_string(sml, "", 0); } else { tv_list_append_string(sml, rmp->startp[i], rmp->endp[i] - rmp->startp[i]); } -- cgit From 2bb1a18631c4035e4a582b7d995968acbac874bf Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 15 Jun 2024 19:50:44 +0200 Subject: refactor(typval): don't use msgpack_packer for msgpackdump() Step towords completely eliminating msgpack_packer. --- src/nvim/eval/encode.c | 76 ++++++++++++++--------------------------- src/nvim/eval/encode.h | 3 +- src/nvim/eval/funcs.c | 24 +++++++------ src/nvim/eval/typval.c | 8 +++-- src/nvim/eval/typval_encode.c.h | 7 ++++ 5 files changed, 52 insertions(+), 66 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index e216dbdaa6..eb70b0534d 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -13,7 +13,7 @@ #include #include "klib/kvec.h" -#include "msgpack/pack.h" +#include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" @@ -28,6 +28,7 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/msgpack_rpc/packer.h" #include "nvim/strings.h" #include "nvim/types_defs.h" #include "nvim/vim_defs.h" // For _() @@ -412,6 +413,8 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ ga_concat(gap, "{}") +#define TYPVAL_ENCODE_CHECK_BEFORE + #define TYPVAL_ENCODE_CONV_NIL(tv) \ ga_concat(gap, "v:null") @@ -536,6 +539,8 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #undef TYPVAL_ENCODE_ALLOW_SPECIALS #define TYPVAL_ENCODE_ALLOW_SPECIALS true +#define TYPVAL_ENCODE_CHECK_BEFORE + #undef TYPVAL_ENCODE_CONV_NIL #define TYPVAL_ENCODE_CONV_NIL(tv) \ ga_concat(gap, "null") @@ -821,6 +826,7 @@ bool encode_check_json_key(const typval_T *const tv) #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER @@ -913,52 +919,22 @@ char *encode_tv2json(typval_T *tv, size_t *len) } #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ - do { \ - if ((buf) == NULL) { \ - msgpack_pack_bin(packer, 0); \ - } else { \ - const size_t len_ = (len); \ - msgpack_pack_bin(packer, len_); \ - msgpack_pack_bin_body(packer, buf, len_); \ - } \ - } while (0) + mpack_bin(buf, (len), packer); \ #define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) \ - do { \ - if ((buf) == NULL) { \ - msgpack_pack_str(packer, 0); \ - } else { \ - const size_t len_ = (len); \ - msgpack_pack_str(packer, len_); \ - msgpack_pack_str_body(packer, buf, len_); \ - } \ - } while (0) + mpack_str(cbuf_as_string(buf, (len)), packer); \ #define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) \ - do { \ - if ((buf) == NULL) { \ - msgpack_pack_ext(packer, 0, (int8_t)(type)); \ - } else { \ - const size_t len_ = (len); \ - msgpack_pack_ext(packer, len_, (int8_t)(type)); \ - msgpack_pack_ext_body(packer, buf, len_); \ - } \ - } while (0) + mpack_ext(buf, (len), (int8_t)(type), packer); \ #define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ - do { \ - const size_t len_ = (size_t)(len); \ - msgpack_pack_bin(packer, len_); \ - if (len_ > 0) { \ - msgpack_pack_bin_body(packer, (blob)->bv_ga.ga_data, len_); \ - } \ - } while (0) + mpack_bin((blob) ? (blob)->bv_ga.ga_data : NULL, (size_t)(len), packer); \ #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ - msgpack_pack_int64(packer, (int64_t)(num)) + mpack_integer(&packer->ptr, (Integer)(num)) #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ - msgpack_pack_double(packer, (double)(flt)) + mpack_float8(&packer->ptr, (double)(flt)) #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ return conv_error(_("E5004: Error while dumping %s, %s: " \ @@ -970,33 +946,30 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_CONV_FUNC_END(tv) #define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ - msgpack_pack_array(packer, 0) + mpack_array(&packer->ptr, 0) #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ - msgpack_pack_array(packer, (size_t)(len)) + mpack_array(&packer->ptr, (uint32_t)(len)) #define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ - msgpack_pack_map(packer, 0) + mpack_map(&packer->ptr, 0) + +#define TYPVAL_ENCODE_CHECK_BEFORE \ + mpack_check_buffer(packer) #define TYPVAL_ENCODE_CONV_NIL(tv) \ - msgpack_pack_nil(packer) + mpack_nil(&packer->ptr) #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ - do { \ - if (num) { \ - msgpack_pack_true(packer); \ - } else { \ - msgpack_pack_false(packer); \ - } \ - } while (0) + mpack_bool(&packer->ptr, (bool)num); \ #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) \ - msgpack_pack_uint64(packer, (num)) + mpack_uint64(&packer->ptr, (num)) #define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ - msgpack_pack_map(packer, (size_t)(len)) + mpack_map(&packer->ptr, (uint32_t)(len)) #define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) @@ -1021,7 +994,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_SCOPE #define TYPVAL_ENCODE_NAME msgpack -#define TYPVAL_ENCODE_FIRST_ARG_TYPE msgpack_packer *const +#define TYPVAL_ENCODE_FIRST_ARG_TYPE PackerBuffer *const #define TYPVAL_ENCODE_FIRST_ARG_NAME packer #include "nvim/eval/typval_encode.c.h" #undef TYPVAL_ENCODE_SCOPE @@ -1043,6 +1016,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h index 6d1c0b61c5..efccfcb5a6 100644 --- a/src/nvim/eval/encode.h +++ b/src/nvim/eval/encode.h @@ -5,6 +5,7 @@ #include "nvim/eval/typval_defs.h" #include "nvim/garray_defs.h" +#include "nvim/msgpack_rpc/packer_defs.h" /// Convert Vimscript value to msgpack string /// @@ -13,7 +14,7 @@ /// @param[in] objname Object name, used for error message. /// /// @return OK in case of success, FAIL otherwise. -int encode_vim_to_msgpack(msgpack_packer *packer, typval_T *tv, const char *objname); +int encode_vim_to_msgpack(PackerBuffer *packer, typval_T *tv, const char *objname); /// Convert Vimscript value to :echo output /// diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 666d46cdad..9cb504c074 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -94,6 +94,7 @@ #include "nvim/move.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/channel_defs.h" +#include "nvim/msgpack_rpc/packer.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/normal.h" #include "nvim/normal_defs.h" @@ -5501,15 +5502,7 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } list_T *const list = argvars[0].vval.v_list; - msgpack_packer *packer; - if (argvars[1].v_type != VAR_UNKNOWN - && strequal(tv_get_string(&argvars[1]), "B")) { - tv_blob_alloc_ret(rettv); - packer = msgpack_packer_new(rettv->vval.v_blob, &encode_blob_write); - } else { - packer = msgpack_packer_new(tv_list_alloc_ret(rettv, kListLenMayKnow), - &encode_list_write); - } + PackerBuffer packer = packer_string_buffer(); const char *const msg = _("msgpackdump() argument, index %i"); // Assume that translation will not take more then 4 times more space char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN]; @@ -5517,11 +5510,20 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) TV_LIST_ITER(list, li, { vim_snprintf(msgbuf, sizeof(msgbuf), msg, idx); idx++; - if (encode_vim_to_msgpack(packer, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) { + if (encode_vim_to_msgpack(&packer, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) { break; } }); - msgpack_packer_free(packer); + String data = packer_take_string(&packer); + if (argvars[1].v_type != VAR_UNKNOWN && strequal(tv_get_string(&argvars[1]), "B")) { + blob_T *b = tv_blob_alloc_ret(rettv); + b->bv_ga.ga_data = data.data; + b->bv_ga.ga_len = (int)data.size; + b->bv_ga.ga_maxlen = (int)(packer.endptr - packer.startptr); + } else { + encode_list_write(tv_list_alloc_ret(rettv, kListLenMayKnow), data.data, data.size); + api_free_string(data); + } } static int msgpackparse_convert_item(const msgpack_object data, const msgpack_unpack_return result, diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 13b31ab30f..f9eb5c33c0 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -3064,8 +3064,7 @@ void f_blob2list(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// list2blob() function void f_list2blob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - tv_blob_alloc_ret(rettv); - blob_T *const blob = rettv->vval.v_blob; + blob_T *blob = tv_blob_alloc_ret(rettv); if (tv_check_for_list_arg(argvars, 0) == FAIL) { return; @@ -3252,11 +3251,12 @@ void tv_dict_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) /// Also sets reference count. /// /// @param[out] ret_tv Structure where blob is saved. -void tv_blob_alloc_ret(typval_T *const ret_tv) +blob_T *tv_blob_alloc_ret(typval_T *const ret_tv) FUNC_ATTR_NONNULL_ALL { blob_T *const b = tv_blob_alloc(); tv_blob_set_ret(ret_tv, b); + return b; } /// Copy a blob typval to a different typval. @@ -3284,6 +3284,7 @@ void tv_blob_copy(blob_T *const from, typval_T *const to) //{{{3 Clear #define TYPVAL_ENCODE_ALLOW_SPECIALS false +#define TYPVAL_ENCODE_CHECK_BEFORE #define TYPVAL_ENCODE_CONV_NIL(tv) \ do { \ @@ -3500,6 +3501,7 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic #undef TYPVAL_ENCODE_FIRST_ARG_NAME #undef TYPVAL_ENCODE_ALLOW_SPECIALS +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_NUMBER diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index c0cd0ce557..afee6dab18 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -6,6 +6,11 @@ /// something else. For these macros to work the following macros must be /// defined: +/// @def TYPVAL_ENCODE_CHECK_BEFORE +/// @brief Macro used before any specific CONV function +/// +/// can be used for a common check, like flushing a buffer if necessary + /// @def TYPVAL_ENCODE_CONV_NIL /// @brief Macros used to convert NIL value /// @@ -323,6 +328,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME, MPConvStack *const mpstack, MPConvStackVal *const cur_mpsv, typval_T *const tv, const int copyID, const char *const objname) { + TYPVAL_ENCODE_CHECK_BEFORE; switch (tv->v_type) { case VAR_STRING: TYPVAL_ENCODE_CONV_STRING(tv, tv->vval.v_string, tv_strlen(tv)); @@ -420,6 +426,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( break; } } + TYPVAL_ENCODE_CHECK_BEFORE; if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { goto _convert_one_value_regular_dict; } -- cgit From bda63d5b97dfb333de6f4bd757dbb978906062a2 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 25 Jun 2024 15:33:47 +0200 Subject: refactor(typval)!: remove distinction of binary and nonbinary strings This is a breaking change which will make refactor of typval and shada code a lot easier. In particular, code that would use or check for v:msgpack_types.binary in the wild would be broken. This appears to be rarely used in existing plugins. Also some cases where v:msgpack_type.string would be used to represent a binary string of "string" type, we use a BLOB instead, which is vimscripts native type for binary blobs, and already was used for BIN formats when necessary. msgpackdump(msgpackparse(data)) no longer preserves the distinction of BIN and STR strings. This is very common behavior for language-specific msgpack bindings. Nvim uses msgpack as a tool to serialize its data. Nvim is not a tool to bit-perfectly manipulate arbitrary msgpack data out in the wild. The changed tests should indicate how behavior changes in various edge cases. --- src/nvim/eval/decode.c | 64 +++++++++++------------------------------ src/nvim/eval/encode.c | 3 +- src/nvim/eval/typval_encode.c.h | 10 ++----- 3 files changed, 19 insertions(+), 58 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index d7df7bb150..13cd3274dd 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -247,45 +247,29 @@ list_T *decode_create_map_special_dict(typval_T *const ret_tv, const ptrdiff_t l /// /// @param[in] s String to decode. /// @param[in] len String length. -/// @param[in] hasnul Whether string has NUL byte, not or it was not yet -/// determined. -/// @param[in] binary Determines decode type if string has NUL bytes. -/// If true convert string to VAR_BLOB, otherwise to the -/// kMPString special type. +/// @param[in] force_blob whether string always should be decoded as a blob, +/// or only when embedded NUL bytes were present /// @param[in] s_allocated If true, then `s` was allocated and can be saved in /// a returned structure. If it is not saved there, it /// will be freed. /// /// @return Decoded string. -typval_T decode_string(const char *const s, const size_t len, const TriState hasnul, - const bool binary, const bool s_allocated) +typval_T decode_string(const char *const s, const size_t len, bool force_blob, + const bool s_allocated) FUNC_ATTR_WARN_UNUSED_RESULT { assert(s != NULL || len == 0); - const bool really_hasnul = (hasnul == kNone - ? ((s != NULL) && (memchr(s, NUL, len) != NULL)) - : (bool)hasnul); - if (really_hasnul) { + const bool use_blob = force_blob || ((s != NULL) && (memchr(s, NUL, len) != NULL)); + if (use_blob) { typval_T tv; tv.v_lock = VAR_UNLOCKED; - if (binary) { - tv_blob_alloc_ret(&tv); - ga_concat_len(&tv.vval.v_blob->bv_ga, s, len); + blob_T *b = tv_blob_alloc_ret(&tv); + if (s_allocated) { + b->bv_ga.ga_data = (void *)s; + b->bv_ga.ga_len = (int)len; + b->bv_ga.ga_maxlen = (int)len; } else { - list_T *const list = tv_list_alloc(kListLenMayKnow); - tv_list_ref(list); - create_special_dict(&tv, kMPString, - (typval_T){ .v_type = VAR_LIST, - .v_lock = VAR_UNLOCKED, - .vval = { .v_list = list } }); - const int elw_ret = encode_list_write((void *)list, s, len); - if (s_allocated) { - xfree((void *)s); - } - if (elw_ret == -1) { - tv_clear(&tv); - return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED }; - } + ga_concat_len(&b->bv_ga, s, len); } return tv; } @@ -405,7 +389,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, char *str = xmalloc(len + 1); int fst_in_pair = 0; char *str_end = str; - bool hasnul = false; #define PUT_FST_IN_PAIR(fst_in_pair, str_end) \ do { \ if ((fst_in_pair) != 0) { \ @@ -426,9 +409,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, uvarnumber_T ch; vim_str2nr(ubuf, NULL, NULL, STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4, true, NULL); - if (ch == 0) { - hasnul = true; - } if (SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) { PUT_FST_IN_PAIR(fst_in_pair, str_end); fst_in_pair = (int)ch; @@ -476,10 +456,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, PUT_FST_IN_PAIR(fst_in_pair, str_end); #undef PUT_FST_IN_PAIR *str_end = NUL; - typval_T obj = decode_string(str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true); - if (obj.v_type == VAR_UNKNOWN) { - goto parse_json_string_fail; - } + typval_T obj = decode_string(str, (size_t)(str_end - str), false, true); POP(obj, obj.v_type != VAR_STRING); goto parse_json_string_ret; parse_json_string_fail: @@ -982,18 +959,8 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) }; break; case MSGPACK_OBJECT_STR: - *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kTrue, false, - false); - if (rettv->v_type == VAR_UNKNOWN) { - return FAIL; - } - break; case MSGPACK_OBJECT_BIN: - *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kNone, true, - false); - if (rettv->v_type == VAR_UNKNOWN) { - return FAIL; - } + *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, false, false); break; case MSGPACK_OBJECT_ARRAY: { list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size); @@ -1016,7 +983,8 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv) } case MSGPACK_OBJECT_MAP: { for (size_t i = 0; i < mobj.via.map.size; i++) { - if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR + if ((mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR + && mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_BIN) || mobj.via.map.ptr[i].key.via.str.size == 0 || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL, mobj.via.map.ptr[i].key.via.str.size) != NULL) { diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index eb70b0534d..383cf9f1bd 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -776,8 +776,7 @@ bool encode_check_json_key(const typval_T *const tv) const dictitem_T *val_di; if ((type_di = tv_dict_find(spdict, S_LEN("_TYPE"))) == NULL || type_di->di_tv.v_type != VAR_LIST - || (type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString] - && type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPBinary]) + || type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString] || (val_di = tv_dict_find(spdict, S_LEN("_VAL"))) == NULL || val_di->di_tv.v_type != VAR_LIST) { return false; diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index afee6dab18..3a78fc5afd 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -501,9 +501,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( } TYPVAL_ENCODE_CONV_FLOAT(tv, val_di->di_tv.vval.v_float); break; - case kMPString: - case kMPBinary: { - const bool is_string = ((MessagePackType)i == kMPString); + case kMPString: { if (val_di->di_tv.v_type != VAR_LIST) { goto _convert_one_value_regular_dict; } @@ -513,11 +511,7 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( &buf)) { goto _convert_one_value_regular_dict; } - if (is_string) { - TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len); - } else { - TYPVAL_ENCODE_CONV_STRING(tv, buf, len); - } + TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len); xfree(buf); break; } -- cgit From 782b3024ef0e3d6615e9dc90509a29e96ab58152 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 24 Jun 2024 11:27:56 +0200 Subject: refactor(shada): don't use msgpack_packer for shada Now msgpack-c is never used for packing. The real fun part will be replacing it for unpacking. --- src/nvim/eval/encode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 383cf9f1bd..92c5aaeffd 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -918,7 +918,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) } #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ - mpack_bin(buf, (len), packer); \ + mpack_bin(cbuf_as_string(buf, (len)), packer); \ #define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) \ mpack_str(cbuf_as_string(buf, (len)), packer); \ @@ -927,7 +927,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) mpack_ext(buf, (len), (int8_t)(type), packer); \ #define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ - mpack_bin((blob) ? (blob)->bv_ga.ga_data : NULL, (size_t)(len), packer); \ + mpack_bin(cbuf_as_string((blob) ? (blob)->bv_ga.ga_data : NULL, (size_t)(len)), packer); #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ mpack_integer(&packer->ptr, (Integer)(num)) -- cgit From 2a883d9c597e70d25ffc53373731d05d18a89b91 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 5 Jul 2024 15:20:02 +0800 Subject: vim-patch:9.1.0524: the recursive parameter in the *_equal functions can be removed (#29572) Problem: the recursive parameter in the *_equal functions can be removed Solution: Remove the recursive parameter in dict_equal(), list_equal() object_equal and tv_equal(). Use a comparison of the static var recursive_cnt == 0 to determine whether or not tv_equal() has been called recursively (Yinzuo Jiang). closes: vim/vim#15070 https://github.com/vim/vim/commit/7ccd1a2e858dbb2ac7fb09971dfcbfad62baa677 Co-authored-by: Yinzuo Jiang --- src/nvim/eval/funcs.c | 8 ++++---- src/nvim/eval/typval.c | 24 ++++++++++-------------- 2 files changed, 14 insertions(+), 18 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 9cb504c074..e28e46d057 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -953,7 +953,7 @@ static varnumber_T count_list(list_T *l, typval_T *needle, int64_t idx, bool ic) varnumber_T n = 0; for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { - if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic, false)) { + if (tv_equal(TV_LIST_ITEM_TV(li), needle, ic)) { n++; } } @@ -973,7 +973,7 @@ static varnumber_T count_dict(dict_T *d, typval_T *needle, bool ic) varnumber_T n = 0; TV_DICT_ITER(d, di, { - if (tv_equal(&di->di_tv, needle, ic, false)) { + if (tv_equal(&di->di_tv, needle, ic)) { n++; } }); @@ -3770,7 +3770,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) typval_T tv; tv.v_type = VAR_NUMBER; tv.vval.v_number = tv_blob_get(b, idx); - if (tv_equal(&tv, &argvars[1], ic, false)) { + if (tv_equal(&tv, &argvars[1], ic)) { rettv->vval.v_number = idx; return; } @@ -3807,7 +3807,7 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) { - if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic, false)) { + if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic)) { rettv->vval.v_number = idx; break; } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index f9eb5c33c0..0d6de3c3e5 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1460,10 +1460,9 @@ void f_uniq(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// @param[in] l1 First list to compare. /// @param[in] l2 Second list to compare. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. /// /// @return True if lists are equal, false otherwise. -bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, const bool recursive) +bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT { if (l1 == l2) { @@ -1485,8 +1484,7 @@ bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, const bool for (; item1 != NULL && item2 != NULL ; (item1 = TV_LIST_ITEM_NEXT(l1, item1), item2 = TV_LIST_ITEM_NEXT(l2, item2))) { - if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic, - recursive)) { + if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic)) { return false; } } @@ -2679,8 +2677,9 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action /// @param[in] d1 First dictionary. /// @param[in] d2 Second dictionary. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. -bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool recursive) +/// +/// @return True if dictionaries are equal, false otherwise. +bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT { if (d1 == d2) { @@ -2702,7 +2701,7 @@ bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool if (di2 == NULL) { return false; } - if (!tv_equal(&di1->di_tv, &di2->di_tv, ic, recursive)) { + if (!tv_equal(&di1->di_tv, &di2->di_tv, ic)) { return false; } }); @@ -3838,10 +3837,9 @@ static int tv_equal_recurse_limit; /// @param[in] tv1 First value to compare. /// @param[in] tv2 Second value to compare. /// @param[in] ic True if case is to be ignored. -/// @param[in] recursive True when used recursively. /// /// @return true if values are equal. -bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const bool recursive) +bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { // TODO(ZyX-I): Make this not recursive @@ -3857,7 +3855,7 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const boo // Reduce the limit every time running into it. That should work fine for // deeply linked structures that are not recursively linked and catch // recursiveness quickly. - if (!recursive) { + if (recursive_cnt == 0) { tv_equal_recurse_limit = 1000; } if (recursive_cnt >= tv_equal_recurse_limit) { @@ -3868,15 +3866,13 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const boo switch (tv1->v_type) { case VAR_LIST: { recursive_cnt++; - const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, - true); + const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic); recursive_cnt--; return r; } case VAR_DICT: { recursive_cnt++; - const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, - true); + const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic); recursive_cnt--; return r; } -- cgit From 3c53e8f78511d6db9a6c804e5a479ba38c33102d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 5 Jul 2024 18:39:06 +0800 Subject: refactor(eval): use uv_random() for init_srand() (#29575) N/A patches for version.c: vim-patch:9.1.0518: initialize the random buffer can be improved vim-patch:9.1.0531: resource leak in mch_get_random() --- src/nvim/eval/funcs.c | 48 +++++++++++++----------------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e28e46d057..c319bd8214 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5883,42 +5883,20 @@ static void f_py3eval(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) static void init_srand(uint32_t *const x) FUNC_ATTR_NONNULL_ALL { -#ifndef MSWIN - static int dev_urandom_state = NOTDONE; // FAIL or OK once tried - - if (dev_urandom_state != FAIL) { - const int fd = os_open("/dev/urandom", O_RDONLY, 0); - struct { - union { - uint32_t number; - char bytes[sizeof(uint32_t)]; - } contents; - } buf; - - // Attempt reading /dev/urandom. - if (fd == -1) { - dev_urandom_state = FAIL; - } else { - buf.contents.number = 0; - if (read(fd, buf.contents.bytes, sizeof(uint32_t)) != sizeof(uint32_t)) { - dev_urandom_state = FAIL; - } else { - dev_urandom_state = OK; - *x = buf.contents.number; - } - os_close(fd); - } - } - if (dev_urandom_state != OK) { - // Reading /dev/urandom doesn't work, fall back to os_hrtime() XOR with process ID -#endif - // uncrustify:off - *x = (uint32_t)os_hrtime(); - *x ^= (uint32_t)os_get_pid(); -#ifndef MSWIN + union { + uint32_t number; + uint8_t bytes[sizeof(uint32_t)]; + } buf; + + if (uv_random(NULL, NULL, buf.bytes, sizeof(buf.bytes), 0, NULL) == 0) { + *x = buf.number; + return; } -#endif - // uncrustify:on + + // The system's random number generator doesn't work, + // fall back to os_hrtime() XOR with process ID + *x = (uint32_t)os_hrtime(); + *x ^= (uint32_t)os_get_pid(); } static inline uint32_t splitmix32(uint32_t *const x) -- cgit From 545aafbeb80eb52c182ce139800489b392a12d0d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 10 Jul 2024 08:07:16 +0800 Subject: vim-patch:9.1.0547: No way to get the arity of a Vim function (#29638) Problem: No way to get the arity of a Vim function (Austin Ziegler) Solution: Enhance get() Vim script function to return the function argument info using get(func, "arity") (LemonBoy) fixes: vim/vim#15097 closes: vim/vim#15109 https://github.com/vim/vim/commit/48b7d05a4f88c4326bd5d7a73a523f2d953b3e51 Co-authored-by: LemonBoy --- src/nvim/eval/funcs.c | 27 +++++++++++++++++++++++++++ src/nvim/eval/userfunc.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index c319bd8214..22e7f383a5 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2372,6 +2372,33 @@ static void f_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) for (int i = 0; i < pt->pt_argc; i++) { tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); } + } else if (strcmp(what, "arity") == 0) { + int required = 0; + int optional = 0; + bool varargs = false; + const char *name = partial_name(pt); + + get_func_arity(name, &required, &optional, &varargs); + + rettv->v_type = VAR_DICT; + tv_dict_alloc_ret(rettv); + dict_T *dict = rettv->vval.v_dict; + + // Take into account the arguments of the partial, if any. + // Note that it is possible to supply more arguments than the function + // accepts. + if (pt->pt_argc >= required + optional) { + required = optional = 0; + } else if (pt->pt_argc > required) { + optional -= pt->pt_argc - required; + required = 0; + } else { + required -= pt->pt_argc; + } + + tv_dict_add_nr(dict, S_LEN("required"), required); + tv_dict_add_nr(dict, S_LEN("optional"), optional); + tv_dict_add_bool(dict, S_LEN("varargs"), varargs); } else { semsg(_(e_invarg2), what); } diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 122a1ac8ab..42391ecec7 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -642,6 +642,44 @@ static char *fname_trans_sid(const char *const name, char *const fname_buf, char return fname; } +int get_func_arity(const char *name, int *required, int *optional, bool *varargs) +{ + int argcount = 0; + int min_argcount = 0; + + const EvalFuncDef *fdef = find_internal_func(name); + if (fdef != NULL) { + argcount = fdef->max_argc; + min_argcount = fdef->min_argc; + *varargs = false; + } else { + char fname_buf[FLEN_FIXED + 1]; + char *tofree = NULL; + int error = FCERR_NONE; + + // May need to translate 123_ to K_SNR. + char *fname = fname_trans_sid(name, fname_buf, &tofree, &error); + ufunc_T *ufunc = NULL; + if (error == FCERR_NONE) { + ufunc = find_func(fname); + } + xfree(tofree); + + if (ufunc == NULL) { + return FAIL; + } + + argcount = ufunc->uf_args.ga_len; + min_argcount = ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len; + *varargs = ufunc->uf_varargs; + } + + *required = min_argcount; + *optional = argcount - min_argcount; + + return OK; +} + /// Find a function by name, return pointer to it in ufuncs. /// /// @return NULL for unknown function. -- cgit From 7dffc36e61c46e6adc92cff5944e876446f3c40e Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 13 Jun 2024 12:00:58 +0200 Subject: refactor(declarations): also generate prototypes for functions in headers Before this change, "static inline" functions in headers needed to have their function attributes specified in a completely different way. The prototype had to be duplicated, and REAL_FATTR_ had to be used instead of the public FUNC_ATTR_ names. TODO: need a check that a "header.h.inline.generated.h" file is not forgotten when the first "static inline" function with attributes is added to a header (they would just be silently missing). --- src/nvim/eval/typval.h | 91 +++++++++++++------------------------------ src/nvim/eval/typval_encode.h | 11 +++--- 2 files changed, 32 insertions(+), 70 deletions(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index f9ebd2f778..ff70eadaaa 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -7,7 +7,6 @@ #include #include "nvim/eval/typval_defs.h" // IWYU pragma: keep -#include "nvim/func_attr.h" #include "nvim/gettext_defs.h" #include "nvim/hashtab.h" #include "nvim/lib/queue_defs.h" @@ -16,6 +15,10 @@ #include "nvim/message.h" #include "nvim/types_defs.h" +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "eval/typval.h.inline.generated.h" +#endif + // In a hashtab item "hi_key" points to "di_key" in a dictitem. // This avoids adding a pointer to the hashtab item. @@ -23,15 +26,13 @@ #define TV_DICT_HI2DI(hi) \ ((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key))) -static inline void tv_list_ref(list_T *l) - REAL_FATTR_ALWAYS_INLINE; - /// Increase reference count for a given list /// /// Does nothing for NULL lists. /// /// @param[in,out] l List to modify. static inline void tv_list_ref(list_T *const l) + FUNC_ATTR_ALWAYS_INLINE { if (l == NULL) { return; @@ -39,29 +40,25 @@ static inline void tv_list_ref(list_T *const l) l->lv_refcount++; } -static inline void tv_list_set_ret(typval_T *tv, list_T *l) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1); - /// Set a list as the return value. Increments the reference count. /// /// @param[out] tv Object to receive the list /// @param[in,out] l List to pass to the object static inline void tv_list_set_ret(typval_T *const tv, list_T *const l) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) { tv->v_type = VAR_LIST; tv->vval.v_list = l; tv_list_ref(l); } -static inline VarLockStatus tv_list_locked(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get list lock status /// /// Returns VAR_FIXED for NULL lists. /// /// @param[in] l List to check. static inline VarLockStatus tv_list_locked(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return VAR_FIXED; @@ -84,9 +81,6 @@ static inline void tv_list_set_lock(list_T *const l, const VarLockStatus lock) l->lv_lock = lock; } -static inline void tv_list_set_copyid(list_T *l, int copyid) - REAL_FATTR_NONNULL_ALL; - /// Set list copyID /// /// Does not expect NULL list, be careful. @@ -94,17 +88,16 @@ static inline void tv_list_set_copyid(list_T *l, int copyid) /// @param[out] l List to modify. /// @param[in] copyid New copyID. static inline void tv_list_set_copyid(list_T *const l, const int copyid) + FUNC_ATTR_NONNULL_ALL { l->lv_copyID = copyid; } -static inline int tv_list_len(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the number of items in a list /// /// @param[in] l List to check. static inline int tv_list_len(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return 0; @@ -112,22 +105,17 @@ static inline int tv_list_len(const list_T *const l) return l->lv_len; } -static inline int tv_list_copyid(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; - /// Get list copyID /// /// Does not expect NULL list, be careful. /// /// @param[in] l List to check. static inline int tv_list_copyid(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { return l->lv_copyID; } -static inline list_T *tv_list_latest_copy(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; - /// Get latest list copy /// /// Gets lv_copylist field assigned by tv_list_copy() earlier. @@ -136,13 +124,11 @@ static inline list_T *tv_list_latest_copy(const list_T *l) /// /// @param[in] l List to check. static inline list_T *tv_list_latest_copy(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { return l->lv_copylist; } -static inline int tv_list_uidx(const list_T *l, int n) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Normalize index: that is, return either -1 or non-negative index /// /// @param[in] l List to index. Used to get length. @@ -150,6 +136,7 @@ static inline int tv_list_uidx(const list_T *l, int n) /// /// @return -1 or list index in range [0, tv_list_len(l)). static inline int tv_list_uidx(const list_T *const l, int n) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { // Negative index is relative to the end. if (n < 0) { @@ -163,9 +150,6 @@ static inline int tv_list_uidx(const list_T *const l, int n) return n; } -static inline bool tv_list_has_watchers(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Check whether list has watchers /// /// E.g. is referenced by a :for loop. @@ -174,19 +158,18 @@ static inline bool tv_list_has_watchers(const list_T *l) /// /// @return true if there are watchers, false otherwise. static inline bool tv_list_has_watchers(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return l && l->lv_watch; } -static inline listitem_T *tv_list_first(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get first list item /// /// @param[in] l List to get item from. /// /// @return List item or NULL in case of an empty list. static inline listitem_T *tv_list_first(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return NULL; @@ -194,15 +177,13 @@ static inline listitem_T *tv_list_first(const list_T *const l) return l->lv_first; } -static inline listitem_T *tv_list_last(const list_T *l) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get last list item /// /// @param[in] l List to get item from. /// /// @return List item or NULL in case of an empty list. static inline listitem_T *tv_list_last(const list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return NULL; @@ -210,14 +191,12 @@ static inline listitem_T *tv_list_last(const list_T *const l) return l->lv_last; } -static inline void tv_dict_set_ret(typval_T *tv, dict_T *d) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1); - /// Set a dictionary as the return value /// /// @param[out] tv Object to receive the dictionary /// @param[in,out] d Dictionary to pass to the object static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) { tv->v_type = VAR_DICT; tv->vval.v_dict = d; @@ -226,13 +205,11 @@ static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d) } } -static inline long tv_dict_len(const dict_T *d) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the number of items in a Dictionary /// /// @param[in] d Dictionary to check. static inline long tv_dict_len(const dict_T *const d) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (d == NULL) { return 0; @@ -240,22 +217,17 @@ static inline long tv_dict_len(const dict_T *const d) return (long)d->dv_hashtab.ht_used; } -static inline bool tv_dict_is_watched(const dict_T *d) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Check if dictionary is watched /// /// @param[in] d Dictionary to check. /// /// @return true if there is at least one watcher. static inline bool tv_dict_is_watched(const dict_T *const d) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return d && !QUEUE_EMPTY(&d->watchers); } -static inline void tv_blob_set_ret(typval_T *tv, blob_T *b) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1); - /// Set a blob as the return value. /// /// Increments the reference count. @@ -263,6 +235,7 @@ static inline void tv_blob_set_ret(typval_T *tv, blob_T *b) /// @param[out] tv Object to receive the blob. /// @param[in,out] b Blob to pass to the object. static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) { tv->v_type = VAR_BLOB; tv->vval.v_blob = b; @@ -271,13 +244,11 @@ static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b) } } -static inline int tv_blob_len(const blob_T *b) - REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the length of the data in the blob, in bytes. /// /// @param[in] b Blob to check. static inline int tv_blob_len(const blob_T *const b) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (b == NULL) { return 0; @@ -285,9 +256,6 @@ static inline int tv_blob_len(const blob_T *const b) return b->bv_ga.ga_len; } -static inline uint8_t tv_blob_get(const blob_T *b, int idx) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the byte at index `idx` in the blob. /// /// @param[in] b Blob to index. Cannot be NULL. @@ -295,19 +263,18 @@ static inline uint8_t tv_blob_get(const blob_T *b, int idx) /// /// @return Byte value at the given index. static inline uint8_t tv_blob_get(const blob_T *const b, int idx) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { return ((uint8_t *)b->bv_ga.ga_data)[idx]; } -static inline void tv_blob_set(blob_T *blob, int idx, uint8_t c) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL; - /// Store the byte `c` at index `idx` in the blob. /// /// @param[in] b Blob to index. Cannot be NULL. /// @param[in] idx Index in a blob. Must be valid. /// @param[in] c Value to store. static inline void tv_blob_set(blob_T *const blob, int idx, uint8_t c) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL { ((uint8_t *)blob->bv_ga.ga_data)[idx] = c; } @@ -417,9 +384,6 @@ extern bool tv_in_free_unref_items; } \ }) -static inline bool tv_get_float_chk(const typval_T *tv, float_T *ret_f) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - /// Get the float value /// /// Raises an error if object is not number or floating-point. @@ -429,6 +393,7 @@ static inline bool tv_get_float_chk(const typval_T *tv, float_T *ret_f) /// /// @return true in case of success, false if tv is not a number or float. static inline bool tv_get_float_chk(const typval_T *const tv, float_T *const ret_f) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { if (tv->v_type == VAR_FLOAT) { *ret_f = tv->vval.v_float; @@ -442,22 +407,17 @@ static inline bool tv_get_float_chk(const typval_T *const tv, float_T *const ret return false; } -static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET - REAL_FATTR_NO_SANITIZE_ADDRESS REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; - /// Compute the `DictWatcher` address from a QUEUE node. /// /// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer /// arithmetic). static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET + FUNC_ATTR_NO_SANITIZE_ADDRESS FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return QUEUE_DATA(q, DictWatcher, node); } -static inline bool tv_is_func(typval_T tv) - REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST; - /// Check whether given typval_T contains a function /// /// That is, whether it contains VAR_FUNC or VAR_PARTIAL. @@ -466,6 +426,7 @@ static inline bool tv_is_func(typval_T tv) /// /// @return True if it is a function or a partial, false otherwise. static inline bool tv_is_func(const typval_T tv) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST { return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL; } diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h index a6e0bd4b2b..8547783213 100644 --- a/src/nvim/eval/typval_encode.h +++ b/src/nvim/eval/typval_encode.h @@ -11,7 +11,10 @@ #include "klib/kvec.h" #include "nvim/eval/typval_defs.h" -#include "nvim/func_attr.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "eval/typval_encode.h.inline.generated.h" +#endif /// Type of the stack entry typedef enum { @@ -62,10 +65,6 @@ typedef struct { /// Stack used to convert Vimscript values to messagepack. typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack; -static inline size_t tv_strlen(const typval_T *tv) - REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT - REAL_FATTR_NONNULL_ALL; - /// Length of the string stored in typval_T /// /// @param[in] tv String for which to compute length for. Must be typval_T @@ -74,6 +73,8 @@ static inline size_t tv_strlen(const typval_T *tv) /// @return Length of the string stored in typval_T, including 0 for NULL /// string. static inline size_t tv_strlen(const typval_T *const tv) + FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT + FUNC_ATTR_NONNULL_ALL { assert(tv->v_type == VAR_STRING); return (tv->vval.v_string == NULL ? 0 : strlen(tv->vval.v_string)); -- cgit From 185b22720de9156393ddc22c2c59dc3eb46b8d97 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 18 Jul 2024 07:47:20 +0800 Subject: vim-patch:9.0.0003: functions are global while they could be local (#29777) Problem: Functions are global while they could be local. Solution: Add "static". Add a few tests. (Yegappan Lakshmanan, closes vim/vim#10612) https://github.com/vim/vim/commit/ee47eaceaa148e07b566ff420f9a3c2edde2fa34 Omit script_name_after_autoload(), untrans_function_name(): Vim9 script only. Co-authored-by: Yegappan Lakshmanan --- src/nvim/eval/vars.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval') diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 7b93a291c4..2dca942bb5 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -105,7 +105,7 @@ char *eval_one_expr_in_str(char *p, garray_T *gap, bool evaluate) /// string in allocated memory. "{{" is reduced to "{" and "}}" to "}". /// Used for a heredoc assignment. /// Returns NULL for an error. -char *eval_all_expr_in_str(char *str) +static char *eval_all_expr_in_str(char *str) { garray_T ga; ga_init(&ga, 1, 80); -- cgit From 96b358e9f138e60a24c3f3c9b45e9b82ffb92c1c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 30 Jul 2024 11:08:16 +0800 Subject: vim-patch:partial:9.0.0327: items() does not work on a list Problem: items() does not work on a list. (Sergey Vlasov) Solution: Make items() work on a list. (closes vim/vim#11013) https://github.com/vim/vim/commit/976f859763b215050a03248dbc2bb62fa5d0d059 Skip CHECK_LIST_MATERIALIZE. Co-authored-