# HG changeset patch # User Christian Brabandt # Date 1473284705 -7200 # Node ID 65afd399ffa7a8c741ce328a659fc9e9b8737936 # Parent f812ea9d4c2886f9a10cdd550cb89b2e7b86513b commit https://github.com/vim/vim/commit/169ebb080454357279ad5ad21ac532deaec605e8 Author: Bram Moolenaar Date: Wed Sep 7 23:32:23 2016 +0200 patch 7.4.2344 Problem: The "Reading from channel output..." message can be unwanted. Appending to a buffer leaves an empty first line behind. Solution: Add the "out_msg" and "err_msg" options. Writing the first line overwrites the first, empty line. diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt --- a/runtime/doc/channel.txt +++ b/runtime/doc/channel.txt @@ -1,4 +1,4 @@ -*channel.txt* For Vim version 7.4. Last change: 2016 Sep 01 +*channel.txt* For Vim version 7.4. Last change: 2016 Sep 07 VIM REFERENCE MANUAL by Bram Moolenaar @@ -646,6 +646,8 @@ See |job_setoptions()| and |ch_setoption "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) +"out_msg": 0 when writing to a new buffer, the first line will be + set to "Reading from channel output..." *job-err_io* *err_name* *err_buf* "err_io": "out" stderr messages to go to stdout @@ -657,6 +659,8 @@ See |job_setoptions()| and |ch_setoption "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) +"err_msg": 0 when writing to a new buffer, the first line will be + set to "Reading from channel error..." "block_write": number only for testing: pretend every other write to stdin will block @@ -686,8 +690,16 @@ 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. + *out_modifiable* *err_modifiable* +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. + *out_msg* *err_msg* +The "out_msg" option can be used to specify whether a new buffer will have the +first line set to "Reading from channel output...". The default is to add the +message. "err_msg" does the same for channel error. -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. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -1079,7 +1079,7 @@ channel_set_job(channel_T *channel, job_ * Returns NULL if there is something very wrong (error already reported). */ static buf_T * -find_buffer(char_u *name, int err) +find_buffer(char_u *name, int err, int msg) { buf_T *buf = NULL; buf_T *save_curbuf = curbuf; @@ -1104,7 +1104,8 @@ find_buffer(char_u *name, int err) #endif if (curbuf->b_ml.ml_mfp == NULL) ml_open(curbuf); - ml_replace(1, (char_u *)(err ? "Reading from channel error..." + if (msg) + ml_replace(1, (char_u *)(err ? "Reading from channel error..." : "Reading from channel output..."), TRUE); changed_bytes(1, 0); curbuf = save_curbuf; @@ -1196,7 +1197,11 @@ channel_set_options(channel_T *channel, } else { - buf = find_buffer(opt->jo_io_name[PART_OUT], FALSE); + int msg = TRUE; + + if (opt->jo_set2 & JO2_OUT_MSG) + msg = opt->jo_message[PART_OUT]; + buf = find_buffer(opt->jo_io_name[PART_OUT], FALSE, msg); } if (buf != NULL) { @@ -1235,7 +1240,13 @@ channel_set_options(channel_T *channel, EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_ERR]); } else - buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE); + { + int msg = TRUE; + + if (opt->jo_set2 & JO2_ERR_MSG) + msg = opt->jo_message[PART_ERR]; + buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE, msg); + } if (buf != NULL) { if (opt->jo_set & JO_ERR_MODIFIABLE) @@ -2227,6 +2238,7 @@ append_to_buffer(buf_T *buffer, char_u * 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; + int empty = (buffer->b_ml.ml_flags & ML_EMPTY); if (!buffer->b_p_ma && !ch_part->ch_nomodifiable) { @@ -2253,9 +2265,16 @@ append_to_buffer(buf_T *buffer, char_u * curbuf = buffer; u_sync(TRUE); /* ignore undo failure, undo is not very useful here */ - ignored = u_save(lnum, lnum + 1); - - ml_append(lnum, msg, 0, FALSE); + ignored = u_save(lnum, lnum + 1 + (empty ? 1 : 0)); + + if (empty) + { + /* The buffer is empty, replace the first (dummy) line. */ + ml_replace(lnum, msg, TRUE); + lnum = 0; + } + else + ml_append(lnum, msg, 0, FALSE); appended_lines_mark(lnum, 1L); curbuf = save_curbuf; if (ch_part->ch_nomodifiable) @@ -4083,6 +4102,16 @@ get_job_options(typval_T *tv, jobopt_T * opt->jo_set |= JO_OUT_MODIFIABLE << (part - PART_OUT); opt->jo_modifiable[part] = get_tv_number(item); } + else if (STRCMP(hi->hi_key, "out_msg") == 0 + || STRCMP(hi->hi_key, "err_msg") == 0) + { + part = part_from_char(*hi->hi_key); + + if (!(supported & JO_OUT_IO)) + break; + opt->jo_set2 |= JO2_OUT_MSG << (part - PART_OUT); + opt->jo_message[part] = get_tv_number(item); + } else if (STRCMP(hi->hi_key, "in_top") == 0 || STRCMP(hi->hi_key, "in_bot") == 0) { diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1634,6 +1634,10 @@ struct channel_S { #define JO_ERR_MODIFIABLE 0x40000000 /* "err_modifiable" (JO_OUT_ << 1) */ #define JO_ALL 0x7fffffff +#define JO2_OUT_MSG 0x0001 /* "out_msg" */ +#define JO2_ERR_MSG 0x0002 /* "err_msg" (JO_OUT_ << 1) */ +#define JO2_ALL 0x0003 + #define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE) #define JO_CB_ALL \ (JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK + JO_CLOSE_CALLBACK) @@ -1645,6 +1649,7 @@ struct channel_S { typedef struct { int jo_set; /* JO_ bits for values that were set */ + int jo_set2; /* JO2_ bits for values that were set */ ch_mode_T jo_mode; ch_mode_T jo_in_mode; @@ -1656,6 +1661,7 @@ typedef struct char_u *jo_io_name[4]; /* not allocated! */ int jo_io_buf[4]; int jo_modifiable[4]; + int jo_message[4]; channel_T *jo_channel; linenr_T jo_in_top; diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -638,21 +638,27 @@ func BufCloseCb(ch) let g:Ch_bufClosed = 'yes' endfunc -func Run_test_pipe_to_buffer(use_name, nomod) +func Run_test_pipe_to_buffer(use_name, nomod, do_msg) if !has('job') return endif call ch_log('Test_pipe_to_buffer()') let g:Ch_bufClosed = 'no' let options = {'out_io': 'buffer', 'close_cb': 'BufCloseCb'} + let expected = ['', 'line one', 'line two', 'this', 'AND this', 'Goodbye!'] if a:use_name let options['out_name'] = 'pipe-output' - let firstline = 'Reading from channel output...' + if a:do_msg + let expected[0] = 'Reading from channel output...' + else + let options['out_msg'] = 0 + call remove(expected, 0) + endif else sp pipe-output let options['out_buf'] = bufnr('%') quit - let firstline = '' + call remove(expected, 0) endif if a:nomod let options['out_modifiable'] = 0 @@ -667,7 +673,7 @@ func Run_test_pipe_to_buffer(use_name, n call ch_sendraw(handle, "quit\n") sp pipe-output call WaitFor('line("$") >= 6 && g:Ch_bufClosed == "yes"') - call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this', 'Goodbye!'], getline(1, '$')) + call assert_equal(expected, getline(1, '$')) if a:nomod call assert_equal(0, &modifiable) else @@ -681,31 +687,41 @@ func Run_test_pipe_to_buffer(use_name, n endfunc func Test_pipe_to_buffer_name() - call Run_test_pipe_to_buffer(1, 0) + call Run_test_pipe_to_buffer(1, 0, 1) endfunc func Test_pipe_to_buffer_nr() - call Run_test_pipe_to_buffer(0, 0) + call Run_test_pipe_to_buffer(0, 0, 1) endfunc func Test_pipe_to_buffer_name_nomod() - call Run_test_pipe_to_buffer(1, 1) + call Run_test_pipe_to_buffer(1, 1, 1) endfunc -func Run_test_pipe_err_to_buffer(use_name, nomod) +func Test_pipe_to_buffer_name_nomsg() + call Run_test_pipe_to_buffer(1, 0, 1) +endfunc + +func Run_test_pipe_err_to_buffer(use_name, nomod, do_msg) if !has('job') return endif call ch_log('Test_pipe_err_to_buffer()') let options = {'err_io': 'buffer'} + let expected = ['', 'line one', 'line two', 'this', 'AND this'] if a:use_name let options['err_name'] = 'pipe-err' - let firstline = 'Reading from channel error...' + if a:do_msg + let expected[0] = 'Reading from channel error...' + else + let options['err_msg'] = 0 + call remove(expected, 0) + endif else sp pipe-err let options['err_buf'] = bufnr('%') quit - let firstline = '' + call remove(expected, 0) endif if a:nomod let options['err_modifiable'] = 0 @@ -720,7 +736,7 @@ func Run_test_pipe_err_to_buffer(use_nam call ch_sendraw(handle, "quit\n") sp pipe-err call WaitFor('line("$") >= 5') - call assert_equal([firstline, 'line one', 'line two', 'this', 'AND this'], getline(1, '$')) + call assert_equal(expected, getline(1, '$')) if a:nomod call assert_equal(0, &modifiable) else @@ -733,15 +749,19 @@ func Run_test_pipe_err_to_buffer(use_nam endfunc func Test_pipe_err_to_buffer_name() - call Run_test_pipe_err_to_buffer(1, 0) + call Run_test_pipe_err_to_buffer(1, 0, 1) endfunc func Test_pipe_err_to_buffer_nr() - call Run_test_pipe_err_to_buffer(0, 0) + call Run_test_pipe_err_to_buffer(0, 0, 1) endfunc func Test_pipe_err_to_buffer_name_nomod() - call Run_test_pipe_err_to_buffer(1, 1) + call Run_test_pipe_err_to_buffer(1, 1, 1) +endfunc + +func Test_pipe_err_to_buffer_name_nomsg() + call Run_test_pipe_err_to_buffer(1, 0, 0) endfunc func Test_pipe_both_to_buffer() @@ -1407,7 +1427,7 @@ func Test_collapse_buffers() 1,$delete call job_start('cat test_channel.vim', {'out_io': 'buffer', 'out_name': 'testout'}) call WaitFor('line("$") > g:linecount') - call assert_inrange(g:linecount + 1, g:linecount + 2, line('$')) + call assert_inrange(g:linecount, g:linecount + 1, line('$')) bwipe! endfunc @@ -1425,9 +1445,9 @@ func Test_raw_passes_nul() 1,$delete call job_start('cat Xtestread', {'out_io': 'buffer', 'out_name': 'testout'}) call WaitFor('line("$") > 2') - call assert_equal("asdf\nasdf", getline(2)) - call assert_equal("xxx\n", getline(3)) - call assert_equal("\nyyy", getline(4)) + call assert_equal("asdf\nasdf", getline(1)) + call assert_equal("xxx\n", getline(2)) + call assert_equal("\nyyy", getline(3)) call delete('Xtestread') bwipe! diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -764,6 +764,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2344, +/**/ 2343, /**/ 2342,