aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/funcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/funcs.c')
-rw-r--r--src/nvim/eval/funcs.c167
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)