diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index af9d731ab7..3159a305d8 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -74,7 +74,7 @@ static Object typval_cbuf_to_obj(EncodedData *edata, const char *data, size_t le kvi_push(edata->stack, typval_cbuf_to_obj(edata, len_ ? blob_->bv_ga.ga_data : "", len_)); \ } while (0) -#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ do { \ ufunc_T *fp = find_func(fun); \ if (fp != NULL && (fp->uf_flags & FC_LUAREF)) { \ diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 507b3b4211..eb080e1791 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -295,7 +295,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ do { \ const char *const buf_ = (buf); \ - if ((buf) == NULL) { \ + if (buf_ == NULL) { \ ga_concat(gap, "''"); \ } else { \ const size_t len_ = (len); \ @@ -370,15 +370,21 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s } \ } while (0) -#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ do { \ const char *const fun_ = (fun); \ if (fun_ == NULL) { \ internal_error("string(): NULL function name"); \ ga_concat(gap, "function(NULL"); \ } else { \ + const char *const prefix_ = (prefix); \ ga_concat(gap, "function("); \ + const int name_off = gap->ga_len; \ + ga_concat(gap, prefix_); \ TYPVAL_ENCODE_CONV_STRING(tv, fun_, strlen(fun_)); \ + /* '' -> ''. */ \ + ((char *)gap->ga_data)[name_off] = '\''; \ + memcpy((char *)gap->ga_data + name_off + 1, prefix_, strlen(prefix_)); \ } \ } while (0) @@ -748,7 +754,7 @@ static inline int convert_to_json_string(garray_T *const gap, const char *const } while (0) #undef TYPVAL_ENCODE_CONV_FUNC_START -#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ return conv_error(_("E474: Error while dumping %s, %s: " \ "attempt to dump function reference"), \ mpstack, objname) @@ -932,7 +938,7 @@ char *encode_tv2json(typval_T *tv, size_t *len) #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ mpack_float8(&packer->ptr, (double)(flt)) -#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ return conv_error(_("E5004: Error while dumping %s, %s: " \ "attempt to dump function reference"), \ mpstack, objname) diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index e40cf17086..33a4b36728 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -3436,7 +3436,7 @@ static inline int _nothing_conv_func_start(typval_T *const tv, char *const fun) } return NOTDONE; } -#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ do { \ if (_nothing_conv_func_start(tv, fun) != NOTDONE) { \ return OK; \ diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h index 99b740f7cb..e174efb7d5 100644 --- a/src/nvim/eval/typval_encode.c.h +++ b/src/nvim/eval/typval_encode.c.h @@ -102,6 +102,7 @@ /// /// @param tv Pointer to typval where value is stored. May not be NULL. /// @param fun Function name. May be NULL. +/// @param prefix Prefix for converting to a string. /// @def TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS /// @brief Macros used before starting to convert partial arguments @@ -344,15 +345,19 @@ static int TYPVAL_ENCODE_CONVERT_ONE_VALUE( tv_blob_len(tv->vval.v_blob)); break; case VAR_FUNC: - TYPVAL_ENCODE_CONV_FUNC_START(tv, tv->vval.v_string); + TYPVAL_ENCODE_CONV_FUNC_START(tv, tv->vval.v_string, ""); TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, 0); TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, -1); TYPVAL_ENCODE_CONV_FUNC_END(tv); break; case VAR_PARTIAL: { partial_T *const pt = tv->vval.v_partial; - (void)pt; - TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : partial_name(pt))); + char *const fun = pt == NULL ? NULL : partial_name(pt); + // When using uf_name prepend "g:" for a global function. + const char *const prefix = fun != NULL && pt->pt_name == NULL + && ASCII_ISUPPER(fun[0]) ? "g:" : ""; + (void)prefix; + TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix); kvi_push(*mpstack, ((MPConvStackVal) { .type = kMPConvPartial, .tv = tv, diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 16bdc31411..669ad31860 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -453,7 +453,7 @@ static bool typval_conv_special = false; lua_pushlstring(lstate, blob_ != NULL ? blob_->bv_ga.ga_data : "", (size_t)(len)); \ } while (0) -#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ +#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ do { \ ufunc_T *fp = find_func(fun); \ if (fp != NULL && fp->uf_flags & FC_LUAREF) { \ diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim index 1f0cd1f031..d90f2f6102 100644 --- a/test/old/testdir/test_functions.vim +++ b/test/old/testdir/test_functions.vim @@ -3719,6 +3719,11 @@ func Test_builtin_check() unlet bar endfunc +func Test_funcref_to_string() + let Fn = funcref('g:Test_funcref_to_string') + call assert_equal("function('g:Test_funcref_to_string')", string(Fn)) +endfunc + " Test for isabsolutepath() func Test_isabsolutepath() call assert_false(isabsolutepath(''))