diff options
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r-- | src/nvim/eval/funcs.c | 160 |
1 files changed, 139 insertions, 21 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e7fb6ed504..ff91f13444 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7218,6 +7218,61 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) fclose(fd); } +/// "getreginfo()" function +static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + const char *strregname; + if (argvars[0].v_type != VAR_UNKNOWN) { + strregname = tv_get_string_chk(&argvars[0]); + if (strregname == NULL) { + return; + } + } else { + strregname = (const char *)get_vim_var_str(VV_REG); + } + + int regname = (strregname == NULL ? '"' : *strregname); + if (regname == 0 || regname == '@') { + regname = '"'; + } + + tv_dict_alloc_ret(rettv); + dict_T *const dict = rettv->vval.v_dict; + + list_T *const list = get_reg_contents(regname, kGRegExprSrc | kGRegList); + if (list == NULL) { + return; + } + tv_dict_add_list(dict, S_LEN("regcontents"), list); + + char buf[NUMBUFLEN + 2]; + buf[0] = NUL; + buf[1] = NUL; + colnr_T reglen = 0; + switch (get_reg_type(regname, ®len)) { + case kMTLineWise: + buf[0] = 'V'; + break; + case kMTCharWise: + buf[0] = 'v'; + break; + case kMTBlockWise: + vim_snprintf(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1); + break; + case kMTUnknown: + abort(); + } + tv_dict_add_str(dict, S_LEN("regtype"), buf); + + buf[0] = get_register_name(get_unname_register()); + buf[1] = NUL; + if (regname == '"') { + tv_dict_add_str(dict, S_LEN("points_to"), buf); + } else { + tv_dict_add_bool(dict, S_LEN("isunnamed"), regname == buf[0] ? kBoolVarTrue : kBoolVarFalse); + } +} + // "reg_executing()" function static void f_reg_executing(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -9039,6 +9094,36 @@ static void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr) set_qf_ll_list(NULL, argvars, rettv); } +/// Translate a register type string to the yank type and block length +static int get_yank_type(char_u **const pp, MotionType *const yank_type, long *const block_len) + FUNC_ATTR_NONNULL_ALL +{ + char_u *stropt = *pp; + switch (*stropt) { + case 'v': + case 'c': // character-wise selection + *yank_type = kMTCharWise; + break; + case 'V': + case 'l': // line-wise selection + *yank_type = kMTLineWise; + break; + case 'b': + case Ctrl_V: // block-wise selection + *yank_type = kMTBlockWise; + if (ascii_isdigit(stropt[1])) { + stropt++; + *block_len = getdigits_long(&stropt, false, 0) - 1; + stropt--; + } + break; + default: + return FAIL; + } + *pp = stropt; + return OK; +} + /* * "setreg()" function */ @@ -9063,8 +9148,53 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) regname = '"'; } + const typval_T *regcontents = NULL; + int pointreg = 0; + if (argvars[1].v_type == VAR_DICT) { + dict_T *const d = argvars[1].vval.v_dict; + + if (tv_dict_len(d) == 0) { + // Empty dict, clear the register (like setreg(0, [])) + char_u *lstval[2] = { NULL, NULL }; + write_reg_contents_lst(regname, lstval, false, kMTUnknown, -1); + return; + } + + dictitem_T *const di = tv_dict_find(d, "regcontents", -1); + if (di != NULL) { + regcontents = &di->di_tv; + } + + const char *stropt = tv_dict_get_string(d, "regtype", false); + if (stropt != NULL) { + const int ret = get_yank_type((char_u **)&stropt, &yank_type, &block_len); + + if (ret == FAIL || *(++stropt) != NUL) { + EMSG2(_(e_invargval), "value"); + return; + } + } + + if (regname == '"') { + stropt = tv_dict_get_string(d, "points_to", false); + if (stropt != NULL) { + pointreg = *stropt; + regname = pointreg; + } + } else if (tv_dict_get_number(d, "isunnamed")) { + pointreg = regname; + } + } else { + regcontents = &argvars[1]; + } + bool set_unnamed = false; if (argvars[2].v_type != VAR_UNKNOWN) { + if (yank_type != kMTUnknown) { + EMSG2(_(e_toomanyarg), "setreg"); + return; + } + const char *stropt = tv_get_string_chk(&argvars[2]); if (stropt == NULL) { return; // Type error. @@ -9075,33 +9205,18 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) case 'A': // append append = true; break; - case 'v': - case 'c': // character-wise selection - yank_type = kMTCharWise; - break; - case 'V': - case 'l': // line-wise selection - yank_type = kMTLineWise; - break; - case 'b': - case Ctrl_V: // block-wise selection - yank_type = kMTBlockWise; - if (ascii_isdigit(stropt[1])) { - stropt++; - block_len = getdigits_long((char_u **)&stropt, true, 0) - 1; - stropt--; - } - break; case 'u': case '"': // unnamed register set_unnamed = true; break; + default: + get_yank_type((char_u **)&stropt, &yank_type, &block_len); } } } - if (argvars[1].v_type == VAR_LIST) { - list_T *ll = argvars[1].vval.v_list; + if (regcontents != NULL && regcontents->v_type == VAR_LIST) { + list_T *const ll = regcontents->vval.v_list; // If the list is NULL handle like an empty list. const int len = tv_list_len(ll); @@ -9137,14 +9252,17 @@ free_lstval: xfree(*--curallocval); } xfree(lstval); - } else { - const char *strval = tv_get_string_chk(&argvars[1]); + } else if (regcontents != NULL) { + const char *const strval = tv_get_string_chk(regcontents); if (strval == NULL) { return; } write_reg_contents_ex(regname, (const char_u *)strval, STRLEN(strval), append, yank_type, block_len); } + if (pointreg != 0) { + get_yank_register(pointreg, YREG_YANK); + } rettv->vval.v_number = 0; if (set_unnamed) { |