diff options
Diffstat (limited to 'src/nvim/eval')
| -rw-r--r-- | src/nvim/eval/decode.c | 4 | ||||
| -rw-r--r-- | src/nvim/eval/encode.c | 4 | ||||
| -rw-r--r-- | src/nvim/eval/executor.c | 2 | ||||
| -rw-r--r-- | src/nvim/eval/funcs.c | 173 | ||||
| -rw-r--r-- | src/nvim/eval/typval.c | 37 |
5 files changed, 166 insertions, 54 deletions
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index 638fef331a..bd4dc87d31 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -147,7 +147,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, tv_clear(&key.val); if (tv_dict_add(last_container.container.vval.v_dict, obj_di) == FAIL) { - assert(false); + abort(); } obj_di->di_tv = obj.val; } else { @@ -480,7 +480,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, break; } default: { - assert(false); + abort(); } } } else { diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 9a9f2e4287..a4d7af7971 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -174,7 +174,7 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack, case kMPConvPartial: { switch (v.data.p.stage) { case kMPConvPartialArgs: { - assert(false); + abort(); break; } case kMPConvPartialSelf: { @@ -237,7 +237,7 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len, char *const buf = xmalloc(len); size_t read_bytes; if (encode_read_from_list(&lrstate, buf, len, &read_bytes) != OK) { - assert(false); + abort(); } assert(len == read_bytes); *ret_buf = buf; diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index da05ecda43..bbba9d12f2 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -118,7 +118,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, return OK; } case VAR_UNKNOWN: { - assert(false); + abort(); } } } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8235d74cbb..1a7bbf2d0e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1798,7 +1798,7 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr) os_copy_fullenv(env, env_size); - for (size_t i = 0; i < env_size; i++) { + for (ssize_t i = env_size - 1; i >= 0; i--) { const char * str = env[i]; const char * const end = strchr(str + (str[0] == '=' ? 1 : 0), '='); @@ -1806,6 +1806,12 @@ 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) { + // 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. + continue; + } tv_dict_add_str(rettv->vval.v_dict, str, len, value); @@ -3301,7 +3307,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } break; case kCdScopeInvalid: // We should never get here - assert(false); + abort(); } if (from) { @@ -4354,7 +4360,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr) break; case kCdScopeInvalid: // We should never get here - assert(false); + abort(); } } @@ -4875,6 +4881,95 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = 1; } +static const char *ignored_env_vars[] = { +#ifndef WIN32 + "COLUMNS", + "LINES", + "TERMCAP", + "COLORFGBG", +#endif + NULL +}; + +/// According to comments in src/win/process.c of libuv, Windows has a few +/// "essential" environment variables. +static const char *required_env_vars[] = { +#ifdef WIN32 + "HOMEDRIVE", + "HOMEPATH", + "LOGONSERVER", + "PATH", + "SYSTEMDRIVE", + "SYSTEMROOT", + "TEMP", + "USERDOMAIN", + "USERNAME", + "USERPROFILE", + "WINDIR", +#endif + NULL +}; + +static dict_T *create_environment(const dictitem_T *job_env, + const bool clear_env, + const bool pty) +{ + dict_T * env = tv_dict_alloc(); + + if (!clear_env) { + typval_T temp_env = TV_INITIAL_VALUE; + f_environ(NULL, &temp_env, NULL); + tv_dict_extend(env, temp_env.vval.v_dict, "force"); + tv_dict_free(temp_env.vval.v_dict); + + if (pty) { + // These environment variables generally shouldn't be propagated to the + // child process. We're removing them here so the user can still decide + // they want to explicitly set them. + for (size_t i = 0; + i < ARRAY_SIZE(ignored_env_vars) && ignored_env_vars[i]; + i++) { + dictitem_T *dv = tv_dict_find(env, ignored_env_vars[i], -1); + if (dv) { + tv_dict_item_remove(env, dv); + } + } +#ifndef WIN32 + // Set COLORTERM to "truecolor" if termguicolors is set and 256 + // otherwise, but only if it was set in the parent terminal at all + dictitem_T *dv = tv_dict_find(env, S_LEN("COLORTERM")); + if (dv) { + tv_dict_item_remove(env, dv); + tv_dict_add_str(env, S_LEN("COLORTERM"), p_tgc ? "truecolor" : "256"); + } +#endif + } + } + + if (job_env) { + tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); + } + + if (pty) { + // Now that the custom environment is configured, we need to ensure certain + // environment variables are present. + for (size_t i = 0; + i < ARRAY_SIZE(required_env_vars) && required_env_vars[i]; + i++) { + size_t len = strlen(required_env_vars[i]); + dictitem_T *dv = tv_dict_find(env, required_env_vars[i], len); + if (!dv) { + const char *env_var = os_getenv(required_env_vars[i]); + if (env_var) { + tv_dict_add_str(env, required_env_vars[i], len, env_var); + } + } + } + } + + return env; +} + // "jobstart()" function static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -4887,7 +4982,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) bool executable = true; char **argv = tv_to_argv(&argvars[0], NULL, &executable); - char **env = NULL; + dict_T *env = NULL; if (!argv) { rettv->vval.v_number = executable ? 0 : -1; return; // Did error message in tv_to_argv. @@ -4911,6 +5006,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) on_stderr = CALLBACK_READER_INIT; Callback on_exit = CALLBACK_NONE; char *cwd = NULL; + dictitem_T *job_env = NULL; if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; @@ -4936,7 +5032,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) #endif char *new_cwd = tv_dict_get_string(job_opts, "cwd", false); - if (new_cwd && strlen(new_cwd) > 0) { + if (new_cwd && *new_cwd != NUL) { cwd = new_cwd; // The new cwd must be a directory. if (!os_isdir_executable((const char *)cwd)) { @@ -4945,52 +5041,22 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } } - dictitem_T *job_env = tv_dict_find(job_opts, S_LEN("env")); - if (job_env) { - if (job_env->di_tv.v_type != VAR_DICT) { - EMSG2(_(e_invarg2), "env"); - shell_free_argv(argv); - return; - } - - size_t custom_env_size = (size_t)tv_dict_len(job_env->di_tv.vval.v_dict); - size_t i = 0; - size_t env_size = 0; - - if (clear_env) { - // + 1 for last null entry - env = xmalloc((custom_env_size + 1) * sizeof(*env)); - env_size = 0; - } else { - env_size = os_get_fullenv_size(); - env = xmalloc((custom_env_size + env_size + 1) * sizeof(*env)); - - os_copy_fullenv(env, env_size); - i = env_size; - } - assert(env); // env must be allocated at this point - - TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, { - const char *str = tv_get_string(&var->di_tv); - assert(str); - size_t len = STRLEN(var->di_key) + strlen(str) + strlen("=") + 1; - env[i] = xmalloc(len); - snprintf(env[i], len, "%s=%s", (char *)var->di_key, str); - i++; - }); - - // must be null terminated - env[env_size + custom_env_size] = NULL; + job_env = tv_dict_find(job_opts, S_LEN("env")); + if (job_env && job_env->di_tv.v_type != VAR_DICT) { + EMSG2(_(e_invarg2), "env"); + shell_free_argv(argv); + return; } - if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); return; } } + env = create_environment(job_env, clear_env, pty); + uint16_t width = 0, height = 0; char *term_name = NULL; @@ -10518,6 +10584,11 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) Callback on_exit = CALLBACK_NONE; dict_T *job_opts = NULL; const char *cwd = "."; + dict_T *env = NULL; + const bool pty = true; + bool clear_env = false; + dictitem_T *job_env = NULL; + if (argvars[1].v_type == VAR_DICT) { job_opts = argvars[1].vval.v_dict; @@ -10532,17 +10603,31 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } + job_env = tv_dict_find(job_opts, S_LEN("env")); + if (job_env && job_env->di_tv.v_type != VAR_DICT) { + EMSG2(_(e_invarg2), "env"); + shell_free_argv(argv); + return; + } + + clear_env = tv_dict_get_number(job_opts, "clear_env") != 0; + if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) { shell_free_argv(argv); return; } } + env = create_environment(job_env, clear_env, pty); + + const bool rpc = false; + const bool overlapped = false; + const bool detach = false; uint16_t term_width = MAX(0, curwin->w_width_inner - win_col_off(curwin)); Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, - true, false, false, false, cwd, + pty, rpc, overlapped, detach, cwd, term_width, curwin->w_height_inner, - xstrdup("xterm-256color"), NULL, + xstrdup("xterm-256color"), env, &rettv->vval.v_number); if (rettv->vval.v_number <= 0) { return; diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 02d32a4f86..9be487f4fd 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1523,6 +1523,33 @@ varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key) return tv_get_number(&di->di_tv); } +/// Converts a dict to an environment +/// +/// +char **tv_dict_to_env(dict_T *denv) +{ + size_t env_size = (size_t)tv_dict_len(denv); + + size_t i = 0; + char **env = NULL; + + // + 1 for NULL + env = xmalloc((env_size + 1) * sizeof(*env)); + + TV_DICT_ITER(denv, var, { + const char *str = tv_get_string(&var->di_tv); + assert(str); + size_t len = STRLEN(var->di_key) + strlen(str) + strlen("=") + 1; + env[i] = xmalloc(len); + snprintf(env[i], len, "%s=%s", (char *)var->di_key, str); + i++; + }); + + // must be null terminated + env[env_size] = NULL; + return env; +} + /// Get a string item from a dictionary /// /// @param[in] d Dictionary to get item from. @@ -2494,7 +2521,7 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock) break; } case VAR_UNKNOWN: { - assert(false); + abort(); } } #undef CHANGE_LOCK @@ -2666,7 +2693,7 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, } } - assert(false); + abort(); return false; } @@ -2719,7 +2746,7 @@ bool tv_check_str_or_nr(const typval_T *const tv) return false; } } - assert(false); + abort(); return false; } @@ -2764,7 +2791,7 @@ bool tv_check_num(const typval_T *const tv) return false; } } - assert(false); + abort(); return false; } @@ -2809,7 +2836,7 @@ bool tv_check_str(const typval_T *const tv) return false; } } - assert(false); + abort(); return false; } |