Skip to content

Commit

Permalink
job: Allow spawning jobs connected to pseudo terminals
Browse files Browse the repository at this point in the history
  • Loading branch information
tarruda committed Feb 24, 2015
1 parent 1ec7db7 commit d7e560e
Show file tree
Hide file tree
Showing 12 changed files with 501 additions and 9 deletions.
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ get_compile_flags(NVIM_VERSION_CFLAGS)

add_subdirectory(test/includes)
add_subdirectory(config)
add_subdirectory(test/functional/job) # compile pty test program


# Setup some test-related bits. We do this after going down the tree because we
# need some of the targets.
Expand Down Expand Up @@ -316,5 +318,5 @@ if(BUSTED_PRG)
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DTEST_TYPE=functional
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
DEPENDS nvim)
DEPENDS nvim tty-test)
endif()
1 change: 1 addition & 0 deletions src/nvim/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ list(APPEND NVIM_LINK_LIBRARIES
${LIBTERMKEY_LIBRARIES}
${LIBUNIBILIUM_LIBRARIES}
m
util
${CMAKE_THREAD_LIBS_INIT}
)

Expand Down
57 changes: 54 additions & 3 deletions src/nvim/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -6488,8 +6488,9 @@ static struct fst {
{"isdirectory", 1, 1, f_isdirectory},
{"islocked", 1, 1, f_islocked},
{"items", 1, 1, f_items},
{"jobresize", 3, 3, f_jobresize},
{"jobsend", 2, 2, f_jobsend},
{"jobstart", 2, 3, f_jobstart},
{"jobstart", 2, 4, f_jobstart},
{"jobstop", 1, 1, f_jobstop},
{"join", 1, 2, f_join},
{"keys", 1, 1, f_keys},
Expand Down Expand Up @@ -10665,6 +10666,39 @@ static void f_jobsend(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = job_write(job, buf);
}

// "jobresize()" function
static void f_jobresize(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;

if (check_restricted() || check_secure()) {
return;
}

if (argvars[0].v_type != VAR_NUMBER || argvars[1].v_type != VAR_NUMBER
|| argvars[2].v_type != VAR_NUMBER) {
// job id, width, height
EMSG(_(e_invarg));
return;
}

Job *job = job_find(argvars[0].vval.v_number);

if (!job) {
// Probably an invalid job id
EMSG(_(e_invjob));
return;
}

if (!job_resize(job, argvars[1].vval.v_number, argvars[2].vval.v_number)) {
EMSG(_(e_jobnotpty));
return;
}

rettv->vval.v_number = 1;
}

// "jobstart()" function
static void f_jobstart(typval_T *argvars, typval_T *rettv)
{
Expand All @@ -10682,8 +10716,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)

if (argvars[0].v_type != VAR_STRING
|| argvars[1].v_type != VAR_STRING
|| (argvars[2].v_type != VAR_LIST
&& argvars[2].v_type != VAR_UNKNOWN)) {
|| (argvars[2].v_type != VAR_LIST && argvars[2].v_type != VAR_UNKNOWN)) {
// Wrong argument types
EMSG(_(e_invarg));
return;
Expand Down Expand Up @@ -10731,6 +10764,24 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
opts.stdout_cb = on_job_stdout;
opts.stderr_cb = on_job_stderr;
opts.exit_cb = on_job_exit;

if (args && argvars[3].v_type == VAR_DICT) {
dict_T *job_opts = argvars[3].vval.v_dict;
opts.pty = true;
uint16_t width = get_dict_number(job_opts, (uint8_t *)"width");
if (width > 0) {
opts.width = width;
}
uint16_t height = get_dict_number(job_opts, (uint8_t *)"height");
if (height > 0) {
opts.height = height;
}
char *term = (char *)get_dict_string(job_opts, (uint8_t *)"TERM", true);
if (term) {
opts.term_name = term;
}
}

job_start(opts, &rettv->vval.v_number);

if (rettv->vval.v_number <= 0) {
Expand Down
1 change: 1 addition & 0 deletions src/nvim/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,7 @@ EXTERN char_u e_isadir2[] INIT(= N_("E17: \"%s\" is a directory"));
EXTERN char_u e_invjob[] INIT(= N_("E900: Invalid job id"));
EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full"));
EXTERN char_u e_jobexe[] INIT(= N_("E902: \"%s\" is not an executable"));
EXTERN char_u e_jobnotpty[] INIT(= N_("E904: Job is not connected to a pty"));
EXTERN char_u e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
EXTERN char_u e_markinval[] INIT(= N_("E19: Mark has invalid line number"));
EXTERN char_u e_marknotset[] INIT(= N_("E20: Mark not set"));
Expand Down
11 changes: 11 additions & 0 deletions src/nvim/os/job.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "nvim/os/job.h"
#include "nvim/os/job_defs.h"
#include "nvim/os/job_private.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/rstream.h"
#include "nvim/os/rstream_defs.h"
#include "nvim/os/wstream.h"
Expand Down Expand Up @@ -320,6 +321,16 @@ void *job_data(Job *job)
return job->opts.data;
}

/// Resize the window for a pty job
bool job_resize(Job *job, uint16_t width, uint16_t height)
{
if (!job->opts.pty) {
return false;
}
pty_process_resize(job, width, height);
return true;
}

/// Iterates the table, sending SIGTERM to stopped jobs and SIGKILL to those
/// that didn't die from SIGTERM after a while(exit_timeout is 0).
static void job_stop_timer_cb(uv_timer_t *handle)
Expand Down
13 changes: 12 additions & 1 deletion src/nvim/os/job_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ typedef struct {
job_exit_cb exit_cb;
// Maximum memory used by the job's WStream
size_t maxmem;
// Connect the job to a pseudo terminal
bool pty;
// Initial window dimensions if the job is connected to a pseudo terminal
uint16_t width, height;
// Value for the $TERM environment variable. A default value of "ansi" is
// assumed if NULL
char *term_name;
} JobOptions;

#define JOB_OPTIONS_INIT ((JobOptions) { \
Expand All @@ -46,6 +53,10 @@ typedef struct {
.stdout_cb = NULL, \
.stderr_cb = NULL, \
.exit_cb = NULL, \
.maxmem = 0 \
.maxmem = 0, \
.pty = false, \
.width = 80, \
.height = 24, \
.term_name = NULL \
})
#endif // NVIM_OS_JOB_DEFS_H
21 changes: 17 additions & 4 deletions src/nvim/os/job_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "nvim/os/rstream_defs.h"
#include "nvim/os/wstream_defs.h"
#include "nvim/os/pipe_process.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/shell.h"
#include "nvim/log.h"

Expand Down Expand Up @@ -45,12 +46,16 @@ extern uv_timer_t job_stop_timer;

static inline bool process_spawn(Job *job)
{
return pipe_process_spawn(job);
return job->opts.pty ? pty_process_spawn(job) : pipe_process_spawn(job);
}

static inline void process_init(Job *job)
{
pipe_process_init(job);
if (job->opts.pty) {
pty_process_init(job);
} else {
pipe_process_init(job);
}
}

static inline void process_close(Job *job)
Expand All @@ -59,12 +64,20 @@ static inline void process_close(Job *job)
return;
}
job->closed = true;
pipe_process_close(job);
if (job->opts.pty) {
pty_process_close(job);
} else {
pipe_process_close(job);
}
}

static inline void process_destroy(Job *job)
{
pipe_process_destroy(job);
if (job->opts.pty) {
pty_process_destroy(job);
} else {
pipe_process_destroy(job);
}
}

static inline void job_exit_callback(Job *job)
Expand Down

0 comments on commit d7e560e

Please sign in to comment.