diff options
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r-- | src/nvim/eval/funcs.c | 167 |
1 files changed, 140 insertions, 27 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 6d328953f6..4f9a9fcd68 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1850,15 +1850,30 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr) ptrdiff_t len = end - str; assert(len > 0); const char * value = str + len + 1; - if (tv_dict_find(rettv->vval.v_dict, str, len) != NULL) { + + char c = env[i][len]; + env[i][len] = NUL; + +#ifdef WIN32 + // Upper-case all the keys for Windows so we can detect duplicates + char *const key = strcase_save(str, true); +#else + char *const key = xstrdup(str); +#endif + + env[i][len] = c; + + if (tv_dict_find(rettv->vval.v_dict, key, len) != NULL) { // Since we're traversing from the end of the env block to the front, any // duplicate names encountered should be ignored. This preserves the // semantics of env vars defined later in the env block taking precedence. + xfree(key); continue; } tv_dict_add_str(rettv->vval.v_dict, - str, len, + key, len, value); + xfree(key); } os_free_fullenv(env); } @@ -1953,8 +1968,8 @@ static char_u *get_list_line(int c, void *cookie, int indent, bool do_concat) return (char_u *)(s == NULL ? NULL : xstrdup(s)); } -// "execute(command)" function -static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, + int arg_off) { const int save_msg_silent = msg_silent; const int save_emsg_silent = emsg_silent; @@ -1968,9 +1983,9 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - if (argvars[1].v_type != VAR_UNKNOWN) { + if (argvars[arg_off + 1].v_type != VAR_UNKNOWN) { char buf[NUMBUFLEN]; - const char *const s = tv_get_string_buf_chk(&argvars[1], buf); + const char *const s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf); if (s == NULL) { return; @@ -1997,10 +2012,10 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) msg_col = 0; // prevent leading spaces } - if (argvars[0].v_type != VAR_LIST) { - do_cmdline_cmd(tv_get_string(&argvars[0])); - } else if (argvars[0].vval.v_list != NULL) { - list_T *const list = argvars[0].vval.v_list; + if (argvars[arg_off].v_type != VAR_LIST) { + do_cmdline_cmd(tv_get_string(&argvars[arg_off])); + } else if (argvars[arg_off].vval.v_list != NULL) { + list_T *const list = argvars[arg_off].vval.v_list; tv_list_ref(list); GetListLineCookie cookie = { .l = list, @@ -2032,6 +2047,39 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) capture_ga = save_capture_ga; } +// "execute(command)" function +static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + execute_common(argvars, rettv, fptr, 0); +} + +// "win_execute(win_id, command)" function +static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + tabpage_T *tp; + win_T *wp = win_id2wp_tp(argvars, &tp); + win_T *save_curwin; + tabpage_T *save_curtab; + // Return an empty string if something fails. + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (wp != NULL && tp != NULL) { + pos_T curpos = wp->w_cursor; + if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true) == + OK) { + check_cursor(); + execute_common(argvars, rettv, fptr, 1); + } + restore_win_noblock(save_curwin, save_curtab, true); + + // Update the status line if the cursor moved. + if (win_valid(wp) && !equalpos(curpos, wp->w_cursor)) { + wp->w_redr_status = true; + } + } +} + /// "exepath()" function static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -2499,7 +2547,7 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else { len = strlen(fname); size_t usedlen = 0; - if (mods != NULL && *mods != NUL) { + if (*mods != NUL) { (void)modify_fname((char_u *)mods, false, &usedlen, (char_u **)&fname, &fbuf, &len); } @@ -2737,10 +2785,9 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } else if (strcmp(what, "args") == 0) { rettv->v_type = VAR_LIST; - if (tv_list_alloc_ret(rettv, pt->pt_argc) != NULL) { - for (int i = 0; i < pt->pt_argc; i++) { - tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); - } + tv_list_alloc_ret(rettv, pt->pt_argc); + for (int i = 0; i < pt->pt_argc; i++) { + tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); } } else { EMSG2(_(e_invarg2), what); @@ -3016,7 +3063,10 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) n = safe_vgetc(); } - if (n == K_IGNORE || n == K_VER_SCROLLBAR || n == K_HOR_SCROLLBAR) { + if (n == K_IGNORE + || n == K_MOUSEMOVE + || n == K_VER_SCROLLBAR + || n == K_HOR_SCROLLBAR) { continue; } break; @@ -5061,7 +5111,21 @@ static dict_T *create_environment(const dictitem_T *job_env, } if (job_env) { +#ifdef WIN32 + TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, { + // Always use upper-case keys for Windows so we detect duplicate keys + char *const key = strcase_save((const char *)var->di_key, true); + size_t len = strlen(key); + dictitem_T *dv = tv_dict_find(env, key, len); + if (dv) { + tv_dict_item_remove(env, dv); + } + tv_dict_add_str(env, key, len, tv_get_string(&var->di_tv)); + xfree(key); + }); +#else tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); +#endif } if (pty) { @@ -5504,18 +5568,36 @@ static void f_libcallnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) libcall_common(argvars, rettv, VAR_NUMBER); } -/* - * "line(string)" function - */ +// "line(string, [winid])" function static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr) { linenr_T lnum = 0; - pos_T *fp; + pos_T *fp = NULL; int fnum; - fp = var2fpos(&argvars[0], TRUE, &fnum); - if (fp != NULL) + if (argvars[1].v_type != VAR_UNKNOWN) { + tabpage_T *tp; + win_T *save_curwin; + tabpage_T *save_curtab; + + // use window specified in the second argument + win_T *wp = win_id2wp_tp(&argvars[1], &tp); + if (wp != NULL && tp != NULL) { + if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true) + == OK) { + check_cursor(); + fp = var2fpos(&argvars[0], true, &fnum); + } + restore_win_noblock(save_curwin, save_curtab, true); + } + } else { + // use current window + fp = var2fpos(&argvars[0], true, &fnum); + } + + if (fp != NULL) { lnum = fp->lnum; + } rettv->vval.v_number = lnum; } @@ -9178,6 +9260,7 @@ static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// struct storing information about current sort typedef struct { int item_compare_ic; + bool item_compare_lc; bool item_compare_numeric; bool item_compare_numbers; bool item_compare_float; @@ -9252,10 +9335,10 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) p2 = ""; } if (!sortinfo->item_compare_numeric) { - if (sortinfo->item_compare_ic) { - res = STRICMP(p1, p2); + if (sortinfo->item_compare_lc) { + res = strcoll(p1, p2); } else { - res = STRCMP(p1, p2); + res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2); } } else { double n1, n2; @@ -9390,6 +9473,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) } info.item_compare_ic = false; + info.item_compare_lc = false; info.item_compare_numeric = false; info.item_compare_numbers = false; info.item_compare_float = false; @@ -9434,6 +9518,9 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) } else if (strcmp(info.item_compare_func, "i") == 0) { info.item_compare_func = NULL; info.item_compare_ic = true; + } else if (strcmp(info.item_compare_func, "l") == 0) { + info.item_compare_func = NULL; + info.item_compare_lc = true; } } } @@ -9574,6 +9661,18 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) const char *word = ""; hlf_T attr = HLF_COUNT; size_t len = 0; + const int wo_spell_save = curwin->w_p_spell; + + if (!curwin->w_p_spell) { + did_set_spelllang(curwin); + curwin->w_p_spell = true; + } + + if (*curwin->w_s->b_p_spl == NUL) { + EMSG(_(e_no_spell)); + curwin->w_p_spell = wo_spell_save; + return; + } if (argvars[0].v_type == VAR_UNKNOWN) { // Find the start and length of the badly spelled word. @@ -9582,7 +9681,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) word = (char *)get_cursor_pos_ptr(); curwin->w_set_curswant = true; } - } else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) { + } else if (*curbuf->b_s.b_p_spl != NUL) { const char *str = tv_get_string_chk(&argvars[0]); int capcol = -1; @@ -9600,6 +9699,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } } + curwin->w_p_spell = wo_spell_save; assert(len <= INT_MAX); tv_list_alloc_ret(rettv, 2); @@ -9621,8 +9721,20 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr) int maxcount; garray_T ga = GA_EMPTY_INIT_VALUE; bool need_capital = false; + const int wo_spell_save = curwin->w_p_spell; + + if (!curwin->w_p_spell) { + did_set_spelllang(curwin); + curwin->w_p_spell = true; + } + + if (*curwin->w_s->b_p_spl == NUL) { + EMSG(_(e_no_spell)); + curwin->w_p_spell = wo_spell_save; + return; + } - if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { + if (*curwin->w_s->b_p_spl != NUL) { const char *const str = tv_get_string(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) { maxcount = tv_get_number_chk(&argvars[1], &typeerr); @@ -9649,6 +9761,7 @@ f_spellsuggest_return: tv_list_append_allocated_string(rettv->vval.v_list, p); } ga_clear(&ga); + curwin->w_p_spell = wo_spell_save; } static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) |