diff options
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r-- | src/nvim/eval/funcs.c | 138 |
1 files changed, 104 insertions, 34 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1a7bbf2d0e..60229e1ebc 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -940,6 +940,52 @@ static void f_char2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) (const char_u *)tv_get_string(&argvars[0])); } +// "charidx()" function +static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + rettv->vval.v_number = -1; + + if (argvars[0].v_type != VAR_STRING + || argvars[1].v_type != VAR_NUMBER + || (argvars[2].v_type != VAR_UNKNOWN + && argvars[2].v_type != VAR_NUMBER)) { + EMSG(_(e_invarg)); + return; + } + + const char *str = tv_get_string_chk(&argvars[0]); + varnumber_T idx = tv_get_number_chk(&argvars[1], NULL); + if (str == NULL || idx < 0) { + return; + } + int countcc = 0; + if (argvars[2].v_type != VAR_UNKNOWN) { + countcc = (int)tv_get_number(&argvars[2]); + } + if (countcc < 0 || countcc > 1) { + EMSG(_(e_invarg)); + return; + } + + int (*ptr2len)(const char_u *); + if (countcc) { + ptr2len = utf_ptr2len; + } else { + ptr2len = utfc_ptr2len; + } + + const char *p; + int len; + for (p = str, len = 0; p <= str + idx; len++) { + if (*p == NUL) { + return; + } + p += ptr2len((const char_u *)p); + } + + rettv->vval.v_number = len > 0 ? len - 1 : 0; +} + /* * "cindent(lnum)" function */ @@ -1629,27 +1675,26 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (u_save(first - 1, last + 1) == FAIL) { rettv->vval.v_number = 1; // FAIL - return; - } - - for (linenr_T lnum = first; lnum <= last; lnum++) { - ml_delete(first, true); - } + } else { + for (linenr_T lnum = first; lnum <= last; lnum++) { + ml_delete(first, true); + } - FOR_ALL_TAB_WINDOWS(tp, wp) { - if (wp->w_buffer == buf) { - if (wp->w_cursor.lnum > last) { - wp->w_cursor.lnum -= count; - } else if (wp->w_cursor.lnum> first) { - wp->w_cursor.lnum = first; - } - if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) { - wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count; + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == buf) { + if (wp->w_cursor.lnum > last) { + wp->w_cursor.lnum -= count; + } else if (wp->w_cursor.lnum> first) { + wp->w_cursor.lnum = first; + } + if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) { + wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count; + } } } + check_cursor_col(); + deleted_lines_mark(first, count); } - check_cursor_col(); - deleted_lines_mark(first, count); if (!is_curbuf) { curbuf = curbuf_save; @@ -2149,7 +2194,7 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) tv_list_alloc_ret(rettv, kListLenMayKnow); int modes = MENU_ALL_MODES; if (argvars[1].v_type == VAR_STRING) { - const char_u *const strmodes = (char_u *)tv_get_string(&argvars[1]); + const char *const strmodes = tv_get_string(&argvars[1]); modes = get_menu_cmd_modes(strmodes, false, NULL, NULL); } menu_get((char_u *)tv_get_string(&argvars[0]), modes, rettv->vval.v_list); @@ -2984,10 +3029,11 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (argvars[0].v_type == VAR_UNKNOWN) { // getchar(): blocking wait. + // TODO(bfredl): deduplicate shared logic with state_enter ? if (!(char_avail() || using_script() || input_available())) { (void)os_inchar(NULL, 0, -1, 0, main_loop.events); if (!multiqueue_empty(main_loop.events)) { - multiqueue_process_events(main_loop.events); + state_handle_k_event(); continue; } } @@ -3135,6 +3181,12 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH | WILD_NO_BEEP; + if (argvars[1].v_type != VAR_STRING) { + EMSG2(_(e_invarg2), "type must be a string"); + return; + } + const char *const type = tv_get_string(&argvars[1]); + if (argvars[2].v_type != VAR_UNKNOWN) { filtered = (bool)tv_get_number_chk(&argvars[2], NULL); } @@ -3148,12 +3200,12 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) options |= WILD_KEEP_ALL; } - if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_STRING) { + if (argvars[0].v_type != VAR_STRING) { EMSG(_(e_invarg)); return; } - if (strcmp(tv_get_string(&argvars[1]), "cmdline") == 0) { + if (strcmp(type, "cmdline") == 0) { set_one_cmd_context(&xpc, tv_get_string(&argvars[0])); xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); goto theend; @@ -3162,15 +3214,14 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) ExpandInit(&xpc); xpc.xp_pattern = (char_u *)tv_get_string(&argvars[0]); xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); - xpc.xp_context = cmdcomplete_str_to_type( - (char_u *)tv_get_string(&argvars[1])); + xpc.xp_context = cmdcomplete_str_to_type(type); if (xpc.xp_context == EXPAND_NOTHING) { - EMSG2(_(e_invarg2), argvars[1].vval.v_string); + EMSG2(_(e_invarg2), type); return; } if (xpc.xp_context == EXPAND_MENUS) { - set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, false); + set_context_in_menu_cmd(&xpc, "menu", xpc.xp_pattern, false); xpc.xp_pattern_len = STRLEN(xpc.xp_pattern); } @@ -4081,7 +4132,9 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) #ifdef _WIN64 "win64", #endif +#ifndef CASE_INSENSITIVE_FILENAME "fname_case", +#endif #ifdef HAVE_ACL "acl", #endif @@ -4912,7 +4965,8 @@ static const char *required_env_vars[] = { static dict_T *create_environment(const dictitem_T *job_env, const bool clear_env, - const bool pty) + const bool pty, + const char * const pty_term_name) { dict_T * env = tv_dict_alloc(); @@ -4946,6 +5000,18 @@ static dict_T *create_environment(const dictitem_T *job_env, } } + // For a pty, we need a sane $TERM set. We can't rely on nvim's environment, + // because the child process is going to be communicating with nvim, not the + // parent terminal. Set a sane default, but let the user override it in the + // job's environment if they want. + if (pty) { + dictitem_T *dv = tv_dict_find(env, S_LEN("TERM")); + if (dv) { + tv_dict_item_remove(env, dv); + } + tv_dict_add_str(env, S_LEN("TERM"), pty_term_name); + } + if (job_env) { tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); } @@ -5055,20 +5121,25 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - env = create_environment(job_env, clear_env, pty); - uint16_t width = 0, height = 0; char *term_name = NULL; if (pty) { width = (uint16_t)tv_dict_get_number(job_opts, "width"); height = (uint16_t)tv_dict_get_number(job_opts, "height"); - term_name = tv_dict_get_string(job_opts, "TERM", true); + // Legacy method, before env option existed, to specify $TERM. No longer + // documented, but still usable to avoid breaking scripts. + term_name = tv_dict_get_string(job_opts, "TERM", false); + if (!term_name) { + term_name = "ansi"; + } } + env = create_environment(job_env, clear_env, pty, term_name); + Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, pty, rpc, overlapped, detach, cwd, width, height, - term_name, env, &rettv->vval.v_number); + env, &rettv->vval.v_number); if (chan) { channel_create_event(chan, NULL); } @@ -7511,7 +7582,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) Channel *chan = channel_job_start(argv, CALLBACK_READER_INIT, CALLBACK_READER_INIT, CALLBACK_NONE, false, true, false, false, NULL, 0, 0, - NULL, NULL, &rettv->vval.v_number); + NULL, &rettv->vval.v_number); if (chan) { channel_create_event(chan, NULL); } @@ -10618,7 +10689,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - env = create_environment(job_env, clear_env, pty); + env = create_environment(job_env, clear_env, pty, "xterm-256color"); const bool rpc = false; const bool overlapped = false; @@ -10627,8 +10698,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, pty, rpc, overlapped, detach, cwd, term_width, curwin->w_height_inner, - xstrdup("xterm-256color"), env, - &rettv->vval.v_number); + env, &rettv->vval.v_number); if (rettv->vval.v_number <= 0) { return; } |