mirror of
https://github.com/neovim/neovim.git
synced 2025-12-17 11:55:34 +00:00
Merge PR #2405 'Job control fixes'
This commit is contained in:
@@ -472,7 +472,7 @@ typedef struct {
|
|||||||
#define JobEventFreer(x)
|
#define JobEventFreer(x)
|
||||||
KMEMPOOL_INIT(JobEventPool, JobEvent, JobEventFreer)
|
KMEMPOOL_INIT(JobEventPool, JobEvent, JobEventFreer)
|
||||||
static kmempool_t(JobEventPool) *job_event_pool = NULL;
|
static kmempool_t(JobEventPool) *job_event_pool = NULL;
|
||||||
static bool defer_job_callbacks = true;
|
static int disable_job_defer = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the global and v: variables.
|
* Initialize the global and v: variables.
|
||||||
@@ -5963,11 +5963,12 @@ static bool get_dict_callback(dict_T *d, char *key, ufunc_T **result)
|
|||||||
|
|
||||||
uint8_t *name = di->di_tv.vval.v_string;
|
uint8_t *name = di->di_tv.vval.v_string;
|
||||||
uint8_t *n = name;
|
uint8_t *n = name;
|
||||||
ufunc_T *rv;
|
ufunc_T *rv = NULL;
|
||||||
if (*n > '9' || *n < '0') {
|
if (*n > '9' || *n < '0') {
|
||||||
n = trans_function_name(&n, false, TFN_INT|TFN_QUIET, NULL);
|
if ((n = trans_function_name(&n, false, TFN_INT|TFN_QUIET, NULL))) {
|
||||||
rv = find_func(n);
|
rv = find_func(n);
|
||||||
free(n);
|
free(n);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// dict function, name is already translated
|
// dict function, name is already translated
|
||||||
rv = find_func(n);
|
rv = find_func(n);
|
||||||
@@ -10921,9 +10922,16 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv)
|
|||||||
list_T *args = argvars[0].vval.v_list;
|
list_T *args = argvars[0].vval.v_list;
|
||||||
list_T *rv = list_alloc();
|
list_T *rv = list_alloc();
|
||||||
|
|
||||||
// must temporarily disable job event deferring so the callbacks are
|
ui_busy_start();
|
||||||
// processed while waiting.
|
// disable breakchecks, which could result in job callbacks being executed
|
||||||
defer_job_callbacks = false;
|
// at unexpected places
|
||||||
|
disable_breakcheck++;
|
||||||
|
// disable job event deferring so the callbacks are processed while waiting.
|
||||||
|
if (!disable_job_defer++) {
|
||||||
|
// process any pending job events in the deferred queue, but only do this if
|
||||||
|
// deferred is not disabled(at the top-level `jobwait()` call)
|
||||||
|
event_process();
|
||||||
|
}
|
||||||
// For each item in the input list append an integer to the output list. -3
|
// For each item in the input list append an integer to the output list. -3
|
||||||
// is used to represent an invalid job id, -2 is for a interrupted job and
|
// is used to represent an invalid job id, -2 is for a interrupted job and
|
||||||
// -1 for jobs that were skipped or timed out.
|
// -1 for jobs that were skipped or timed out.
|
||||||
@@ -10996,8 +11004,9 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv)
|
|||||||
// job exits
|
// job exits
|
||||||
data->status_ptr = NULL;
|
data->status_ptr = NULL;
|
||||||
}
|
}
|
||||||
// restore defer flag
|
disable_job_defer--;
|
||||||
defer_job_callbacks = true;
|
disable_breakcheck--;
|
||||||
|
ui_busy_stop();
|
||||||
|
|
||||||
rv->lv_refcount++;
|
rv->lv_refcount++;
|
||||||
rettv->v_type = VAR_LIST;
|
rettv->v_type = VAR_LIST;
|
||||||
@@ -20175,7 +20184,7 @@ static inline void push_job_event(Job *job, ufunc_T *callback,
|
|||||||
event_push((Event) {
|
event_push((Event) {
|
||||||
.handler = on_job_event,
|
.handler = on_job_event,
|
||||||
.data = event_data
|
.data = event_data
|
||||||
}, defer_job_callbacks);
|
}, !disable_job_defer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_job_stdout(RStream *rstream, void *job, bool eof)
|
static void on_job_stdout(RStream *rstream, void *job, bool eof)
|
||||||
|
|||||||
@@ -898,6 +898,14 @@ EXTERN FILE *scriptout INIT(= NULL); /* stream to write script to */
|
|||||||
/* volatile because it is used in signal handler catch_sigint(). */
|
/* volatile because it is used in signal handler catch_sigint(). */
|
||||||
EXTERN volatile int got_int INIT(= FALSE); /* set to TRUE when interrupt
|
EXTERN volatile int got_int INIT(= FALSE); /* set to TRUE when interrupt
|
||||||
signal occurred */
|
signal occurred */
|
||||||
|
EXTERN int disable_breakcheck INIT(= 0); // > 0 if breakchecks should be
|
||||||
|
// ignored. FIXME(tarruda): Hacky
|
||||||
|
// way to run functions that would
|
||||||
|
// result in *_breakcheck calls
|
||||||
|
// while events that would normally
|
||||||
|
// be deferred are being processed
|
||||||
|
// immediately. Ref:
|
||||||
|
// neovim/neovim#2371
|
||||||
EXTERN int bangredo INIT(= FALSE); /* set to TRUE with ! command */
|
EXTERN int bangredo INIT(= FALSE); /* set to TRUE with ! command */
|
||||||
EXTERN int searchcmdlen; /* length of previous search cmd */
|
EXTERN int searchcmdlen; /* length of previous search cmd */
|
||||||
EXTERN int reg_do_extmatch INIT(= 0); /* Used when compiling regexp:
|
EXTERN int reg_do_extmatch INIT(= 0); /* Used when compiling regexp:
|
||||||
|
|||||||
@@ -128,8 +128,10 @@ bool os_char_avail(void)
|
|||||||
// Check for CTRL-C typed by reading all available characters.
|
// Check for CTRL-C typed by reading all available characters.
|
||||||
void os_breakcheck(void)
|
void os_breakcheck(void)
|
||||||
{
|
{
|
||||||
|
if (!disable_breakcheck && !got_int) {
|
||||||
event_poll(0);
|
event_poll(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Test whether a file descriptor refers to a terminal.
|
/// Test whether a file descriptor refers to a terminal.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -249,6 +249,52 @@ describe('jobs', function()
|
|||||||
eq({'notification', 'wait', {{-2}}}, next_msg())
|
eq({'notification', 'wait', {{-2}}}, next_msg())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can be called recursively', function()
|
||||||
|
source([[
|
||||||
|
let g:opts = {}
|
||||||
|
let g:counter = 0
|
||||||
|
function g:opts.on_stdout(id, msg)
|
||||||
|
if self.state == 0
|
||||||
|
if self.counter < 10
|
||||||
|
call Run()
|
||||||
|
endif
|
||||||
|
let self.state = 1
|
||||||
|
call jobsend(a:id, "line1\n")
|
||||||
|
elseif self.state == 1
|
||||||
|
let self.state = 2
|
||||||
|
call jobsend(a:id, "line2\n")
|
||||||
|
elseif self.state == 2
|
||||||
|
let self.state = 3
|
||||||
|
call jobsend(a:id, "line3\n")
|
||||||
|
else
|
||||||
|
call rpcnotify(g:channel, 'w', printf('job %d closed', self.counter))
|
||||||
|
call jobclose(a:id, 'stdin')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
function g:opts.on_exit()
|
||||||
|
call rpcnotify(g:channel, 'w', printf('job %d exited', self.counter))
|
||||||
|
endfunction
|
||||||
|
function Run()
|
||||||
|
let g:counter += 1
|
||||||
|
let j = copy(g:opts)
|
||||||
|
let j.state = 0
|
||||||
|
let j.counter = g:counter
|
||||||
|
call jobwait([
|
||||||
|
\ jobstart([&sh, '-c', 'echo ready; cat -'], j),
|
||||||
|
\ ])
|
||||||
|
endfunction
|
||||||
|
]])
|
||||||
|
execute('call Run()')
|
||||||
|
local r
|
||||||
|
for i = 10, 1, -1 do
|
||||||
|
r = next_msg()
|
||||||
|
eq('job '..i..' closed', r[3][1])
|
||||||
|
r = next_msg()
|
||||||
|
eq('job '..i..' exited', r[3][1])
|
||||||
|
end
|
||||||
|
eq(10, nvim('eval', 'g:counter'))
|
||||||
|
end)
|
||||||
|
|
||||||
describe('with timeout argument', function()
|
describe('with timeout argument', function()
|
||||||
it('will return -1 if the wait timed out', function()
|
it('will return -1 if the wait timed out', function()
|
||||||
source([[
|
source([[
|
||||||
@@ -292,7 +338,7 @@ describe('jobs', function()
|
|||||||
data[i] = data[i]:gsub('\n', '\000')
|
data[i] = data[i]:gsub('\n', '\000')
|
||||||
end
|
end
|
||||||
rv = table.concat(data, '\n')
|
rv = table.concat(data, '\n')
|
||||||
rv = rv:gsub('\r\n$', '')
|
rv = rv:gsub('\r\n$', ''):gsub('^\r\n', '')
|
||||||
if rv ~= '' then
|
if rv ~= '' then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|||||||
1
third-party/cmake/BuildLuarocks.cmake
vendored
1
third-party/cmake/BuildLuarocks.cmake
vendored
@@ -57,7 +57,6 @@ add_custom_target(stable-busted-deps
|
|||||||
add_custom_command(OUTPUT ${DEPS_BIN_DIR}/busted
|
add_custom_command(OUTPUT ${DEPS_BIN_DIR}/busted
|
||||||
COMMAND ${DEPS_BIN_DIR}/luarocks
|
COMMAND ${DEPS_BIN_DIR}/luarocks
|
||||||
ARGS build https://raw.githubusercontent.com/Olivine-Labs/busted/master/busted-scm-0.rockspec CC=${DEPS_C_COMPILER} LD=${DEPS_C_COMPILER}
|
ARGS build https://raw.githubusercontent.com/Olivine-Labs/busted/master/busted-scm-0.rockspec CC=${DEPS_C_COMPILER} LD=${DEPS_C_COMPILER}
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/utfTerminalDetailed.lua
|
|
||||||
${DEPS_INSTALL_DIR}/share/lua/5.1/busted/outputHandlers
|
${DEPS_INSTALL_DIR}/share/lua/5.1/busted/outputHandlers
|
||||||
DEPENDS stable-busted-deps)
|
DEPENDS stable-busted-deps)
|
||||||
add_custom_target(busted
|
add_custom_target(busted
|
||||||
|
|||||||
27
third-party/utfTerminalDetailed.lua
vendored
27
third-party/utfTerminalDetailed.lua
vendored
@@ -1,27 +0,0 @@
|
|||||||
-- busted output handler that immediately prints file and test names before
|
|
||||||
-- tests are executed. It simplifies identifying which tests are
|
|
||||||
-- hanging/crashing
|
|
||||||
if package.config:sub(1,1) == '\\' and not os.getenv("ANSICON") then
|
|
||||||
-- Disable colors on Windows.
|
|
||||||
colors = setmetatable({}, {__index = function() return function(s) return s end end})
|
|
||||||
else
|
|
||||||
colors = require 'term.colors'
|
|
||||||
end
|
|
||||||
|
|
||||||
return function(options, busted)
|
|
||||||
local handler = require 'busted.outputHandlers.utfTerminal'(options, busted)
|
|
||||||
|
|
||||||
handler.fileStart = function(name)
|
|
||||||
io.write('\n' .. colors.cyan(name) .. ':')
|
|
||||||
end
|
|
||||||
|
|
||||||
handler.testStart = function(element, parent, status, debug)
|
|
||||||
io.write('\n ' .. handler.getFullName(element) .. ' ... ')
|
|
||||||
io.flush()
|
|
||||||
end
|
|
||||||
|
|
||||||
busted.subscribe({ 'file', 'start' }, handler.fileStart)
|
|
||||||
busted.subscribe({ 'test', 'start' }, handler.testStart)
|
|
||||||
|
|
||||||
return handler
|
|
||||||
end
|
|
||||||
Reference in New Issue
Block a user