mirror of
https://github.com/neovim/neovim.git
synced 2025-09-18 17:28:23 +00:00
eval: allow setting cwd in {jobstart,termopen}()
Processes in vim are always started in the current directory, which causes issues when the process is a daemon and the current directory is a mountpoint. Fix this by adding an option to set the cwd of the new process with jobstart(). In addition, fix termopen() so that it actually uses the cwd option from the dict (it couldn't previously set the cwd value due to dead code). Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
This commit is contained in:
@@ -11731,8 +11731,21 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
|
|||||||
|
|
||||||
dict_T *job_opts = NULL;
|
dict_T *job_opts = NULL;
|
||||||
ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL;
|
ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL;
|
||||||
|
char *cwd = NULL;
|
||||||
if (argvars[1].v_type == VAR_DICT) {
|
if (argvars[1].v_type == VAR_DICT) {
|
||||||
job_opts = argvars[1].vval.v_dict;
|
job_opts = argvars[1].vval.v_dict;
|
||||||
|
|
||||||
|
char *new_cwd = (char *)get_dict_string(job_opts, (char_u *)"cwd", false);
|
||||||
|
if (new_cwd && strlen(new_cwd) > 0) {
|
||||||
|
cwd = new_cwd;
|
||||||
|
// The new cwd must be a directory.
|
||||||
|
if (!os_isdir((char_u *)cwd)) {
|
||||||
|
EMSG2(_(e_invarg2), "expected valid directory");
|
||||||
|
shell_free_argv(argv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
|
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
|
||||||
shell_free_argv(argv);
|
shell_free_argv(argv);
|
||||||
return;
|
return;
|
||||||
@@ -11742,7 +11755,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
|
|||||||
bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0;
|
bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0;
|
||||||
bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0;
|
bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0;
|
||||||
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
|
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
|
||||||
job_opts, pty, detach);
|
job_opts, pty, detach, cwd);
|
||||||
Process *proc = (Process *)&data->proc;
|
Process *proc = (Process *)&data->proc;
|
||||||
|
|
||||||
if (pty) {
|
if (pty) {
|
||||||
@@ -16424,8 +16437,21 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
|
|||||||
|
|
||||||
ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL;
|
ufunc_T *on_stdout = NULL, *on_stderr = NULL, *on_exit = NULL;
|
||||||
dict_T *job_opts = NULL;
|
dict_T *job_opts = NULL;
|
||||||
|
char *cwd = ".";
|
||||||
if (argvars[1].v_type == VAR_DICT) {
|
if (argvars[1].v_type == VAR_DICT) {
|
||||||
job_opts = argvars[1].vval.v_dict;
|
job_opts = argvars[1].vval.v_dict;
|
||||||
|
|
||||||
|
char *new_cwd = (char *)get_dict_string(job_opts, (char_u *)"cwd", false);
|
||||||
|
if (new_cwd && strlen(new_cwd) > 0) {
|
||||||
|
cwd = new_cwd;
|
||||||
|
// The new cwd must be a directory.
|
||||||
|
if (!os_isdir((char_u *)cwd)) {
|
||||||
|
EMSG2(_(e_invarg2), "expected valid directory");
|
||||||
|
shell_free_argv(argv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
|
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
|
||||||
shell_free_argv(argv);
|
shell_free_argv(argv);
|
||||||
return;
|
return;
|
||||||
@@ -16433,7 +16459,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
|
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
|
||||||
job_opts, true, false);
|
job_opts, true, false, cwd);
|
||||||
data->proc.pty.width = curwin->w_width;
|
data->proc.pty.width = curwin->w_width;
|
||||||
data->proc.pty.height = curwin->w_height;
|
data->proc.pty.height = curwin->w_height;
|
||||||
data->proc.pty.term_name = xstrdup("xterm-256color");
|
data->proc.pty.term_name = xstrdup("xterm-256color");
|
||||||
@@ -16448,11 +16474,6 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
|
|||||||
topts.resize_cb = term_resize;
|
topts.resize_cb = term_resize;
|
||||||
topts.close_cb = term_close;
|
topts.close_cb = term_close;
|
||||||
|
|
||||||
char *cwd = ".";
|
|
||||||
if (argvars[1].v_type == VAR_STRING
|
|
||||||
&& os_isdir(argvars[1].vval.v_string)) {
|
|
||||||
cwd = (char *)argvars[1].vval.v_string;
|
|
||||||
}
|
|
||||||
int pid = data->proc.pty.process.pid;
|
int pid = data->proc.pty.process.pid;
|
||||||
|
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
@@ -21717,7 +21738,8 @@ static inline TerminalJobData *common_job_init(char **argv,
|
|||||||
ufunc_T *on_exit,
|
ufunc_T *on_exit,
|
||||||
dict_T *self,
|
dict_T *self,
|
||||||
bool pty,
|
bool pty,
|
||||||
bool detach)
|
bool detach,
|
||||||
|
char *cwd)
|
||||||
{
|
{
|
||||||
TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));
|
TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));
|
||||||
data->stopped = false;
|
data->stopped = false;
|
||||||
@@ -21741,6 +21763,7 @@ static inline TerminalJobData *common_job_init(char **argv,
|
|||||||
proc->cb = on_process_exit;
|
proc->cb = on_process_exit;
|
||||||
proc->events = data->events;
|
proc->events = data->events;
|
||||||
proc->detach = detach;
|
proc->detach = detach;
|
||||||
|
proc->cwd = cwd;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,7 +25,7 @@ bool libuv_process_spawn(LibuvProcess *uvproc)
|
|||||||
uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
|
uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
|
||||||
}
|
}
|
||||||
uvproc->uvopts.exit_cb = exit_cb;
|
uvproc->uvopts.exit_cb = exit_cb;
|
||||||
uvproc->uvopts.cwd = NULL;
|
uvproc->uvopts.cwd = proc->cwd;
|
||||||
uvproc->uvopts.env = NULL;
|
uvproc->uvopts.env = NULL;
|
||||||
uvproc->uvopts.stdio = uvproc->uvstdio;
|
uvproc->uvopts.stdio = uvproc->uvstdio;
|
||||||
uvproc->uvopts.stdio_count = 3;
|
uvproc->uvopts.stdio_count = 3;
|
||||||
|
@@ -21,6 +21,7 @@ struct process {
|
|||||||
int pid, status, refcount;
|
int pid, status, refcount;
|
||||||
// set to the hrtime of when process_stop was called for the process.
|
// set to the hrtime of when process_stop was called for the process.
|
||||||
uint64_t stopped_time;
|
uint64_t stopped_time;
|
||||||
|
char *cwd;
|
||||||
char **argv;
|
char **argv;
|
||||||
Stream *in, *out, *err;
|
Stream *in, *out, *err;
|
||||||
process_exit_cb cb;
|
process_exit_cb cb;
|
||||||
@@ -40,6 +41,7 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
|
|||||||
.status = 0,
|
.status = 0,
|
||||||
.refcount = 0,
|
.refcount = 0,
|
||||||
.stopped_time = 0,
|
.stopped_time = 0,
|
||||||
|
.cwd = NULL,
|
||||||
.argv = NULL,
|
.argv = NULL,
|
||||||
.in = NULL,
|
.in = NULL,
|
||||||
.out = NULL,
|
.out = NULL,
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "nvim/event/process.h"
|
#include "nvim/event/process.h"
|
||||||
#include "nvim/os/pty_process_unix.h"
|
#include "nvim/os/pty_process_unix.h"
|
||||||
#include "nvim/log.h"
|
#include "nvim/log.h"
|
||||||
|
#include "nvim/os/os.h"
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "os/pty_process_unix.c.generated.h"
|
# include "os/pty_process_unix.c.generated.h"
|
||||||
@@ -131,6 +132,12 @@ static void init_child(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL
|
|||||||
signal(SIGTERM, SIG_DFL);
|
signal(SIGTERM, SIG_DFL);
|
||||||
signal(SIGALRM, SIG_DFL);
|
signal(SIGALRM, SIG_DFL);
|
||||||
|
|
||||||
|
Process *proc = (Process *)ptyproc;
|
||||||
|
if (proc->cwd && os_chdir(proc->cwd) != 0) {
|
||||||
|
fprintf(stderr, "chdir failed: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
|
setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
|
||||||
execvp(ptyproc->process.argv[0], ptyproc->process.argv);
|
execvp(ptyproc->process.argv[0], ptyproc->process.argv);
|
||||||
fprintf(stderr, "execvp failed: %s\n", strerror(errno));
|
fprintf(stderr, "execvp failed: %s\n", strerror(errno));
|
||||||
|
Reference in New Issue
Block a user