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
|
||||
@ -578,8 +578,8 @@ See |job_setoptions()| and |ch_setoptions()|.
|
||||
"exit_cb": handler Callback for when the job ends. The arguments are the
|
||||
job and the exit status.
|
||||
Vim checks about every 10 seconds for jobs that ended.
|
||||
The callback can also be triggered by calling
|
||||
|job_status()|.
|
||||
The check also be triggered by calling |job_status()|,
|
||||
which may then invoke the exit_cb handler.
|
||||
Note that data can be buffered, callbacks may still be
|
||||
called after the process ends.
|
||||
*job-timeout*
|
||||
@ -625,18 +625,22 @@ See |job_setoptions()| and |ch_setoptions()|.
|
||||
"out_io": "null" disconnect stdout (goes to /dev/null)
|
||||
"out_io": "pipe" stdout is connected to the channel (default)
|
||||
"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_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*
|
||||
"err_io": "out" stderr messages to go to stdout
|
||||
"err_io": "null" disconnect stderr (goes to /dev/null)
|
||||
"err_io": "pipe" stderr is connected to the channel (default)
|
||||
"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_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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
@ -1209,9 +1209,20 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
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;
|
||||
linenr_T lnum = buffer->b_ml.ml_line_count;
|
||||
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
|
||||
* 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 */
|
||||
ch_logn(channel, "appending line %d to buffer", (int)lnum + 1);
|
||||
|
||||
buffer->b_p_ma = TRUE;
|
||||
curbuf = buffer;
|
||||
u_sync(TRUE);
|
||||
/* 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);
|
||||
appended_lines_mark(lnum, 1L);
|
||||
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)
|
||||
{
|
||||
@ -2359,7 +2397,7 @@ may_invoke_callback(channel_T *channel, int part)
|
||||
/* JSON or JS mode: re-encode the message. */
|
||||
msg = json_encode(listtv, ch_mode);
|
||||
if (msg != NULL)
|
||||
append_to_buffer(buffer, msg, channel);
|
||||
append_to_buffer(buffer, msg, channel, part);
|
||||
}
|
||||
|
||||
if (callback != NULL)
|
||||
@ -3915,6 +3953,16 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
||||
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
|
||||
|| STRCMP(hi->hi_key, "in_bot") == 0)
|
||||
{
|
||||
|
@ -1401,6 +1401,8 @@ typedef struct {
|
||||
partial_T *ch_partial;
|
||||
|
||||
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 */
|
||||
linenr_T ch_buf_top; /* next 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_CHANNEL 0x8000000 /* "channel" */
|
||||
#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_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[4]; /* not allocated! */
|
||||
int jo_io_buf[4];
|
||||
int jo_modifiable[4];
|
||||
channel_T *jo_channel;
|
||||
|
||||
linenr_T jo_in_top;
|
||||
|
@ -676,7 +676,7 @@ func Test_nl_write_both_file()
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func Run_test_pipe_to_buffer(use_name)
|
||||
func Run_test_pipe_to_buffer(use_name, nomod)
|
||||
if !has('job')
|
||||
return
|
||||
endif
|
||||
@ -691,6 +691,9 @@ func Run_test_pipe_to_buffer(use_name)
|
||||
quit
|
||||
let firstline = ''
|
||||
endif
|
||||
if a:nomod
|
||||
let options['out_modifiable'] = 0
|
||||
endif
|
||||
let job = job_start(s:python . " test_channel_pipe.py", options)
|
||||
call assert_equal("run", job_status(job))
|
||||
try
|
||||
@ -705,6 +708,11 @@ func Run_test_pipe_to_buffer(use_name)
|
||||
$del
|
||||
endif
|
||||
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!
|
||||
finally
|
||||
call job_stop(job)
|
||||
@ -712,14 +720,18 @@ func Run_test_pipe_to_buffer(use_name)
|
||||
endfunc
|
||||
|
||||
func Test_pipe_to_buffer_name()
|
||||
call Run_test_pipe_to_buffer(1)
|
||||
call Run_test_pipe_to_buffer(1, 0)
|
||||
endfunc
|
||||
|
||||
func Test_pipe_to_buffer_nr()
|
||||
call Run_test_pipe_to_buffer(0)
|
||||
call Run_test_pipe_to_buffer(0, 0)
|
||||
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')
|
||||
return
|
||||
endif
|
||||
@ -734,6 +746,9 @@ func Run_test_pipe_err_to_buffer(use_name)
|
||||
quit
|
||||
let firstline = ''
|
||||
endif
|
||||
if a:nomod
|
||||
let options['err_modifiable'] = 0
|
||||
endif
|
||||
let job = job_start(s:python . " test_channel_pipe.py", options)
|
||||
call assert_equal("run", job_status(job))
|
||||
try
|
||||
@ -745,6 +760,11 @@ func Run_test_pipe_err_to_buffer(use_name)
|
||||
sp pipe-err
|
||||
call s:waitFor('line("$") >= 5')
|
||||
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!
|
||||
finally
|
||||
call job_stop(job)
|
||||
@ -752,11 +772,15 @@ func Run_test_pipe_err_to_buffer(use_name)
|
||||
endfunc
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
func Test_pipe_both_to_buffer()
|
||||
|
@ -753,6 +753,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1857,
|
||||
/**/
|
||||
1856,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user