forked from aniani/vim
patch 7.4.1310
Problem: Jobs don't open a channel. Solution: Create pipes and add them to the channel. Add ch_logfile(). Only Unix for now.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
*eval.txt* For Vim version 7.4. Last change: 2016 Feb 07
|
*eval.txt* For Vim version 7.4. Last change: 2016 Feb 13
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@@ -1416,7 +1416,7 @@ v:exception The value of the exception most recently caught and not
|
|||||||
|
|
||||||
*v:false* *false-variable*
|
*v:false* *false-variable*
|
||||||
v:false A Number with value zero. Used to put "false" in JSON. See
|
v:false A Number with value zero. Used to put "false" in JSON. See
|
||||||
|jsonencode()|.
|
|json_encode()|.
|
||||||
When used as a string this evaluates to "false". >
|
When used as a string this evaluates to "false". >
|
||||||
echo v:false
|
echo v:false
|
||||||
< false ~
|
< false ~
|
||||||
@@ -1556,7 +1556,7 @@ v:mouse_col Column number for a mouse click obtained with |getchar()|.
|
|||||||
|
|
||||||
*v:none* *none-variable*
|
*v:none* *none-variable*
|
||||||
v:none An empty String. Used to put an empty item in JSON. See
|
v:none An empty String. Used to put an empty item in JSON. See
|
||||||
|jsonencode()|.
|
|json_encode()|.
|
||||||
When used as a number this evaluates to zero.
|
When used as a number this evaluates to zero.
|
||||||
When used as a string this evaluates to "none". >
|
When used as a string this evaluates to "none". >
|
||||||
echo v:none
|
echo v:none
|
||||||
@@ -1564,7 +1564,7 @@ v:none An empty String. Used to put an empty item in JSON. See
|
|||||||
|
|
||||||
*v:null* *null-variable*
|
*v:null* *null-variable*
|
||||||
v:null An empty String. Used to put "null" in JSON. See
|
v:null An empty String. Used to put "null" in JSON. See
|
||||||
|jsonencode()|.
|
|json_encode()|.
|
||||||
When used as a number this evaluates to zero.
|
When used as a number this evaluates to zero.
|
||||||
When used as a string this evaluates to "null". >
|
When used as a string this evaluates to "null". >
|
||||||
echo v:null
|
echo v:null
|
||||||
@@ -1737,7 +1737,7 @@ v:throwpoint The point where the exception most recently caught and not
|
|||||||
|
|
||||||
*v:true* *true-variable*
|
*v:true* *true-variable*
|
||||||
v:true A Number with value one. Used to put "true" in JSON. See
|
v:true A Number with value one. Used to put "true" in JSON. See
|
||||||
|jsonencode()|.
|
|json_encode()|.
|
||||||
When used as a string this evaluates to "true". >
|
When used as a string this evaluates to "true". >
|
||||||
echo v:true
|
echo v:true
|
||||||
< true ~
|
< true ~
|
||||||
@@ -1816,7 +1816,9 @@ call( {func}, {arglist} [, {dict}])
|
|||||||
any call {func} with arguments {arglist}
|
any call {func} with arguments {arglist}
|
||||||
ceil( {expr}) Float round {expr} up
|
ceil( {expr}) Float round {expr} up
|
||||||
ch_close( {handle}) none close a channel
|
ch_close( {handle}) none close a channel
|
||||||
|
ch_logfile( {fname} [, {mode}]) none start logging channel activity
|
||||||
ch_open( {address} [, {argdict})] Number open a channel to {address}
|
ch_open( {address} [, {argdict})] Number open a channel to {address}
|
||||||
|
ch_readraw( {handle}) String read from channel {handle}
|
||||||
ch_sendexpr( {handle}, {expr} [, {callback}])
|
ch_sendexpr( {handle}, {expr} [, {callback}])
|
||||||
any send {expr} over JSON channel {handle}
|
any send {expr} over JSON channel {handle}
|
||||||
ch_sendraw( {handle}, {string} [, {callback}])
|
ch_sendraw( {handle}, {string} [, {callback}])
|
||||||
@@ -1980,9 +1982,9 @@ mapcheck( {name}[, {mode} [, {abbr}]])
|
|||||||
String check for mappings matching {name}
|
String check for mappings matching {name}
|
||||||
match( {expr}, {pat}[, {start}[, {count}]])
|
match( {expr}, {pat}[, {start}[, {count}]])
|
||||||
Number position where {pat} matches in {expr}
|
Number position where {pat} matches in {expr}
|
||||||
matchadd( {group}, {pattern}[, {priority}[, {id}]])
|
matchadd( {group}, {pattern}[, {priority}[, {id} [, {dict}]]])
|
||||||
Number highlight {pattern} with {group}
|
Number highlight {pattern} with {group}
|
||||||
matchaddpos( {group}, {list}[, {priority}[, {id}]])
|
matchaddpos( {group}, {pos}[, {priority}[, {id}[, {dict}]]])
|
||||||
Number highlight positions with {group}
|
Number highlight positions with {group}
|
||||||
matcharg( {nr}) List arguments of |:match|
|
matcharg( {nr}) List arguments of |:match|
|
||||||
matchdelete( {id}) Number delete match identified by {id}
|
matchdelete( {id}) Number delete match identified by {id}
|
||||||
@@ -2274,7 +2276,7 @@ assert_fails({cmd} [, {error}]) *assert_fails()*
|
|||||||
assert_false({actual} [, {msg}]) *assert_false()*
|
assert_false({actual} [, {msg}]) *assert_false()*
|
||||||
When {actual} is not false an error message is added to
|
When {actual} is not false an error message is added to
|
||||||
|v:errors|, like with |assert_equal()|.
|
|v:errors|, like with |assert_equal()|.
|
||||||
A value is false when it is zero. When "{actual}" is not a
|
A value is false when it is zero. When {actual} is not a
|
||||||
number the assert fails.
|
number the assert fails.
|
||||||
When {msg} is omitted an error in the form "Expected False but
|
When {msg} is omitted an error in the form "Expected False but
|
||||||
got {actual}" is produced.
|
got {actual}" is produced.
|
||||||
@@ -2676,10 +2678,16 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
|
|||||||
don't fit, a vertical layout is used anyway. For some systems
|
don't fit, a vertical layout is used anyway. For some systems
|
||||||
the horizontal layout is always used.
|
the horizontal layout is always used.
|
||||||
|
|
||||||
ch_close({handle}) *ch_close()*
|
ch_close({handle}) *ch_close()*
|
||||||
Close channel {handle}. See |channel|.
|
Close channel {handle}. See |channel|.
|
||||||
{only available when compiled with the |+channel| feature}
|
{only available when compiled with the |+channel| feature}
|
||||||
|
|
||||||
|
ch_logfile( {fname} [, {mode}]) *ch_logfile()*
|
||||||
|
Start logging channel activity to {fname}.
|
||||||
|
When {mode} is omitted or "a" append to the file.
|
||||||
|
When {mode} is "w" start with an empty file.
|
||||||
|
When {fname} is an empty string: stop logging.
|
||||||
|
|
||||||
ch_open({address} [, {argdict}]) *ch_open()*
|
ch_open({address} [, {argdict}]) *ch_open()*
|
||||||
Open a channel to {address}. See |channel|.
|
Open a channel to {address}. See |channel|.
|
||||||
Returns the channel handle on success. Returns a negative
|
Returns the channel handle on success. Returns a negative
|
||||||
@@ -2703,7 +2711,13 @@ ch_open({address} [, {argdict}]) *ch_open()*
|
|||||||
Default: 2000.
|
Default: 2000.
|
||||||
{only available when compiled with the |+channel| feature}
|
{only available when compiled with the |+channel| feature}
|
||||||
|
|
||||||
ch_sendexpr({handle}, {expr} [, {callback}]) *ch_sendexpr()*
|
ch_readraw({handle}) *ch_readraw()*
|
||||||
|
Read from channel {handle} and return the received message.
|
||||||
|
This uses the channel timeout. When there is nothing to read
|
||||||
|
within that time an empty string is returned.
|
||||||
|
TODO: depends on channel mode.
|
||||||
|
|
||||||
|
ch_sendexpr({handle}, {expr} [, {callback}]) *ch_sendexpr()*
|
||||||
Send {expr} over channel {handle}. The {expr} is encoded
|
Send {expr} over channel {handle}. The {expr} is encoded
|
||||||
according to the type of channel. The function cannot be used
|
according to the type of channel. The function cannot be used
|
||||||
with a raw channel. See |channel-use|. *E912*
|
with a raw channel. See |channel-use|. *E912*
|
||||||
@@ -2844,9 +2858,11 @@ deepcopy({expr}[, {noref}]) *deepcopy()* *E698*
|
|||||||
different from using {expr} directly.
|
different from using {expr} directly.
|
||||||
When {expr} is a |List| a full copy is created. This means
|
When {expr} is a |List| a full copy is created. This means
|
||||||
that the original |List| can be changed without changing the
|
that the original |List| can be changed without changing the
|
||||||
copy, and vice versa. When an item is a |List|, a copy for it
|
copy, and vice versa. When an item is a |List| or
|
||||||
is made, recursively. Thus changing an item in the copy does
|
|Dictionary|, a copy for it is made, recursively. Thus
|
||||||
not change the contents of the original |List|.
|
changing an item in the copy does not change the contents of
|
||||||
|
the original |List|.
|
||||||
|
A |Dictionary| is copied in a similar way as a |List|.
|
||||||
When {noref} is omitted or zero a contained |List| or
|
When {noref} is omitted or zero a contained |List| or
|
||||||
|Dictionary| is only copied once. All references point to
|
|Dictionary| is only copied once. All references point to
|
||||||
this single copy. With {noref} set to 1 every occurrence of a
|
this single copy. With {noref} set to 1 every occurrence of a
|
||||||
@@ -2907,6 +2923,14 @@ diff_hlID({lnum}, {col}) *diff_hlID()*
|
|||||||
The highlight ID can be used with |synIDattr()| to obtain
|
The highlight ID can be used with |synIDattr()| to obtain
|
||||||
syntax information about the highlighting.
|
syntax information about the highlighting.
|
||||||
|
|
||||||
|
*disable_char_avail_for_testing()*
|
||||||
|
disable_char_avail_for_testing({expr})
|
||||||
|
When {expr} is 1 the internal char_avail() function will
|
||||||
|
return FALSE. When {expr} is 0 the char_avail() function will
|
||||||
|
function normally.
|
||||||
|
Only use this for a test where typeahead causes the test not
|
||||||
|
to work. E.g., to trigger the CursorMovedI autocommand event.
|
||||||
|
|
||||||
empty({expr}) *empty()*
|
empty({expr}) *empty()*
|
||||||
Return the Number 1 if {expr} is empty, zero otherwise.
|
Return the Number 1 if {expr} is empty, zero otherwise.
|
||||||
- A |List| or |Dictionary| is empty when it does not have any
|
- A |List| or |Dictionary| is empty when it does not have any
|
||||||
@@ -3937,7 +3961,7 @@ glob2regpat({expr}) *glob2regpat()*
|
|||||||
empty string.
|
empty string.
|
||||||
|
|
||||||
*globpath()*
|
*globpath()*
|
||||||
globpath({path}, {expr} [, {nosuf} [, {list} [, {allinks}]]])
|
globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]])
|
||||||
Perform glob() on all directories in {path} and concatenate
|
Perform glob() on all directories in {path} and concatenate
|
||||||
the results. Example: >
|
the results. Example: >
|
||||||
:echo globpath(&rtp, "syntax/c.vim")
|
:echo globpath(&rtp, "syntax/c.vim")
|
||||||
@@ -3963,7 +3987,7 @@ globpath({path}, {expr} [, {nosuf} [, {list} [, {allinks}]]])
|
|||||||
they are separated by <NL> characters. Example: >
|
they are separated by <NL> characters. Example: >
|
||||||
:echo globpath(&rtp, "syntax/c.vim", 0, 1)
|
:echo globpath(&rtp, "syntax/c.vim", 0, 1)
|
||||||
<
|
<
|
||||||
{allinks} is used as with |glob()|.
|
{alllinks} is used as with |glob()|.
|
||||||
|
|
||||||
The "**" item can be used to search in a directory tree.
|
The "**" item can be used to search in a directory tree.
|
||||||
For example, to find all "README.txt" files in the directories
|
For example, to find all "README.txt" files in the directories
|
||||||
@@ -4314,22 +4338,25 @@ job_start({command} [, {options}]) *job_start()*
|
|||||||
Start a job and return a Job object. Unlike |system()| and
|
Start a job and return a Job object. Unlike |system()| and
|
||||||
|:!cmd| this does not wait for the job to finish.
|
|:!cmd| this does not wait for the job to finish.
|
||||||
|
|
||||||
{command} can be a string. This works best on MS-Windows. On
|
{command} can be a String. This works best on MS-Windows. On
|
||||||
Unix it is split up in white-separated parts to be passed to
|
Unix it is split up in white-separated parts to be passed to
|
||||||
execvp(). Arguments in double quotes can contain white space.
|
execvp(). Arguments in double quotes can contain white space.
|
||||||
|
|
||||||
{command} can be a list, where the first item is the executable
|
{command} can be a List, where the first item is the executable
|
||||||
and further items are the arguments. All items are converted
|
and further items are the arguments. All items are converted
|
||||||
to String. This works best on Unix.
|
to String. This works best on Unix.
|
||||||
|
|
||||||
|
On MS-Windows, job_start() makes a GUI application hidden. If
|
||||||
|
want to show it, Use |:!start| instead.
|
||||||
|
|
||||||
The command is executed directly, not through a shell, the
|
The command is executed directly, not through a shell, the
|
||||||
'shell' option is not used. To use the shell: >
|
'shell' option is not used. To use the shell: >
|
||||||
let job = job_start(["/bin/sh", "-c", "echo hello"])
|
let job = job_start(["/bin/sh", "-c", "echo hello"])
|
||||||
< Or: >
|
< Or: >
|
||||||
let job = job_start('/bin/sh -c "echo hello"')
|
let job = job_start('/bin/sh -c "echo hello"')
|
||||||
< However, the status of the job will now be the status of the
|
< Note that this will start two processes, the shell and the
|
||||||
shell, and stopping the job means stopping the shell and the
|
command it executes. If you don't want this use the "exec"
|
||||||
command may continue to run.
|
shell command.
|
||||||
|
|
||||||
On Unix $PATH is used to search for the executable only when
|
On Unix $PATH is used to search for the executable only when
|
||||||
the command does not contain a slash.
|
the command does not contain a slash.
|
||||||
@@ -4342,12 +4369,10 @@ job_start({command} [, {options}]) *job_start()*
|
|||||||
The returned Job object can be used to get the status with
|
The returned Job object can be used to get the status with
|
||||||
|job_status()| and stop the job with |job_stop()|.
|
|job_status()| and stop the job with |job_stop()|.
|
||||||
|
|
||||||
{options} must be a Dictionary. It can contain these optional
|
{options} must be a Dictionary. It can contain many optional
|
||||||
items:
|
items, see |job-options|.
|
||||||
killonexit When non-zero kill the job when Vim
|
|
||||||
exits. (default: 0, don't kill)
|
|
||||||
|
|
||||||
{only available when compiled with the |+channel| feature}
|
{only available when compiled with the |+job| feature}
|
||||||
|
|
||||||
job_status({job}) *job_status()*
|
job_status({job}) *job_status()*
|
||||||
Returns a String with the status of {job}:
|
Returns a String with the status of {job}:
|
||||||
@@ -4355,27 +4380,40 @@ job_status({job}) *job_status()*
|
|||||||
"fail" job failed to start
|
"fail" job failed to start
|
||||||
"dead" job died or was stopped after running
|
"dead" job died or was stopped after running
|
||||||
|
|
||||||
{only available when compiled with the |+channel| feature}
|
{only available when compiled with the |+job| feature}
|
||||||
|
|
||||||
job_stop({job} [, {how}]) *job_stop()*
|
job_stop({job} [, {how}]) *job_stop()*
|
||||||
Stop the {job}. This can also be used to signal the job.
|
Stop the {job}. This can also be used to signal the job.
|
||||||
|
|
||||||
When {how} is omitted or is "term" the job will be terminated
|
When {how} is omitted or is "term" the job will be terminated
|
||||||
normally. For Unix SIGTERM is sent.
|
normally. For Unix SIGTERM is sent. For MS-Windows
|
||||||
Other values:
|
CTRL_BREAK will be sent. This goes to the process group, thus
|
||||||
|
children may also be affected.
|
||||||
|
|
||||||
|
Other values for Unix:
|
||||||
"hup" Unix: SIGHUP
|
"hup" Unix: SIGHUP
|
||||||
"quit" Unix: SIGQUIT
|
"quit" Unix: SIGQUIT
|
||||||
"kill" Unix: SIGKILL (strongest way to stop)
|
"kill" Unix: SIGKILL (strongest way to stop)
|
||||||
number Unix: signal with that number
|
number Unix: signal with that number
|
||||||
|
|
||||||
|
Other values for MS-Windows:
|
||||||
|
"int" Windows: CTRL_C
|
||||||
|
"kill" Windows: terminate process forcedly
|
||||||
|
Others Windows: CTRL_BREAK
|
||||||
|
|
||||||
|
On Unix the signal is sent to the process group. This means
|
||||||
|
that when the job is "sh -c command" it affects both the shell
|
||||||
|
and the command.
|
||||||
|
|
||||||
The result is a Number: 1 if the operation could be executed,
|
The result is a Number: 1 if the operation could be executed,
|
||||||
0 if "how" is not supported on the system.
|
0 if "how" is not supported on the system.
|
||||||
Note that even when the operation was executed, whether the
|
Note that even when the operation was executed, whether the
|
||||||
job was actually stopped needs to be checked with
|
job was actually stopped needs to be checked with
|
||||||
job_status().
|
job_status().
|
||||||
The operation will even be done when the job wasn't running.
|
The status of the job isn't checked, the operation will even
|
||||||
|
be done when Vim thinks the job isn't running.
|
||||||
|
|
||||||
{only available when compiled with the |+channel| feature}
|
{only available when compiled with the |+job| feature}
|
||||||
|
|
||||||
join({list} [, {sep}]) *join()*
|
join({list} [, {sep}]) *join()*
|
||||||
Join the items in {list} together into one String.
|
Join the items in {list} together into one String.
|
||||||
@@ -4773,7 +4811,7 @@ match({expr}, {pat}[, {start}[, {count}]]) *match()*
|
|||||||
done like 'magic' is set and 'cpoptions' is empty.
|
done like 'magic' is set and 'cpoptions' is empty.
|
||||||
|
|
||||||
*matchadd()* *E798* *E799* *E801*
|
*matchadd()* *E798* *E799* *E801*
|
||||||
matchadd({group}, {pattern}[, {priority}[, {id} [, {dict}]]])
|
matchadd({group}, {pattern}[, {priority}[, {id}[, {dict}]]])
|
||||||
Defines a pattern to be highlighted in the current window (a
|
Defines a pattern to be highlighted in the current window (a
|
||||||
"match"). It will be highlighted with {group}. Returns an
|
"match"). It will be highlighted with {group}. Returns an
|
||||||
identification number (ID), which can be used to delete the
|
identification number (ID), which can be used to delete the
|
||||||
@@ -4809,7 +4847,7 @@ matchadd({group}, {pattern}[, {priority}[, {id} [, {dict}]]])
|
|||||||
highlighted matches. The dict can have the following members:
|
highlighted matches. The dict can have the following members:
|
||||||
|
|
||||||
conceal Special character to show instead of the
|
conceal Special character to show instead of the
|
||||||
match (only for |hl-Conceal| highlighed
|
match (only for |hl-Conceal| highlighted
|
||||||
matches, see |:syn-cchar|)
|
matches, see |:syn-cchar|)
|
||||||
|
|
||||||
The number of matches is not limited, as it is the case with
|
The number of matches is not limited, as it is the case with
|
||||||
@@ -6808,7 +6846,7 @@ type({expr}) The result is a Number, depending on the type of {expr}:
|
|||||||
:if type(myvar) == type({})
|
:if type(myvar) == type({})
|
||||||
:if type(myvar) == type(0.0)
|
:if type(myvar) == type(0.0)
|
||||||
:if type(myvar) == type(v:false)
|
:if type(myvar) == type(v:false)
|
||||||
:if type(myvar) == type(v:none
|
:if type(myvar) == type(v:none)
|
||||||
|
|
||||||
undofile({name}) *undofile()*
|
undofile({name}) *undofile()*
|
||||||
Return the name of the undo file that would be used for a file
|
Return the name of the undo file that would be used for a file
|
||||||
|
795
src/channel.c
795
src/channel.c
File diff suppressed because it is too large
Load Diff
78
src/eval.c
78
src/eval.c
@@ -503,8 +503,10 @@ static void f_call(typval_T *argvars, typval_T *rettv);
|
|||||||
static void f_ceil(typval_T *argvars, typval_T *rettv);
|
static void f_ceil(typval_T *argvars, typval_T *rettv);
|
||||||
#endif
|
#endif
|
||||||
#ifdef FEAT_CHANNEL
|
#ifdef FEAT_CHANNEL
|
||||||
static void f_ch_open(typval_T *argvars, typval_T *rettv);
|
|
||||||
static void f_ch_close(typval_T *argvars, typval_T *rettv);
|
static void f_ch_close(typval_T *argvars, typval_T *rettv);
|
||||||
|
static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
|
||||||
|
static void f_ch_open(typval_T *argvars, typval_T *rettv);
|
||||||
|
static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
|
static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
|
static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
|
||||||
#endif
|
#endif
|
||||||
@@ -624,6 +626,7 @@ static void f_isdirectory(typval_T *argvars, typval_T *rettv);
|
|||||||
static void f_islocked(typval_T *argvars, typval_T *rettv);
|
static void f_islocked(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_items(typval_T *argvars, typval_T *rettv);
|
static void f_items(typval_T *argvars, typval_T *rettv);
|
||||||
#ifdef FEAT_JOB
|
#ifdef FEAT_JOB
|
||||||
|
static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_job_start(typval_T *argvars, typval_T *rettv);
|
static void f_job_start(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_job_stop(typval_T *argvars, typval_T *rettv);
|
static void f_job_stop(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_job_status(typval_T *argvars, typval_T *rettv);
|
static void f_job_status(typval_T *argvars, typval_T *rettv);
|
||||||
@@ -7720,6 +7723,8 @@ failret:
|
|||||||
static void
|
static void
|
||||||
job_free(job_T *job)
|
job_free(job_T *job)
|
||||||
{
|
{
|
||||||
|
if (job->jv_channel >= 0)
|
||||||
|
channel_close(job->jv_channel);
|
||||||
mch_clear_job(job);
|
mch_clear_job(job);
|
||||||
vim_free(job);
|
vim_free(job);
|
||||||
}
|
}
|
||||||
@@ -8083,7 +8088,9 @@ static struct fst
|
|||||||
#endif
|
#endif
|
||||||
#ifdef FEAT_CHANNEL
|
#ifdef FEAT_CHANNEL
|
||||||
{"ch_close", 1, 1, f_ch_close},
|
{"ch_close", 1, 1, f_ch_close},
|
||||||
|
{"ch_logfile", 1, 2, f_ch_logfile},
|
||||||
{"ch_open", 1, 2, f_ch_open},
|
{"ch_open", 1, 2, f_ch_open},
|
||||||
|
{"ch_readraw", 1, 2, f_ch_readraw},
|
||||||
{"ch_sendexpr", 2, 3, f_ch_sendexpr},
|
{"ch_sendexpr", 2, 3, f_ch_sendexpr},
|
||||||
{"ch_sendraw", 2, 3, f_ch_sendraw},
|
{"ch_sendraw", 2, 3, f_ch_sendraw},
|
||||||
#endif
|
#endif
|
||||||
@@ -8207,6 +8214,7 @@ static struct fst
|
|||||||
{"islocked", 1, 1, f_islocked},
|
{"islocked", 1, 1, f_islocked},
|
||||||
{"items", 1, 1, f_items},
|
{"items", 1, 1, f_items},
|
||||||
#ifdef FEAT_JOB
|
#ifdef FEAT_JOB
|
||||||
|
{"job_getchannel", 1, 1, f_job_getchannel},
|
||||||
{"job_start", 1, 2, f_job_start},
|
{"job_start", 1, 2, f_job_start},
|
||||||
{"job_status", 1, 1, f_job_status},
|
{"job_status", 1, 1, f_job_status},
|
||||||
{"job_stop", 1, 2, f_job_stop},
|
{"job_stop", 1, 2, f_job_stop},
|
||||||
@@ -9788,7 +9796,7 @@ get_channel_arg(typval_T *tv)
|
|||||||
}
|
}
|
||||||
ch_idx = tv->vval.v_number;
|
ch_idx = tv->vval.v_number;
|
||||||
|
|
||||||
if (!channel_is_open(ch_idx))
|
if (!channel_can_write_to(ch_idx))
|
||||||
{
|
{
|
||||||
EMSGN(_("E906: not an open channel"), ch_idx);
|
EMSGN(_("E906: not an open channel"), ch_idx);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -9824,6 +9832,32 @@ get_callback(typval_T *arg)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "ch_logfile()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
|
||||||
|
{
|
||||||
|
char_u *fname;
|
||||||
|
char_u *opt = (char_u *)"";
|
||||||
|
char_u buf[NUMBUFLEN];
|
||||||
|
FILE *file = NULL;
|
||||||
|
|
||||||
|
fname = get_tv_string(&argvars[0]);
|
||||||
|
if (argvars[1].v_type == VAR_STRING)
|
||||||
|
opt = get_tv_string_buf(&argvars[1], buf);
|
||||||
|
if (*fname != NUL)
|
||||||
|
{
|
||||||
|
file = fopen((char *)fname, *opt == 'w' ? "w" : "a");
|
||||||
|
if (file == NULL)
|
||||||
|
{
|
||||||
|
EMSG2(_(e_notopen), fname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ch_logfile(file);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "ch_open()" function
|
* "ch_open()" function
|
||||||
*/
|
*/
|
||||||
@@ -9913,6 +9947,27 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
|||||||
rettv->vval.v_number = ch_idx;
|
rettv->vval.v_number = ch_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "ch_readraw()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_ch_readraw(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
int ch_idx;
|
||||||
|
|
||||||
|
/* return an empty string by default */
|
||||||
|
rettv->v_type = VAR_STRING;
|
||||||
|
rettv->vval.v_string = NULL;
|
||||||
|
|
||||||
|
ch_idx = get_channel_arg(&argvars[0]);
|
||||||
|
if (ch_idx < 0)
|
||||||
|
{
|
||||||
|
EMSG(_(e_invarg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rettv->vval.v_string = channel_read_block(ch_idx);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* common for "sendexpr()" and "sendraw()"
|
* common for "sendexpr()" and "sendraw()"
|
||||||
* Returns the channel index if the caller should read the response.
|
* Returns the channel index if the caller should read the response.
|
||||||
@@ -14299,6 +14354,23 @@ f_items(typval_T *argvars, typval_T *rettv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEAT_JOB
|
#ifdef FEAT_JOB
|
||||||
|
/*
|
||||||
|
* "job_getchannel()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_job_getchannel(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
if (argvars[0].v_type != VAR_JOB)
|
||||||
|
EMSG(_(e_invarg));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
job_T *job = argvars[0].vval.v_job;
|
||||||
|
|
||||||
|
rettv->v_type = VAR_NUMBER;
|
||||||
|
rettv->vval.v_number = job->jv_channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "job_start()" function
|
* "job_start()" function
|
||||||
*/
|
*/
|
||||||
@@ -14401,7 +14473,7 @@ theend:
|
|||||||
* "job_status()" function
|
* "job_status()" function
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
f_job_status(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
f_job_status(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
char *result;
|
char *result;
|
||||||
|
|
||||||
|
@@ -1780,10 +1780,10 @@ process_message(void)
|
|||||||
#ifdef FEAT_CHANNEL
|
#ifdef FEAT_CHANNEL
|
||||||
if (msg.message == WM_NETBEANS)
|
if (msg.message == WM_NETBEANS)
|
||||||
{
|
{
|
||||||
int channel_idx = channel_socket2idx((sock_T)msg.wParam);
|
int channel_idx = channel_fd2idx((sock_T)msg.wParam);
|
||||||
|
|
||||||
if (channel_idx >= 0)
|
if (channel_idx >= 0)
|
||||||
channel_read(channel_idx);
|
channel_read(channel_idx, FALSE, "process_message");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
151
src/os_unix.c
151
src/os_unix.c
@@ -3982,6 +3982,42 @@ mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc)
|
|||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_SYSTEM) || defined(FEAT_JOB)
|
||||||
|
static void
|
||||||
|
set_child_environment(void)
|
||||||
|
{
|
||||||
|
# ifdef HAVE_SETENV
|
||||||
|
char envbuf[50];
|
||||||
|
# else
|
||||||
|
static char envbuf_Rows[20];
|
||||||
|
static char envbuf_Columns[20];
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* Simulate to have a dumb terminal (for now) */
|
||||||
|
# ifdef HAVE_SETENV
|
||||||
|
setenv("TERM", "dumb", 1);
|
||||||
|
sprintf((char *)envbuf, "%ld", Rows);
|
||||||
|
setenv("ROWS", (char *)envbuf, 1);
|
||||||
|
sprintf((char *)envbuf, "%ld", Rows);
|
||||||
|
setenv("LINES", (char *)envbuf, 1);
|
||||||
|
sprintf((char *)envbuf, "%ld", Columns);
|
||||||
|
setenv("COLUMNS", (char *)envbuf, 1);
|
||||||
|
# else
|
||||||
|
/*
|
||||||
|
* Putenv does not copy the string, it has to remain valid.
|
||||||
|
* Use a static array to avoid losing allocated memory.
|
||||||
|
*/
|
||||||
|
putenv("TERM=dumb");
|
||||||
|
sprintf(envbuf_Rows, "ROWS=%ld", Rows);
|
||||||
|
putenv(envbuf_Rows);
|
||||||
|
sprintf(envbuf_Rows, "LINES=%ld", Rows);
|
||||||
|
putenv(envbuf_Rows);
|
||||||
|
sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
|
||||||
|
putenv(envbuf_Columns);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -4134,12 +4170,6 @@ mch_call_shell(
|
|||||||
int fd_toshell[2]; /* for pipes */
|
int fd_toshell[2]; /* for pipes */
|
||||||
int fd_fromshell[2];
|
int fd_fromshell[2];
|
||||||
int pipe_error = FALSE;
|
int pipe_error = FALSE;
|
||||||
# ifdef HAVE_SETENV
|
|
||||||
char envbuf[50];
|
|
||||||
# else
|
|
||||||
static char envbuf_Rows[20];
|
|
||||||
static char envbuf_Columns[20];
|
|
||||||
# endif
|
|
||||||
int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
|
int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
|
||||||
|
|
||||||
newcmd = vim_strsave(p_sh);
|
newcmd = vim_strsave(p_sh);
|
||||||
@@ -4349,28 +4379,7 @@ mch_call_shell(
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
/* Simulate to have a dumb terminal (for now) */
|
set_child_environment();
|
||||||
# ifdef HAVE_SETENV
|
|
||||||
setenv("TERM", "dumb", 1);
|
|
||||||
sprintf((char *)envbuf, "%ld", Rows);
|
|
||||||
setenv("ROWS", (char *)envbuf, 1);
|
|
||||||
sprintf((char *)envbuf, "%ld", Rows);
|
|
||||||
setenv("LINES", (char *)envbuf, 1);
|
|
||||||
sprintf((char *)envbuf, "%ld", Columns);
|
|
||||||
setenv("COLUMNS", (char *)envbuf, 1);
|
|
||||||
# else
|
|
||||||
/*
|
|
||||||
* Putenv does not copy the string, it has to remain valid.
|
|
||||||
* Use a static array to avoid losing allocated memory.
|
|
||||||
*/
|
|
||||||
putenv("TERM=dumb");
|
|
||||||
sprintf(envbuf_Rows, "ROWS=%ld", Rows);
|
|
||||||
putenv(envbuf_Rows);
|
|
||||||
sprintf(envbuf_Rows, "LINES=%ld", Rows);
|
|
||||||
putenv(envbuf_Rows);
|
|
||||||
sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
|
|
||||||
putenv(envbuf_Columns);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stderr is only redirected when using the GUI, so that a
|
* stderr is only redirected when using the GUI, so that a
|
||||||
@@ -5030,13 +5039,34 @@ error:
|
|||||||
void
|
void
|
||||||
mch_start_job(char **argv, job_T *job)
|
mch_start_job(char **argv, job_T *job)
|
||||||
{
|
{
|
||||||
pid_t pid = fork();
|
pid_t pid;
|
||||||
|
int fd_in[2]; /* for stdin */
|
||||||
|
int fd_out[2]; /* for stdout */
|
||||||
|
int fd_err[2]; /* for stderr */
|
||||||
|
int ch_idx;
|
||||||
|
|
||||||
if (pid == -1) /* maybe we should use vfork() */
|
/* default is to fail */
|
||||||
|
job->jv_status = JOB_FAILED;
|
||||||
|
fd_in[0] = -1;
|
||||||
|
fd_out[0] = -1;
|
||||||
|
fd_err[0] = -1;
|
||||||
|
|
||||||
|
/* Open pipes for stdin, stdout, stderr. */
|
||||||
|
if ((pipe(fd_in) < 0) || (pipe(fd_out) < 0) ||(pipe(fd_err) < 0))
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
ch_idx = add_channel();
|
||||||
|
if (ch_idx < 0)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
pid = fork(); /* maybe we should use vfork() */
|
||||||
|
if (pid == -1)
|
||||||
{
|
{
|
||||||
job->jv_status = JOB_FAILED;
|
/* failed to fork */
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
else if (pid == 0)
|
|
||||||
|
if (pid == 0)
|
||||||
{
|
{
|
||||||
/* child */
|
/* child */
|
||||||
reset_signals(); /* handle signals normally */
|
reset_signals(); /* handle signals normally */
|
||||||
@@ -5048,17 +5078,62 @@ mch_start_job(char **argv, job_T *job)
|
|||||||
(void)setsid();
|
(void)setsid();
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
set_child_environment();
|
||||||
|
|
||||||
|
/* set up stdin for the child */
|
||||||
|
close(fd_in[1]);
|
||||||
|
close(0);
|
||||||
|
ignored = dup(fd_in[0]);
|
||||||
|
close(fd_in[0]);
|
||||||
|
|
||||||
|
/* set up stdout for the child */
|
||||||
|
close(fd_out[0]);
|
||||||
|
close(1);
|
||||||
|
ignored = dup(fd_out[1]);
|
||||||
|
close(fd_out[1]);
|
||||||
|
|
||||||
|
/* set up stderr for the child */
|
||||||
|
close(fd_err[0]);
|
||||||
|
close(2);
|
||||||
|
ignored = dup(fd_err[1]);
|
||||||
|
close(fd_err[1]);
|
||||||
|
|
||||||
/* See above for type of argv. */
|
/* See above for type of argv. */
|
||||||
execvp(argv[0], argv);
|
execvp(argv[0], argv);
|
||||||
|
|
||||||
perror("executing job failed");
|
perror("executing job failed");
|
||||||
_exit(EXEC_FAILED); /* exec failed, return failure code */
|
_exit(EXEC_FAILED); /* exec failed, return failure code */
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/* parent */
|
||||||
|
job->jv_pid = pid;
|
||||||
|
job->jv_status = JOB_STARTED;
|
||||||
|
job->jv_channel = ch_idx;
|
||||||
|
|
||||||
|
/* child stdin, stdout and stderr */
|
||||||
|
close(fd_in[0]);
|
||||||
|
close(fd_out[1]);
|
||||||
|
close(fd_err[1]);
|
||||||
|
channel_set_pipes(ch_idx, fd_in[1], fd_out[0], fd_err[0]);
|
||||||
|
channel_set_job(ch_idx, job);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
if (fd_in[0] >= 0)
|
||||||
{
|
{
|
||||||
/* parent */
|
close(fd_in[0]);
|
||||||
job->jv_pid = pid;
|
close(fd_in[1]);
|
||||||
job->jv_status = JOB_STARTED;
|
}
|
||||||
|
if (fd_out[0] >= 0)
|
||||||
|
{
|
||||||
|
close(fd_out[0]);
|
||||||
|
close(fd_out[1]);
|
||||||
|
}
|
||||||
|
if (fd_err[0] >= 0)
|
||||||
|
{
|
||||||
|
close(fd_err[0]);
|
||||||
|
close(fd_err[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5104,8 +5179,8 @@ mch_job_status(job_T *job)
|
|||||||
int
|
int
|
||||||
mch_stop_job(job_T *job, char_u *how)
|
mch_stop_job(job_T *job, char_u *how)
|
||||||
{
|
{
|
||||||
int sig = -1;
|
int sig = -1;
|
||||||
pid_t job_pid;
|
pid_t job_pid;
|
||||||
|
|
||||||
if (STRCMP(how, "hup") == 0)
|
if (STRCMP(how, "hup") == 0)
|
||||||
sig = SIGHUP;
|
sig = SIGHUP;
|
||||||
|
@@ -1,22 +1,27 @@
|
|||||||
/* channel.c */
|
/* channel.c */
|
||||||
|
void ch_logfile(FILE *file);
|
||||||
|
int add_channel(void);
|
||||||
void channel_gui_register_all(void);
|
void channel_gui_register_all(void);
|
||||||
int channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void));
|
int channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void));
|
||||||
|
void channel_set_pipes(int idx, int in, int out, int err);
|
||||||
|
void channel_set_job(int idx, job_T *job);
|
||||||
void channel_set_json_mode(int idx, ch_mode_T ch_mode);
|
void channel_set_json_mode(int idx, ch_mode_T ch_mode);
|
||||||
void channel_set_timeout(int idx, int timeout);
|
void channel_set_timeout(int idx, int timeout);
|
||||||
void channel_set_callback(int idx, char_u *callback);
|
void channel_set_callback(int idx, char_u *callback);
|
||||||
void channel_set_req_callback(int idx, char_u *callback, int id);
|
void channel_set_req_callback(int idx, char_u *callback, int id);
|
||||||
char_u *channel_get(int idx);
|
char_u *channel_get(int idx);
|
||||||
int channel_collapse(int idx);
|
int channel_collapse(int idx);
|
||||||
|
int channel_can_write_to(int idx);
|
||||||
int channel_is_open(int idx);
|
int channel_is_open(int idx);
|
||||||
void channel_close(int idx);
|
void channel_close(int idx);
|
||||||
int channel_save(int idx, char_u *buf, int len);
|
int channel_save(int idx, char_u *buf, int len);
|
||||||
char_u *channel_peek(int idx);
|
char_u *channel_peek(int idx);
|
||||||
void channel_clear(int idx);
|
void channel_clear(int idx);
|
||||||
int channel_get_id(void);
|
int channel_get_id(void);
|
||||||
void channel_read(int idx);
|
void channel_read(int idx, int use_stderr, char *func);
|
||||||
char_u *channel_read_block(int idx);
|
char_u *channel_read_block(int idx);
|
||||||
int channel_read_json_block(int ch_idx, int id, typval_T **rettv);
|
int channel_read_json_block(int ch_idx, int id, typval_T **rettv);
|
||||||
int channel_socket2idx(sock_T fd);
|
int channel_fd2idx(sock_T fd);
|
||||||
int channel_send(int idx, char_u *buf, char *fun);
|
int channel_send(int idx, char_u *buf, char *fun);
|
||||||
int channel_poll_setup(int nfd_in, void *fds_in);
|
int channel_poll_setup(int nfd_in, void *fds_in);
|
||||||
int channel_poll_check(int ret_in, void *fds_in);
|
int channel_poll_check(int ret_in, void *fds_in);
|
||||||
|
@@ -1110,7 +1110,12 @@ typedef double float_T;
|
|||||||
|
|
||||||
typedef struct listvar_S list_T;
|
typedef struct listvar_S list_T;
|
||||||
typedef struct dictvar_S dict_T;
|
typedef struct dictvar_S dict_T;
|
||||||
|
|
||||||
typedef struct jobvar_S job_T;
|
typedef struct jobvar_S job_T;
|
||||||
|
typedef struct readq_S readq_T;
|
||||||
|
typedef struct jsonq_S jsonq_T;
|
||||||
|
typedef struct cbq_S cbq_T;
|
||||||
|
typedef struct channel_S channel_T;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -1255,8 +1260,92 @@ struct jobvar_S
|
|||||||
jobstatus_T jv_status;
|
jobstatus_T jv_status;
|
||||||
|
|
||||||
int jv_refcount; /* reference count */
|
int jv_refcount; /* reference count */
|
||||||
|
int jv_channel; /* channel for I/O */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structures to hold info about a Channel.
|
||||||
|
*/
|
||||||
|
struct readq_S
|
||||||
|
{
|
||||||
|
char_u *buffer;
|
||||||
|
readq_T *next;
|
||||||
|
readq_T *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jsonq_S
|
||||||
|
{
|
||||||
|
typval_T *value;
|
||||||
|
jsonq_T *next;
|
||||||
|
jsonq_T *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cbq_S
|
||||||
|
{
|
||||||
|
char_u *callback;
|
||||||
|
int seq_nr;
|
||||||
|
cbq_T *next;
|
||||||
|
cbq_T *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* mode for a channel */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MODE_RAW = 0,
|
||||||
|
MODE_JSON,
|
||||||
|
MODE_JS
|
||||||
|
} ch_mode_T;
|
||||||
|
|
||||||
|
struct channel_S {
|
||||||
|
sock_T ch_sock; /* the socket, -1 for a closed channel */
|
||||||
|
|
||||||
|
#ifdef UNIX
|
||||||
|
# define CHANNEL_PIPES
|
||||||
|
int ch_in; /* stdin of the job, -1 if not used */
|
||||||
|
int ch_out; /* stdout of the job, -1 if not used */
|
||||||
|
int ch_err; /* stderr of the job, -1 if not used */
|
||||||
|
|
||||||
|
# if defined(UNIX) && !defined(HAVE_SELECT)
|
||||||
|
int ch_sock_idx; /* used by channel_poll_setup() */
|
||||||
|
int ch_in_idx; /* used by channel_poll_setup() */
|
||||||
|
int ch_out_idx; /* used by channel_poll_setup() */
|
||||||
|
int ch_err_idx; /* used by channel_poll_setup() */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
readq_T ch_head; /* dummy node, header for circular queue */
|
||||||
|
|
||||||
|
int ch_error; /* When TRUE an error was reported. Avoids
|
||||||
|
* giving pages full of error messages when
|
||||||
|
* the other side has exited, only mention the
|
||||||
|
* first error until the connection works
|
||||||
|
* again. */
|
||||||
|
#ifdef FEAT_GUI_X11
|
||||||
|
XtInputId ch_inputHandler; /* Cookie for input */
|
||||||
|
#endif
|
||||||
|
#ifdef FEAT_GUI_GTK
|
||||||
|
gint ch_inputHandler; /* Cookie for input */
|
||||||
|
#endif
|
||||||
|
#ifdef WIN32
|
||||||
|
int ch_inputHandler; /* simply ret.value of WSAAsyncSelect() */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void (*ch_close_cb)(void); /* callback for when channel is closed */
|
||||||
|
|
||||||
|
int ch_block_id; /* ID that channel_read_json_block() is
|
||||||
|
waiting for */
|
||||||
|
char_u *ch_callback; /* function to call when a msg is not handled */
|
||||||
|
cbq_T ch_cb_head; /* dummy node for pre-request callbacks */
|
||||||
|
|
||||||
|
ch_mode_T ch_mode;
|
||||||
|
jsonq_T ch_json_head; /* dummy node, header for circular queue */
|
||||||
|
|
||||||
|
int ch_timeout; /* request timeout in msec */
|
||||||
|
|
||||||
|
job_T *ch_job; /* job that uses this channel */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* structure used for explicit stack while garbage collecting hash tables */
|
/* structure used for explicit stack while garbage collecting hash tables */
|
||||||
typedef struct ht_stack_S
|
typedef struct ht_stack_S
|
||||||
{
|
{
|
||||||
@@ -2729,11 +2818,3 @@ struct js_reader
|
|||||||
void *js_cookie; /* can be used by js_fill */
|
void *js_cookie; /* can be used by js_fill */
|
||||||
};
|
};
|
||||||
typedef struct js_reader js_read_T;
|
typedef struct js_reader js_read_T;
|
||||||
|
|
||||||
/* mode for a channel */
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
MODE_RAW = 0,
|
|
||||||
MODE_JSON,
|
|
||||||
MODE_JS
|
|
||||||
} ch_mode_T;
|
|
||||||
|
@@ -273,3 +273,20 @@ func Test_connect_waittime()
|
|||||||
call assert_true(reltimefloat(elapsed) < (has('unix') ? 1.0 : 3.0))
|
call assert_true(reltimefloat(elapsed) < (has('unix') ? 1.0 : 3.0))
|
||||||
endif
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_pipe()
|
||||||
|
if !has('job') || !has('unix')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let job = job_start("python test_channel_pipe.py")
|
||||||
|
call assert_equal("run", job_status(job))
|
||||||
|
try
|
||||||
|
let handle = job_getchannel(job)
|
||||||
|
call ch_sendraw(handle, "echo something\n", 0)
|
||||||
|
call assert_equal("something\n", ch_readraw(handle))
|
||||||
|
let reply = ch_sendraw(handle, "quit\n")
|
||||||
|
call assert_equal("Goodbye!\n", reply)
|
||||||
|
finally
|
||||||
|
call job_stop(job)
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
24
src/testdir/test_channel_pipe.py
Normal file
24
src/testdir/test_channel_pipe.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Server that will communicate over stdin/stderr
|
||||||
|
#
|
||||||
|
# This requires Python 2.6 or later.
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
print(sys.argv[1])
|
||||||
|
|
||||||
|
while True:
|
||||||
|
typed = sys.stdin.readline()
|
||||||
|
if typed.startswith("quit"):
|
||||||
|
print("Goodbye!")
|
||||||
|
sys.stdout.flush()
|
||||||
|
break
|
||||||
|
if typed.startswith("echo"):
|
||||||
|
print(typed[5:-1])
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
@@ -747,6 +747,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1310,
|
||||||
/**/
|
/**/
|
||||||
1309,
|
1309,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user