mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge #4813 'runtime: clipboard: start daemons in /'.
This commit is contained in:
commit
a160590e40
@ -94,6 +94,7 @@ function! s:clipboard.set(lines, regtype, reg)
|
|||||||
let selection.data = [a:lines, a:regtype]
|
let selection.data = [a:lines, a:regtype]
|
||||||
let argv = split(s:copy[a:reg], " ")
|
let argv = split(s:copy[a:reg], " ")
|
||||||
let selection.detach = s:cache_enabled
|
let selection.detach = s:cache_enabled
|
||||||
|
let selection.cwd = "/"
|
||||||
let jobid = jobstart(argv, selection)
|
let jobid = jobstart(argv, selection)
|
||||||
if jobid <= 0
|
if jobid <= 0
|
||||||
echohl WarningMsg
|
echohl WarningMsg
|
||||||
|
@ -4309,21 +4309,24 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
|
|||||||
with 'shell' or 'shellcmdflag' options. The above call is
|
with 'shell' or 'shellcmdflag' options. The above call is
|
||||||
only written to show the idea, one needs to perform unquoting
|
only written to show the idea, one needs to perform unquoting
|
||||||
and do split taking quotes into account.
|
and do split taking quotes into account.
|
||||||
If passed, {opts} must be a dictionary with any of the
|
|
||||||
following keys:
|
{opts} is a dictionary with these keys:
|
||||||
- on_stdout: stdout event handler
|
on_stdout: stdout event handler
|
||||||
- on_stderr: stderr event handler
|
on_stderr: stderr event handler
|
||||||
- on_exit: exit event handler
|
on_exit : exit event handler
|
||||||
- pty: If set, the job will be connected to a new pseudo
|
cwd : Working directory of the job; defaults to
|
||||||
terminal, and the job streams are connected to the master
|
|current-directory|.
|
||||||
file descriptor.
|
pty : If set, the job will be connected to a new pseudo
|
||||||
- width: Width of the terminal screen(only if pty is set)
|
terminal, and the job streams are connected to
|
||||||
- height: Height of the terminal screen(only if pty is set)
|
the master file descriptor.
|
||||||
- TERM: $TERM environment variable(only if pty is set)
|
width : (pty only) Width of the terminal screen
|
||||||
- detach: Detach the job process from the nvim process. The
|
height : (pty only) Height of the terminal screen
|
||||||
process won't get killed when nvim exists. If the process
|
TERM : (pty only) $TERM environment variable
|
||||||
dies before nvim exits, on_exit will still be invoked.
|
detach : (non-pty only) Detach the job process from the
|
||||||
This option is only allowed for non-pty jobs.
|
nvim process. The process will not get killed
|
||||||
|
when nvim exits. If the process dies before
|
||||||
|
nvim exits, on_exit will still be invoked.
|
||||||
|
|
||||||
Either funcrefs or function names can be passed as event
|
Either funcrefs or function names can be passed as event
|
||||||
handlers. The {opts} object is also used as the "self"
|
handlers. The {opts} object is also used as the "self"
|
||||||
argument for the callback, so the caller may pass arbitrary
|
argument for the callback, so the caller may pass arbitrary
|
||||||
|
@ -11742,8 +11742,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;
|
||||||
@ -11753,7 +11766,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) {
|
||||||
@ -16468,8 +16481,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;
|
||||||
@ -16477,7 +16503,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");
|
||||||
@ -16492,11 +16518,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];
|
||||||
@ -21764,7 +21785,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;
|
||||||
@ -21788,6 +21810,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));
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
|
|
||||||
local helpers = require('test.functional.helpers')
|
local helpers = require('test.functional.helpers')
|
||||||
local clear, eq, eval, execute, feed, insert, neq, next_msg, nvim,
|
local clear, eq, eval, execute, feed, insert, neq, next_msg, nvim,
|
||||||
nvim_dir, ok, source, write_file = helpers.clear,
|
nvim_dir, ok, source, write_file, mkdir, rmdir = helpers.clear,
|
||||||
helpers.eq, helpers.eval, helpers.execute, helpers.feed,
|
helpers.eq, helpers.eval, helpers.execute, helpers.feed,
|
||||||
helpers.insert, helpers.neq, helpers.next_message, helpers.nvim,
|
helpers.insert, helpers.neq, helpers.next_message, helpers.nvim,
|
||||||
helpers.nvim_dir, helpers.ok, helpers.source,
|
helpers.nvim_dir, helpers.ok, helpers.source,
|
||||||
helpers.write_file
|
helpers.write_file, helpers.mkdir, helpers.rmdir
|
||||||
local Screen = require('test.functional.ui.screen')
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +37,32 @@ describe('jobs', function()
|
|||||||
eq({'notification', 'exit', {0, 0}}, next_msg())
|
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('changes to given / directory', function()
|
||||||
|
nvim('command', "let g:job_opts.cwd = '/'")
|
||||||
|
nvim('command', "let j = jobstart('pwd', g:job_opts)")
|
||||||
|
eq({'notification', 'stdout', {0, {'/', ''}}}, next_msg())
|
||||||
|
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('changes to given `cwd` directory', function()
|
||||||
|
local dir = eval('resolve(tempname())')
|
||||||
|
mkdir(dir)
|
||||||
|
nvim('command', "let g:job_opts.cwd = '" .. dir .. "'")
|
||||||
|
nvim('command', "let j = jobstart('pwd', g:job_opts)")
|
||||||
|
eq({'notification', 'stdout', {0, {dir, ''}}}, next_msg())
|
||||||
|
eq({'notification', 'exit', {0, 0}}, next_msg())
|
||||||
|
rmdir(dir)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('fails to change to invalid `cwd`', function()
|
||||||
|
local dir = eval('resolve(tempname())."-bogus"')
|
||||||
|
local _, err = pcall(function()
|
||||||
|
nvim('command', "let g:job_opts.cwd = '" .. dir .. "'")
|
||||||
|
nvim('command', "let j = jobstart('pwd', g:job_opts)")
|
||||||
|
end)
|
||||||
|
ok(string.find(err, "E475: Invalid argument: expected valid directory$") ~= nil)
|
||||||
|
end)
|
||||||
|
|
||||||
it('returns 0 when it fails to start', function()
|
it('returns 0 when it fails to start', function()
|
||||||
local status, rv = pcall(eval, "jobstart([])")
|
local status, rv = pcall(eval, "jobstart([])")
|
||||||
eq(false, status)
|
eq(false, status)
|
||||||
|
Loading…
Reference in New Issue
Block a user