diff options
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 300 |
1 files changed, 216 insertions, 84 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 31e5ae8806..4e303414a3 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10980,81 +10980,122 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const bool inputdialog) FUNC_ATTR_NONNULL_ALL { - const char *prompt = tv_get_string_chk(&argvars[0]); - int cmd_silent_save = cmd_silent; - int xp_type = EXPAND_NOTHING; - char_u *xp_arg = NULL; - rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - cmd_silent = FALSE; /* Want to see the prompt. */ - if (prompt != NULL) { - // Only the part of the message after the last NL is considered as - // prompt for the command line. - const char *p = strrchr(prompt, '\n'); - if (p == NULL) { - p = prompt; - } else { - p++; - msg_start(); - msg_clr_eos(); - msg_puts_attr_len(prompt, p - prompt, echo_attr); - msg_didout = false; - msg_starthere(); + const char *prompt = ""; + const char *defstr = ""; + const char *cancelreturn = NULL; + const char *xp_name = NULL; + char prompt_buf[NUMBUFLEN]; + char defstr_buf[NUMBUFLEN]; + char cancelreturn_buf[NUMBUFLEN]; + char xp_name_buf[NUMBUFLEN]; + if (argvars[0].v_type == VAR_DICT) { + if (argvars[1].v_type != VAR_UNKNOWN) { + emsgf(_("E5050: {opts} must be the only argument")); + return; + } + const dict_T *const dict = argvars[0].vval.v_dict; + prompt = tv_dict_get_string_buf_chk(dict, S_LEN("prompt"), prompt_buf, ""); + if (prompt == NULL) { + return; + } + defstr = tv_dict_get_string_buf_chk(dict, S_LEN("default"), defstr_buf, ""); + if (defstr == NULL) { + return; + } + char def[1] = { 0 }; + cancelreturn = tv_dict_get_string_buf_chk(dict, S_LEN("cancelreturn"), + cancelreturn_buf, def); + if (cancelreturn == NULL) { // error + return; + } + if (*cancelreturn == NUL) { + cancelreturn = NULL; + } + xp_name = tv_dict_get_string_buf_chk(dict, S_LEN("completion"), + xp_name_buf, def); + if (xp_name == NULL) { // error + return; + } + if (xp_name == def) { // default to NULL + xp_name = NULL; + } + } else { + prompt = tv_get_string_buf_chk(&argvars[0], prompt_buf); + if (prompt == NULL) { + return; } - cmdline_row = msg_row; - - const char *defstr = ""; - char buf[NUMBUFLEN]; if (argvars[1].v_type != VAR_UNKNOWN) { - defstr = tv_get_string_buf_chk(&argvars[1], buf); - if (defstr != NULL) { - stuffReadbuffSpec(defstr); + defstr = tv_get_string_buf_chk(&argvars[1], defstr_buf); + if (defstr == NULL) { + return; } - - if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN) { - char buf2[NUMBUFLEN]; - // input() with a third argument: completion - rettv->vval.v_string = NULL; - - const char *const xp_name = tv_get_string_buf_chk(&argvars[2], buf2); - if (xp_name == NULL) { + if (argvars[2].v_type != VAR_UNKNOWN) { + const char *const arg2 = tv_get_string_buf_chk(&argvars[2], + cancelreturn_buf); + if (arg2 == NULL) { return; } - - const int xp_namelen = (int)strlen(xp_name); - - uint32_t argt; - if (parse_compl_arg((char_u *)xp_name, xp_namelen, &xp_type, &argt, - &xp_arg) == FAIL) { - return; + if (inputdialog) { + cancelreturn = arg2; + } else { + xp_name = arg2; } } } + } - if (defstr != NULL) { - int save_ex_normal_busy = ex_normal_busy; - ex_normal_busy = 0; - rettv->vval.v_string = - getcmdline_prompt(inputsecret_flag ? NUL : '@', (char_u *)p, echo_attr, - xp_type, xp_arg); - ex_normal_busy = save_ex_normal_busy; - } - if (inputdialog && rettv->vval.v_string == NULL - && argvars[1].v_type != VAR_UNKNOWN - && argvars[2].v_type != VAR_UNKNOWN) { - char buf[NUMBUFLEN]; - rettv->vval.v_string = (char_u *)xstrdup(tv_get_string_buf( - &argvars[2], buf)); + int xp_type = EXPAND_NOTHING; + char *xp_arg = NULL; + if (xp_name != NULL) { + // input() with a third argument: completion + const int xp_namelen = (int)strlen(xp_name); + + uint32_t argt; + if (parse_compl_arg((char_u *)xp_name, xp_namelen, &xp_type, + &argt, (char_u **)&xp_arg) == FAIL) { + return; } + } - xfree(xp_arg); + int cmd_silent_save = cmd_silent; - /* since the user typed this, no need to wait for return */ - need_wait_return = FALSE; - msg_didout = FALSE; + cmd_silent = false; // Want to see the prompt. + // Only the part of the message after the last NL is considered as + // prompt for the command line. + const char *p = strrchr(prompt, '\n'); + if (p == NULL) { + p = prompt; + } else { + p++; + msg_start(); + msg_clr_eos(); + msg_puts_attr_len(prompt, p - prompt, echo_attr); + msg_didout = false; + msg_starthere(); + } + cmdline_row = msg_row; + + stuffReadbuffSpec(defstr); + + int save_ex_normal_busy = ex_normal_busy; + ex_normal_busy = 0; + rettv->vval.v_string = + getcmdline_prompt(inputsecret_flag ? NUL : '@', (char_u *)p, echo_attr, + xp_type, (char_u *)xp_arg); + ex_normal_busy = save_ex_normal_busy; + + if (rettv->vval.v_string == NULL && cancelreturn != NULL) { + rettv->vval.v_string = (char_u *)xstrdup(cancelreturn); } + + xfree(xp_arg); + + // Since the user typed this, no need to wait for return. + need_wait_return = false; + msg_didout = false; cmd_silent = cmd_silent_save; } @@ -12061,22 +12102,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) tv_dict_alloc_ret(rettv); if (rhs != NULL) { // Return a dictionary. - char_u *lhs = str2special_save(mp->m_keys, true); - char *const mapmode = map_mode_to_chars(mp->m_mode); - dict_T *dict = rettv->vval.v_dict; - - tv_dict_add_str(dict, S_LEN("lhs"), (const char *)lhs); - tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str); - tv_dict_add_nr(dict, S_LEN("noremap"), mp->m_noremap ? 1 : 0); - tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0); - tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0); - tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ID); - tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_local); - tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0); - tv_dict_add_str(dict, S_LEN("mode"), mapmode); - - xfree(lhs); - xfree(mapmode); + mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true); } } } @@ -12093,6 +12119,46 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) executor_eval_lua(cstr_as_string((char *)str), &argvars[1], rettv); } +/// Fill a dictionary with all applicable maparg() like dictionaries +/// +/// @param dict The dictionary to be filled +/// @param mp The maphash that contains the mapping information +/// @param buffer_value The "buffer" value +/// @param compatible True for compatible with old maparg() dict +void mapblock_fill_dict(dict_T *const dict, + const mapblock_T *const mp, + long buffer_value, + bool compatible) + FUNC_ATTR_NONNULL_ALL +{ + char_u *lhs = str2special_save(mp->m_keys, true); + char *const mapmode = map_mode_to_chars(mp->m_mode); + varnumber_T noremap_value; + + if (compatible) { + // Keep old compatible behavior + // This is unable to determine whether a mapping is a <script> mapping + noremap_value = !!mp->m_noremap; + } else { + // Distinguish between <script> mapping + // If it's not a <script> mapping, check if it's a noremap + noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap; + } + + tv_dict_add_str(dict, S_LEN("lhs"), (const char *)lhs); + tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str); + tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value); + tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0); + tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0); + tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ID); + tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_value); + tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0); + tv_dict_add_str(dict, S_LEN("mode"), mapmode); + + xfree(lhs); + xfree(mapmode); +} + /* * "map()" function */ @@ -13017,8 +13083,9 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) /* have to shuffle buf to close gap */ int adjust_prevlen = 0; - if (dest < buf) { - adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */ + if (dest < buf) { // -V782 + adjust_prevlen = (int)(buf - dest); // -V782 + // adjust_prevlen must be 1 or 2. dest = buf; } if (readlen > p - buf + 1) @@ -14254,22 +14321,39 @@ static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } + char *address; // If the user supplied an address, use it, otherwise use a temp. if (argvars[0].v_type != VAR_UNKNOWN) { if (argvars[0].v_type != VAR_STRING) { EMSG(_(e_invarg)); return; } else { - rettv->vval.v_string = (char_u *)xstrdup(tv_get_string(argvars)); + address = xstrdup(tv_get_string(argvars)); } } else { - rettv->vval.v_string = (char_u *)server_address_new(); + address = server_address_new(); } - int result = server_start((char *) rettv->vval.v_string); + int result = server_start(address); + xfree(address); + if (result != 0) { - EMSG2("Failed to start server: %s", uv_strerror(result)); + EMSG2("Failed to start server: %s", + result > 0 ? "Unknonwn system error" : uv_strerror(result)); + return; + } + + // Since it's possible server_start adjusted the given {address} (e.g., + // "localhost:" will now have a port), return the final value to the user. + size_t n; + char **addrs = server_address_list(&n); + rettv->vval.v_string = (char_u *)addrs[n - 1]; + + n--; + for (size_t i = 0; i < n; i++) { + xfree(addrs[i]); } + xfree(addrs); } /// "serverstop()" function @@ -14974,6 +15058,54 @@ static void f_simplify(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->v_type = VAR_STRING; } +/// "sockconnect()" function +static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_STRING) { + EMSG(_(e_invarg)); + return; + } + if (argvars[2].v_type != VAR_DICT && argvars[2].v_type != VAR_UNKNOWN) { + // Wrong argument types + EMSG2(_(e_invarg2), "expected dictionary"); + return; + } + + const char *mode = tv_get_string(&argvars[0]); + const char *address = tv_get_string(&argvars[1]); + + bool tcp; + if (strcmp(mode, "tcp") == 0) { + tcp = true; + } else if (strcmp(mode, "pipe") == 0) { + tcp = false; + } else { + EMSG2(_(e_invarg2), "invalid mode"); + return; + } + + bool rpc = false; + if (argvars[2].v_type == VAR_DICT) { + dict_T *opts = argvars[2].vval.v_dict; + rpc = tv_dict_get_number(opts, "rpc") != 0; + } + + if (!rpc) { + EMSG2(_(e_invarg2), "rpc option must be true"); + return; + } + + const char *error = NULL; + uint64_t id = channel_connect(tcp, address, 50, &error); + + if (error) { + EMSG2(_("connection failed: %s"), error); + } + + rettv->vval.v_number = (varnumber_T)id; + rettv->v_type = VAR_NUMBER; +} + /// struct used in the array that's given to qsort() typedef struct { listitem_T *item; @@ -21052,9 +21184,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, // Do not want errors such as E724 here. emsg_off++; char *tofree = encode_tv2string(&argvars[i], NULL); - char *s = tofree; emsg_off--; - if (s != NULL) { + if (tofree != NULL) { + char *s = tofree; char buf[MSG_BUF_LEN]; if (vim_strsize((char_u *)s) > MSG_BUF_CLEN) { trunc_string((char_u *)s, (char_u *)buf, MSG_BUF_CLEN, @@ -21118,7 +21250,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, if (func_or_func_caller_profiling) { call_start = profile_end(call_start); - call_start = profile_sub_wait(wait_start, call_start); + call_start = profile_sub_wait(wait_start, call_start); // -V614 fp->uf_tm_total = profile_add(fp->uf_tm_total, call_start); fp->uf_tm_self = profile_self(fp->uf_tm_self, call_start, fp->uf_tm_children); |