mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 7.4.1857
Problem: When a channel appends to a buffer that is 'nomodifiable' there is an error but appending is done anyway. Solution: Add the 'modifiable' option. Refuse to write to a 'nomodifiable' when the value is 1.
This commit is contained in:
parent
324a78f3b6
commit
9f5842e63f
@ -1,4 +1,4 @@
|
|||||||
*channel.txt* For Vim version 7.4. Last change: 2016 May 24
|
*channel.txt* For Vim version 7.4. Last change: 2016 May 29
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -578,8 +578,8 @@ See |job_setoptions()| and |ch_setoptions()|.
|
|||||||
"exit_cb": handler Callback for when the job ends. The arguments are the
|
"exit_cb": handler Callback for when the job ends. The arguments are the
|
||||||
job and the exit status.
|
job and the exit status.
|
||||||
Vim checks about every 10 seconds for jobs that ended.
|
Vim checks about every 10 seconds for jobs that ended.
|
||||||
The callback can also be triggered by calling
|
The check also be triggered by calling |job_status()|,
|
||||||
|job_status()|.
|
which may then invoke the exit_cb handler.
|
||||||
Note that data can be buffered, callbacks may still be
|
Note that data can be buffered, callbacks may still be
|
||||||
called after the process ends.
|
called after the process ends.
|
||||||
*job-timeout*
|
*job-timeout*
|
||||||
@ -625,18 +625,22 @@ See |job_setoptions()| and |ch_setoptions()|.
|
|||||||
"out_io": "null" disconnect stdout (goes to /dev/null)
|
"out_io": "null" disconnect stdout (goes to /dev/null)
|
||||||
"out_io": "pipe" stdout is connected to the channel (default)
|
"out_io": "pipe" stdout is connected to the channel (default)
|
||||||
"out_io": "file" stdout writes to a file
|
"out_io": "file" stdout writes to a file
|
||||||
"out_io": "buffer" stdout appends to a buffer
|
"out_io": "buffer" stdout appends to a buffer (see below)
|
||||||
"out_name": "/path/file" the name of the file or buffer to write to
|
"out_name": "/path/file" the name of the file or buffer to write to
|
||||||
"out_buf": number the number of the buffer to write to
|
"out_buf": number the number of the buffer to write to
|
||||||
|
"out_modifiable": 0 when writing to a buffer, 'modifiable' will be off
|
||||||
|
(see below)
|
||||||
|
|
||||||
*job-err_io* *err_name* *err_buf*
|
*job-err_io* *err_name* *err_buf*
|
||||||
"err_io": "out" stderr messages to go to stdout
|
"err_io": "out" stderr messages to go to stdout
|
||||||
"err_io": "null" disconnect stderr (goes to /dev/null)
|
"err_io": "null" disconnect stderr (goes to /dev/null)
|
||||||
"err_io": "pipe" stderr is connected to the channel (default)
|
"err_io": "pipe" stderr is connected to the channel (default)
|
||||||
"err_io": "file" stderr writes to a file
|
"err_io": "file" stderr writes to a file
|
||||||
"err_io": "buffer" stderr appends to a buffer
|
"err_io": "buffer" stderr appends to a buffer (see below)
|
||||||
"err_name": "/path/file" the name of the file or buffer to write to
|
"err_name": "/path/file" the name of the file or buffer to write to
|
||||||
"err_buf": number the number of the buffer to write to
|
"err_buf": number the number of the buffer to write to
|
||||||
|
"err_modifiable": 0 when writing to a buffer, 'modifiable' will be off
|
||||||
|
(see below)
|
||||||
|
|
||||||
"block_write": number only for testing: pretend every other write to stdin
|
"block_write": number only for testing: pretend every other write to stdin
|
||||||
will block
|
will block
|
||||||
@ -663,6 +667,15 @@ used to get the buffer number.
|
|||||||
For a new buffer 'buftype' is set to "nofile" and 'bufhidden' to "hide". If
|
For a new buffer 'buftype' is set to "nofile" and 'bufhidden' to "hide". If
|
||||||
you prefer other settings, create the buffer first and pass the buffer number.
|
you prefer other settings, create the buffer first and pass the buffer number.
|
||||||
|
|
||||||
|
The "out_modifiable" and "err_modifiable" options can be used to set the
|
||||||
|
'modifiable' option off, or write to a buffer that has 'modifiable' off. That
|
||||||
|
means that lines will be appended to the buffer, but the user can't easily
|
||||||
|
change the buffer.
|
||||||
|
|
||||||
|
When an existing buffer is to be written where 'modifiable' is off and the
|
||||||
|
"out_modifiable" or "err_modifiable" options is not zero, an error is given
|
||||||
|
and the buffer will not be written to.
|
||||||
|
|
||||||
When the buffer written to is displayed in a window and the cursor is in the
|
When the buffer written to is displayed in a window and the cursor is in the
|
||||||
first column of the last line, the cursor will be moved to the newly added
|
first column of the last line, the cursor will be moved to the newly added
|
||||||
line and the window is scrolled up to show the cursor if needed.
|
line and the window is scrolled up to show the cursor if needed.
|
||||||
|
@ -1209,9 +1209,20 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
|
|||||||
}
|
}
|
||||||
if (buf != NULL)
|
if (buf != NULL)
|
||||||
{
|
{
|
||||||
ch_logs(channel, "writing out to buffer '%s'",
|
if (opt->jo_set & JO_OUT_MODIFIABLE)
|
||||||
|
channel->ch_part[PART_OUT].ch_nomodifiable =
|
||||||
|
!opt->jo_modifiable[PART_OUT];
|
||||||
|
|
||||||
|
if (!buf->b_p_ma && !channel->ch_part[PART_OUT].ch_nomodifiable)
|
||||||
|
{
|
||||||
|
EMSG(_(e_modifiable));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch_logs(channel, "writing out to buffer '%s'",
|
||||||
(char *)buf->b_ffname);
|
(char *)buf->b_ffname);
|
||||||
channel->ch_part[PART_OUT].ch_buffer = buf;
|
channel->ch_part[PART_OUT].ch_buffer = buf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1236,9 +1247,19 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
|
|||||||
buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE);
|
buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE);
|
||||||
if (buf != NULL)
|
if (buf != NULL)
|
||||||
{
|
{
|
||||||
ch_logs(channel, "writing err to buffer '%s'",
|
if (opt->jo_set & JO_ERR_MODIFIABLE)
|
||||||
|
channel->ch_part[PART_ERR].ch_nomodifiable =
|
||||||
|
!opt->jo_modifiable[PART_ERR];
|
||||||
|
if (!buf->b_p_ma && !channel->ch_part[PART_ERR].ch_nomodifiable)
|
||||||
|
{
|
||||||
|
EMSG(_(e_modifiable));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ch_logs(channel, "writing err to buffer '%s'",
|
||||||
(char *)buf->b_ffname);
|
(char *)buf->b_ffname);
|
||||||
channel->ch_part[PART_ERR].ch_buffer = buf;
|
channel->ch_part[PART_ERR].ch_buffer = buf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2107,11 +2128,23 @@ invoke_one_time_callback(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel)
|
append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, int part)
|
||||||
{
|
{
|
||||||
buf_T *save_curbuf = curbuf;
|
buf_T *save_curbuf = curbuf;
|
||||||
linenr_T lnum = buffer->b_ml.ml_line_count;
|
linenr_T lnum = buffer->b_ml.ml_line_count;
|
||||||
int save_write_to = buffer->b_write_to_channel;
|
int save_write_to = buffer->b_write_to_channel;
|
||||||
|
chanpart_T *ch_part = &channel->ch_part[part];
|
||||||
|
int save_p_ma = buffer->b_p_ma;
|
||||||
|
|
||||||
|
if (!buffer->b_p_ma && !ch_part->ch_nomodifiable)
|
||||||
|
{
|
||||||
|
if (!ch_part->ch_nomod_error)
|
||||||
|
{
|
||||||
|
ch_error(channel, "Buffer is not modifiable, cannot append");
|
||||||
|
ch_part->ch_nomod_error = TRUE;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the buffer is also used as input insert above the last
|
/* If the buffer is also used as input insert above the last
|
||||||
* line. Don't write these lines. */
|
* line. Don't write these lines. */
|
||||||
@ -2124,6 +2157,7 @@ append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel)
|
|||||||
/* Append to the buffer */
|
/* Append to the buffer */
|
||||||
ch_logn(channel, "appending line %d to buffer", (int)lnum + 1);
|
ch_logn(channel, "appending line %d to buffer", (int)lnum + 1);
|
||||||
|
|
||||||
|
buffer->b_p_ma = TRUE;
|
||||||
curbuf = buffer;
|
curbuf = buffer;
|
||||||
u_sync(TRUE);
|
u_sync(TRUE);
|
||||||
/* ignore undo failure, undo is not very useful here */
|
/* ignore undo failure, undo is not very useful here */
|
||||||
@ -2132,6 +2166,10 @@ append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel)
|
|||||||
ml_append(lnum, msg, 0, FALSE);
|
ml_append(lnum, msg, 0, FALSE);
|
||||||
appended_lines_mark(lnum, 1L);
|
appended_lines_mark(lnum, 1L);
|
||||||
curbuf = save_curbuf;
|
curbuf = save_curbuf;
|
||||||
|
if (ch_part->ch_nomodifiable)
|
||||||
|
buffer->b_p_ma = FALSE;
|
||||||
|
else
|
||||||
|
buffer->b_p_ma = save_p_ma;
|
||||||
|
|
||||||
if (buffer->b_nwindows > 0)
|
if (buffer->b_nwindows > 0)
|
||||||
{
|
{
|
||||||
@ -2359,7 +2397,7 @@ may_invoke_callback(channel_T *channel, int part)
|
|||||||
/* JSON or JS mode: re-encode the message. */
|
/* JSON or JS mode: re-encode the message. */
|
||||||
msg = json_encode(listtv, ch_mode);
|
msg = json_encode(listtv, ch_mode);
|
||||||
if (msg != NULL)
|
if (msg != NULL)
|
||||||
append_to_buffer(buffer, msg, channel);
|
append_to_buffer(buffer, msg, channel, part);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback != NULL)
|
if (callback != NULL)
|
||||||
@ -3915,6 +3953,16 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (STRCMP(hi->hi_key, "out_modifiable") == 0
|
||||||
|
|| STRCMP(hi->hi_key, "err_modifiable") == 0)
|
||||||
|
{
|
||||||
|
part = part_from_char(*hi->hi_key);
|
||||||
|
|
||||||
|
if (!(supported & JO_OUT_IO))
|
||||||
|
break;
|
||||||
|
opt->jo_set |= JO_OUT_MODIFIABLE << (part - PART_OUT);
|
||||||
|
opt->jo_modifiable[part] = get_tv_number(item);
|
||||||
|
}
|
||||||
else if (STRCMP(hi->hi_key, "in_top") == 0
|
else if (STRCMP(hi->hi_key, "in_top") == 0
|
||||||
|| STRCMP(hi->hi_key, "in_bot") == 0)
|
|| STRCMP(hi->hi_key, "in_bot") == 0)
|
||||||
{
|
{
|
||||||
|
@ -1401,6 +1401,8 @@ typedef struct {
|
|||||||
partial_T *ch_partial;
|
partial_T *ch_partial;
|
||||||
|
|
||||||
buf_T *ch_buffer; /* buffer to read from or write to */
|
buf_T *ch_buffer; /* buffer to read from or write to */
|
||||||
|
int ch_nomodifiable; /* TRUE when buffer can be 'nomodifiable' */
|
||||||
|
int ch_nomod_error; /* TRUE when e_modifiable was given */
|
||||||
int ch_buf_append; /* write appended lines instead top-bot */
|
int ch_buf_append; /* write appended lines instead top-bot */
|
||||||
linenr_T ch_buf_top; /* next line to send */
|
linenr_T ch_buf_top; /* next line to send */
|
||||||
linenr_T ch_buf_bot; /* last line to send */
|
linenr_T ch_buf_bot; /* last line to send */
|
||||||
@ -1477,6 +1479,8 @@ struct channel_S {
|
|||||||
#define JO_IN_BUF 0x4000000 /* "in_buf" (JO_OUT_BUF << 2) */
|
#define JO_IN_BUF 0x4000000 /* "in_buf" (JO_OUT_BUF << 2) */
|
||||||
#define JO_CHANNEL 0x8000000 /* "channel" */
|
#define JO_CHANNEL 0x8000000 /* "channel" */
|
||||||
#define JO_BLOCK_WRITE 0x10000000 /* "block_write" */
|
#define JO_BLOCK_WRITE 0x10000000 /* "block_write" */
|
||||||
|
#define JO_OUT_MODIFIABLE 0x20000000 /* "out_modifiable" */
|
||||||
|
#define JO_ERR_MODIFIABLE 0x40000000 /* "err_modifiable" (JO_OUT_ << 1) */
|
||||||
#define JO_ALL 0x7fffffff
|
#define JO_ALL 0x7fffffff
|
||||||
|
|
||||||
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
|
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
|
||||||
@ -1500,6 +1504,7 @@ typedef struct
|
|||||||
char_u jo_io_name_buf[4][NUMBUFLEN];
|
char_u jo_io_name_buf[4][NUMBUFLEN];
|
||||||
char_u *jo_io_name[4]; /* not allocated! */
|
char_u *jo_io_name[4]; /* not allocated! */
|
||||||
int jo_io_buf[4];
|
int jo_io_buf[4];
|
||||||
|
int jo_modifiable[4];
|
||||||
channel_T *jo_channel;
|
channel_T *jo_channel;
|
||||||
|
|
||||||
linenr_T jo_in_top;
|
linenr_T jo_in_top;
|
||||||
|
@ -676,7 +676,7 @@ func Test_nl_write_both_file()
|
|||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Run_test_pipe_to_buffer(use_name)
|
func Run_test_pipe_to_buffer(use_name, nomod)
|
||||||
if !has('job')
|
if !has('job')
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
@ -691,6 +691,9 @@ func Run_test_pipe_to_buffer(use_name)
|
|||||||
quit
|
quit
|
||||||
let firstline = ''
|
let firstline = ''
|
||||||
endif
|
endif
|
||||||
|
if a:nomod
|
||||||
|
let options['out_modifiable'] = 0
|
||||||
|
endif
|
||||||
let job = job_start(s:python . " test_channel_pipe.py", options)
|
let job = job_start(s:python . " test_channel_pipe.py", options)
|
||||||
call assert_equal("run", job_status(job))
|
call assert_equal("run", job_status(job))
|
||||||
try
|
try
|
||||||
@ -705,6 +708,11 @@ func Run_test_pipe_to_buffer(use_name)
|
|||||||
$del
|
$del
|
||||||
endif
|
endif
|
||||||
call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this', 'Goodbye!'], getline(1, '$'))
|
call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this', 'Goodbye!'], getline(1, '$'))
|
||||||
|
if a:nomod
|
||||||
|
call assert_equal(0, &modifiable)
|
||||||
|
else
|
||||||
|
call assert_equal(1, &modifiable)
|
||||||
|
endif
|
||||||
bwipe!
|
bwipe!
|
||||||
finally
|
finally
|
||||||
call job_stop(job)
|
call job_stop(job)
|
||||||
@ -712,14 +720,18 @@ func Run_test_pipe_to_buffer(use_name)
|
|||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_pipe_to_buffer_name()
|
func Test_pipe_to_buffer_name()
|
||||||
call Run_test_pipe_to_buffer(1)
|
call Run_test_pipe_to_buffer(1, 0)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_pipe_to_buffer_nr()
|
func Test_pipe_to_buffer_nr()
|
||||||
call Run_test_pipe_to_buffer(0)
|
call Run_test_pipe_to_buffer(0, 0)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Run_test_pipe_err_to_buffer(use_name)
|
func Test_pipe_to_buffer_name_nomod()
|
||||||
|
call Run_test_pipe_to_buffer(1, 1)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Run_test_pipe_err_to_buffer(use_name, nomod)
|
||||||
if !has('job')
|
if !has('job')
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
@ -734,6 +746,9 @@ func Run_test_pipe_err_to_buffer(use_name)
|
|||||||
quit
|
quit
|
||||||
let firstline = ''
|
let firstline = ''
|
||||||
endif
|
endif
|
||||||
|
if a:nomod
|
||||||
|
let options['err_modifiable'] = 0
|
||||||
|
endif
|
||||||
let job = job_start(s:python . " test_channel_pipe.py", options)
|
let job = job_start(s:python . " test_channel_pipe.py", options)
|
||||||
call assert_equal("run", job_status(job))
|
call assert_equal("run", job_status(job))
|
||||||
try
|
try
|
||||||
@ -745,6 +760,11 @@ func Run_test_pipe_err_to_buffer(use_name)
|
|||||||
sp pipe-err
|
sp pipe-err
|
||||||
call s:waitFor('line("$") >= 5')
|
call s:waitFor('line("$") >= 5')
|
||||||
call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this'], getline(1, '$'))
|
call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this'], getline(1, '$'))
|
||||||
|
if a:nomod
|
||||||
|
call assert_equal(0, &modifiable)
|
||||||
|
else
|
||||||
|
call assert_equal(1, &modifiable)
|
||||||
|
endif
|
||||||
bwipe!
|
bwipe!
|
||||||
finally
|
finally
|
||||||
call job_stop(job)
|
call job_stop(job)
|
||||||
@ -752,11 +772,15 @@ func Run_test_pipe_err_to_buffer(use_name)
|
|||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_pipe_err_to_buffer_name()
|
func Test_pipe_err_to_buffer_name()
|
||||||
call Run_test_pipe_err_to_buffer(1)
|
call Run_test_pipe_err_to_buffer(1, 0)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_pipe_err_to_buffer_nr()
|
func Test_pipe_err_to_buffer_nr()
|
||||||
call Run_test_pipe_err_to_buffer(0)
|
call Run_test_pipe_err_to_buffer(0, 0)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_pipe_err_to_buffer_name_nomod()
|
||||||
|
call Run_test_pipe_err_to_buffer(1, 1)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_pipe_both_to_buffer()
|
func Test_pipe_both_to_buffer()
|
||||||
|
@ -753,6 +753,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 */
|
||||||
|
/**/
|
||||||
|
1857,
|
||||||
/**/
|
/**/
|
||||||
1856,
|
1856,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user