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.c138
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;
}