mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
Merge pull request #24984 from zeertzjq/backport
Backport to release-0.9
This commit is contained in:
@@ -829,6 +829,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
|
|||||||
size_t ncells = (size_t)(endcol - startcol);
|
size_t ncells = (size_t)(endcol - startcol);
|
||||||
int last_hl = -1;
|
int last_hl = -1;
|
||||||
uint32_t nelem = 0;
|
uint32_t nelem = 0;
|
||||||
|
bool was_space = false;
|
||||||
for (size_t i = 0; i < ncells; i++) {
|
for (size_t i = 0; i < ncells; i++) {
|
||||||
repeat++;
|
repeat++;
|
||||||
if (i == ncells - 1 || attrs[i] != attrs[i + 1]
|
if (i == ncells - 1 || attrs[i] != attrs[i + 1]
|
||||||
@@ -867,9 +868,12 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
|
|||||||
data->ncells_pending += MIN(repeat, 2);
|
data->ncells_pending += MIN(repeat, 2);
|
||||||
last_hl = attrs[i];
|
last_hl = attrs[i];
|
||||||
repeat = 0;
|
repeat = 0;
|
||||||
|
was_space = strequal(chunk[i], " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (endcol < clearcol) {
|
// If the last chunk was all spaces, add a clearing chunk even if there are
|
||||||
|
// no more cells to clear, so there is no ambiguity about what to clear.
|
||||||
|
if (endcol < clearcol || was_space) {
|
||||||
nelem++;
|
nelem++;
|
||||||
data->ncells_pending += 1;
|
data->ncells_pending += 1;
|
||||||
mpack_array(buf, 3);
|
mpack_array(buf, 3);
|
||||||
|
@@ -309,6 +309,7 @@ static void close_cb(Stream *stream, void *data)
|
|||||||
///
|
///
|
||||||
/// @param[in] argv Arguments vector specifying the command to run,
|
/// @param[in] argv Arguments vector specifying the command to run,
|
||||||
/// NULL-terminated
|
/// NULL-terminated
|
||||||
|
/// @param[in] exepath The path to the executable. If NULL, use `argv[0]`.
|
||||||
/// @param[in] on_stdout Callback to read the job's stdout
|
/// @param[in] on_stdout Callback to read the job's stdout
|
||||||
/// @param[in] on_stderr Callback to read the job's stderr
|
/// @param[in] on_stderr Callback to read the job's stderr
|
||||||
/// @param[in] on_exit Callback to receive the job's exit status
|
/// @param[in] on_exit Callback to receive the job's exit status
|
||||||
@@ -330,10 +331,11 @@ static void close_cb(Stream *stream, void *data)
|
|||||||
/// < 0 if the job can't start
|
/// < 0 if the job can't start
|
||||||
///
|
///
|
||||||
/// @returns [allocated] channel
|
/// @returns [allocated] channel
|
||||||
Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader on_stderr,
|
Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_stdout,
|
||||||
Callback on_exit, bool pty, bool rpc, bool overlapped, bool detach,
|
CallbackReader on_stderr, Callback on_exit, bool pty, bool rpc,
|
||||||
ChannelStdinMode stdin_mode, const char *cwd, uint16_t pty_width,
|
bool overlapped, bool detach, ChannelStdinMode stdin_mode,
|
||||||
uint16_t pty_height, dict_T *env, varnumber_T *status_out)
|
const char *cwd, uint16_t pty_width, uint16_t pty_height, dict_T *env,
|
||||||
|
varnumber_T *status_out)
|
||||||
{
|
{
|
||||||
Channel *chan = channel_alloc(kChannelStreamProc);
|
Channel *chan = channel_alloc(kChannelStreamProc);
|
||||||
chan->on_data = on_stdout;
|
chan->on_data = on_stdout;
|
||||||
@@ -364,6 +366,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader
|
|||||||
|
|
||||||
Process *proc = &chan->stream.proc;
|
Process *proc = &chan->stream.proc;
|
||||||
proc->argv = argv;
|
proc->argv = argv;
|
||||||
|
proc->exepath = exepath;
|
||||||
proc->cb = channel_process_exit_cb;
|
proc->cb = channel_process_exit_cb;
|
||||||
proc->events = chan->events;
|
proc->events = chan->events;
|
||||||
proc->detach = detach;
|
proc->detach = detach;
|
||||||
@@ -371,7 +374,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader
|
|||||||
proc->env = env;
|
proc->env = env;
|
||||||
proc->overlapped = overlapped;
|
proc->overlapped = overlapped;
|
||||||
|
|
||||||
char *cmd = xstrdup(proc->argv[0]);
|
char *cmd = xstrdup(process_get_exepath(proc));
|
||||||
bool has_out, has_err;
|
bool has_out, has_err;
|
||||||
if (proc->type == kProcessTypePty) {
|
if (proc->type == kProcessTypePty) {
|
||||||
has_out = true;
|
has_out = true;
|
||||||
|
@@ -4200,7 +4200,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
|
|
||||||
env = create_environment(job_env, clear_env, pty, term_name);
|
env = create_environment(job_env, clear_env, pty, term_name);
|
||||||
|
|
||||||
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, pty,
|
Channel *chan = channel_job_start(argv, NULL, on_stdout, on_stderr, on_exit, pty,
|
||||||
rpc, overlapped, detach, stdin_mode, cwd,
|
rpc, overlapped, detach, stdin_mode, cwd,
|
||||||
width, height, env, &rettv->vval.v_number);
|
width, height, env, &rettv->vval.v_number);
|
||||||
if (chan) {
|
if (chan) {
|
||||||
@@ -6729,7 +6729,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
// The last item of argv must be NULL
|
// The last item of argv must be NULL
|
||||||
argv[i] = NULL;
|
argv[i] = NULL;
|
||||||
|
|
||||||
Channel *chan = channel_job_start(argv, CALLBACK_READER_INIT,
|
Channel *chan = channel_job_start(argv, NULL, CALLBACK_READER_INIT,
|
||||||
CALLBACK_READER_INIT, CALLBACK_NONE,
|
CALLBACK_READER_INIT, CALLBACK_NONE,
|
||||||
false, true, false, false,
|
false, true, false, false,
|
||||||
kChannelStdinPipe, NULL, 0, 0, NULL,
|
kChannelStdinPipe, NULL, 0, 0, NULL,
|
||||||
@@ -8825,7 +8825,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
const bool detach = false;
|
const bool detach = false;
|
||||||
ChannelStdinMode stdin_mode = kChannelStdinPipe;
|
ChannelStdinMode stdin_mode = kChannelStdinPipe;
|
||||||
uint16_t term_width = (uint16_t)MAX(0, curwin->w_width_inner - win_col_off(curwin));
|
uint16_t term_width = (uint16_t)MAX(0, curwin->w_width_inner - win_col_off(curwin));
|
||||||
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit,
|
Channel *chan = channel_job_start(argv, NULL, on_stdout, on_stderr, on_exit,
|
||||||
pty, rpc, overlapped, detach, stdin_mode,
|
pty, rpc, overlapped, detach, stdin_mode,
|
||||||
cwd, term_width, (uint16_t)curwin->w_height_inner,
|
cwd, term_width, (uint16_t)curwin->w_height_inner,
|
||||||
env, &rettv->vval.v_number);
|
env, &rettv->vval.v_number);
|
||||||
|
@@ -24,7 +24,7 @@ int libuv_process_spawn(LibuvProcess *uvproc)
|
|||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
Process *proc = (Process *)uvproc;
|
Process *proc = (Process *)uvproc;
|
||||||
uvproc->uvopts.file = proc->argv[0];
|
uvproc->uvopts.file = process_get_exepath(proc);
|
||||||
uvproc->uvopts.args = proc->argv;
|
uvproc->uvopts.args = proc->argv;
|
||||||
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE;
|
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE;
|
||||||
#ifdef MSWIN
|
#ifdef MSWIN
|
||||||
|
@@ -131,7 +131,7 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
|
|||||||
proc->internal_close_cb = decref;
|
proc->internal_close_cb = decref;
|
||||||
proc->refcount++;
|
proc->refcount++;
|
||||||
kl_push(WatcherPtr, proc->loop->children, proc);
|
kl_push(WatcherPtr, proc->loop->children, proc);
|
||||||
DLOG("new: pid=%d argv=[%s]", proc->pid, proc->argv[0]);
|
DLOG("new: pid=%d exepath=[%s]", proc->pid, process_get_exepath(proc));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,7 @@ struct process {
|
|||||||
uint64_t stopped_time; // process_stop() timestamp
|
uint64_t stopped_time; // process_stop() timestamp
|
||||||
const char *cwd;
|
const char *cwd;
|
||||||
char **argv;
|
char **argv;
|
||||||
|
const char *exepath;
|
||||||
dict_T *env;
|
dict_T *env;
|
||||||
Stream in, out, err;
|
Stream in, out, err;
|
||||||
/// Exit handler. If set, user must call process_free().
|
/// Exit handler. If set, user must call process_free().
|
||||||
@@ -55,6 +56,7 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
|
|||||||
.stopped_time = 0,
|
.stopped_time = 0,
|
||||||
.cwd = NULL,
|
.cwd = NULL,
|
||||||
.argv = NULL,
|
.argv = NULL,
|
||||||
|
.exepath = NULL,
|
||||||
.in = { .closed = false },
|
.in = { .closed = false },
|
||||||
.out = { .closed = false },
|
.out = { .closed = false },
|
||||||
.err = { .closed = false },
|
.err = { .closed = false },
|
||||||
@@ -67,6 +69,12 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the path to the executable of the process.
|
||||||
|
static inline const char *process_get_exepath(Process *proc)
|
||||||
|
{
|
||||||
|
return proc->exepath != NULL ? proc->exepath : proc->argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool process_is_stopped(Process *proc)
|
static inline bool process_is_stopped(Process *proc)
|
||||||
{
|
{
|
||||||
bool exited = (proc->status >= 0);
|
bool exited = (proc->status >= 0);
|
||||||
|
@@ -286,7 +286,7 @@ static void init_child(PtyProcess *ptyproc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *prog = ptyproc->process.argv[0];
|
const char *prog = process_get_exepath(proc);
|
||||||
|
|
||||||
assert(proc->env);
|
assert(proc->env);
|
||||||
environ = tv_dict_to_env(proc->env);
|
environ = tv_dict_to_env(proc->env);
|
||||||
|
@@ -43,7 +43,7 @@ uint64_t ui_client_start_server(int argc, char **argv)
|
|||||||
varnumber_T exit_status;
|
varnumber_T exit_status;
|
||||||
char **args = xmalloc(((size_t)(2 + argc)) * sizeof(char *));
|
char **args = xmalloc(((size_t)(2 + argc)) * sizeof(char *));
|
||||||
int args_idx = 0;
|
int args_idx = 0;
|
||||||
args[args_idx++] = xstrdup(get_vim_var_str(VV_PROGPATH));
|
args[args_idx++] = xstrdup(argv[0]);
|
||||||
args[args_idx++] = xstrdup("--embed");
|
args[args_idx++] = xstrdup("--embed");
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
args[args_idx++] = xstrdup(argv[i]);
|
args[args_idx++] = xstrdup(argv[i]);
|
||||||
@@ -53,8 +53,8 @@ uint64_t ui_client_start_server(int argc, char **argv)
|
|||||||
CallbackReader on_err = CALLBACK_READER_INIT;
|
CallbackReader on_err = CALLBACK_READER_INIT;
|
||||||
on_err.fwd_err = true;
|
on_err.fwd_err = true;
|
||||||
|
|
||||||
Channel *channel = channel_job_start(args, CALLBACK_READER_INIT,
|
Channel *channel = channel_job_start(args, get_vim_var_str(VV_PROGPATH),
|
||||||
on_err, CALLBACK_NONE,
|
CALLBACK_READER_INIT, on_err, CALLBACK_NONE,
|
||||||
false, true, true, false, kChannelStdinPipe,
|
false, true, true, false, kChannelStdinPipe,
|
||||||
NULL, 0, 0, NULL, &exit_status);
|
NULL, 0, 0, NULL, &exit_status);
|
||||||
|
|
||||||
|
@@ -27,8 +27,7 @@ local is_os = helpers.is_os
|
|||||||
local new_pipename = helpers.new_pipename
|
local new_pipename = helpers.new_pipename
|
||||||
local spawn_argv = helpers.spawn_argv
|
local spawn_argv = helpers.spawn_argv
|
||||||
local set_session = helpers.set_session
|
local set_session = helpers.set_session
|
||||||
local feed = helpers.feed
|
local write_file = helpers.write_file
|
||||||
local eval = helpers.eval
|
|
||||||
|
|
||||||
if helpers.skip(helpers.is_os('win')) then return end
|
if helpers.skip(helpers.is_os('win')) then return end
|
||||||
|
|
||||||
@@ -897,7 +896,7 @@ describe('TUI', function()
|
|||||||
feed_data('\022\027[107;33u') -- Meta + k
|
feed_data('\022\027[107;33u') -- Meta + k
|
||||||
feed_data('\022\027[13;41u') -- Super + Meta + Enter
|
feed_data('\022\027[13;41u') -- Super + Meta + Enter
|
||||||
feed_data('\022\027[127;48u') -- Shift + Alt + Ctrl + Super + Meta + Backspace
|
feed_data('\022\027[127;48u') -- Shift + Alt + Ctrl + Super + Meta + Backspace
|
||||||
feed('\n')
|
feed_data('\n')
|
||||||
feed_data('\022\027[57376;9u') -- Super + F13
|
feed_data('\022\027[57376;9u') -- Super + F13
|
||||||
feed_data('\022\027[57377;33u') -- Meta + F14
|
feed_data('\022\027[57377;33u') -- Meta + F14
|
||||||
feed_data('\022\027[57378;41u') -- Super + Meta + F15
|
feed_data('\022\027[57378;41u') -- Super + Meta + F15
|
||||||
@@ -1751,7 +1750,7 @@ describe('TUI', function()
|
|||||||
|
|
|
|
||||||
{5:-- TERMINAL --} |
|
{5:-- TERMINAL --} |
|
||||||
]])
|
]])
|
||||||
feed('i')
|
feed_data('i')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
{1: } |
|
{1: } |
|
||||||
{2:~}{3: }|
|
{2:~}{3: }|
|
||||||
@@ -1789,9 +1788,6 @@ end)
|
|||||||
|
|
||||||
describe('TUI', function()
|
describe('TUI', function()
|
||||||
before_each(clear)
|
before_each(clear)
|
||||||
after_each(function()
|
|
||||||
os.remove('testF')
|
|
||||||
end)
|
|
||||||
|
|
||||||
it('resize at startup #17285 #15044 #11330', function()
|
it('resize at startup #17285 #15044 #11330', function()
|
||||||
local screen = Screen.new(50, 10)
|
local screen = Screen.new(50, 10)
|
||||||
@@ -1822,7 +1818,46 @@ describe('TUI', function()
|
|||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('argv[0] can be overridden #23953', function()
|
||||||
|
if not exec_lua('return pcall(require, "ffi")') then
|
||||||
|
pending('missing LuaJIT FFI')
|
||||||
|
end
|
||||||
|
local script_file = 'Xargv0.lua'
|
||||||
|
write_file(script_file, [=[
|
||||||
|
local ffi = require('ffi')
|
||||||
|
ffi.cdef([[int execl(const char *, const char *, ...);]])
|
||||||
|
ffi.C.execl(vim.v.progpath, 'Xargv0nvim', '--clean')
|
||||||
|
]=])
|
||||||
|
finally(function()
|
||||||
|
os.remove(script_file)
|
||||||
|
end)
|
||||||
|
local screen = thelpers.screen_setup(0, string.format([=[["%s", "--clean", "-l", "%s"]]=],
|
||||||
|
nvim_prog, script_file))
|
||||||
|
screen:expect{grid=[[
|
||||||
|
{1: } |
|
||||||
|
{4:~ }|
|
||||||
|
{4:~ }|
|
||||||
|
{4:~ }|
|
||||||
|
{5:[No Name] 0,0-1 All}|
|
||||||
|
|
|
||||||
|
{3:-- TERMINAL --} |
|
||||||
|
]]}
|
||||||
|
feed_data(':put =v:argv + [v:progname]\n')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
Xargv0nvim |
|
||||||
|
--embed |
|
||||||
|
--clean |
|
||||||
|
{1:X}argv0nvim |
|
||||||
|
{5:[No Name] [+] 5,1 Bot}|
|
||||||
|
4 more lines |
|
||||||
|
{3:-- TERMINAL --} |
|
||||||
|
]]}
|
||||||
|
end)
|
||||||
|
|
||||||
it('with non-tty (pipe) stdout/stderr', function()
|
it('with non-tty (pipe) stdout/stderr', function()
|
||||||
|
finally(function()
|
||||||
|
os.remove('testF')
|
||||||
|
end)
|
||||||
local screen = thelpers.screen_setup(0, '"'..nvim_prog
|
local screen = thelpers.screen_setup(0, '"'..nvim_prog
|
||||||
..' -u NONE -i NONE --cmd \'set noswapfile noshowcmd noruler\' --cmd \'normal iabc\' > /dev/null 2>&1 && cat testF && rm testF"')
|
..' -u NONE -i NONE --cmd \'set noswapfile noshowcmd noruler\' --cmd \'normal iabc\' > /dev/null 2>&1 && cat testF && rm testF"')
|
||||||
feed_data(':w testF\n:q\n')
|
feed_data(':w testF\n:q\n')
|
||||||
@@ -1861,6 +1896,30 @@ describe('TUI', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('draws line with many trailing spaces correctly #24955', function()
|
||||||
|
local screen = thelpers.screen_setup(0, '["'..nvim_prog..[[", "-u", "NONE", "-i", "NONE"]]
|
||||||
|
..[[, "--cmd", "call setline(1, ['1st line' .. repeat(' ', 153), '2nd line'])"]]..']', 80)
|
||||||
|
screen:expect{grid=[[
|
||||||
|
{1:1}st line |
|
||||||
|
|
|
||||||
|
|
|
||||||
|
2nd line |
|
||||||
|
{5:[No Name] [+] 1,1 All}|
|
||||||
|
|
|
||||||
|
{3:-- TERMINAL --} |
|
||||||
|
]]}
|
||||||
|
feed_data('$')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
1st line |
|
||||||
|
|
|
||||||
|
{1: } |
|
||||||
|
2nd line |
|
||||||
|
{5:[No Name] [+] 1,161 All}|
|
||||||
|
|
|
||||||
|
{3:-- TERMINAL --} |
|
||||||
|
]]}
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('TUI UIEnter/UILeave', function()
|
describe('TUI UIEnter/UILeave', function()
|
||||||
@@ -2666,8 +2725,8 @@ describe("TUI as a client", function()
|
|||||||
local client_super = spawn_argv(true)
|
local client_super = spawn_argv(true)
|
||||||
|
|
||||||
set_session(server)
|
set_session(server)
|
||||||
local server_pipe = eval'v:servername'
|
local server_pipe = meths.get_vvar('servername')
|
||||||
feed'iHalloj!<esc>'
|
server:request('nvim_input', 'iHalloj!<Esc>')
|
||||||
|
|
||||||
set_session(client_super)
|
set_session(client_super)
|
||||||
local screen = thelpers.screen_setup(0,
|
local screen = thelpers.screen_setup(0,
|
||||||
|
Reference in New Issue
Block a user