To: vim_dev@googlegroups.com Subject: Patch 7.4.1857 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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. Files: src/structs.h, src/channel.c, src/testdir/test_channel.vim, runtime/doc/channel.txt *** ../vim-7.4.1856/src/structs.h 2016-05-24 15:43:46.695296634 +0200 --- src/structs.h 2016-05-29 15:36:14.029360356 +0200 *************** *** 1401,1406 **** --- 1401,1408 ---- 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,1482 **** --- 1479,1486 ---- #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,1505 **** --- 1504,1510 ---- 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; *** ../vim-7.4.1856/src/channel.c 2016-05-28 22:22:28.826213562 +0200 --- src/channel.c 2016-05-29 16:11:42.133331082 +0200 *************** *** 1209,1217 **** } if (buf != NULL) { ! ch_logs(channel, "writing out to buffer '%s'", (char *)buf->b_ffname); ! channel->ch_part[PART_OUT].ch_buffer = buf; } } --- 1209,1228 ---- } if (buf != NULL) { ! 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; ! } } } *************** *** 1236,1244 **** buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE); if (buf != NULL) { ! ch_logs(channel, "writing err to buffer '%s'", (char *)buf->b_ffname); ! channel->ch_part[PART_ERR].ch_buffer = buf; } } --- 1247,1265 ---- buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE); if (buf != NULL) { ! 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; ! } } } *************** *** 2107,2117 **** } static void ! append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel) { buf_T *save_curbuf = curbuf; linenr_T lnum = buffer->b_ml.ml_line_count; int save_write_to = buffer->b_write_to_channel; /* If the buffer is also used as input insert above the last * line. Don't write these lines. */ --- 2128,2150 ---- } static void ! 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,2129 **** --- 2157,2163 ---- /* 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,2137 **** --- 2166,2175 ---- 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,2365 **** /* JSON or JS mode: re-encode the message. */ msg = json_encode(listtv, ch_mode); if (msg != NULL) ! append_to_buffer(buffer, msg, channel); } if (callback != NULL) --- 2397,2403 ---- /* JSON or JS mode: re-encode the message. */ msg = json_encode(listtv, ch_mode); if (msg != NULL) ! append_to_buffer(buffer, msg, channel, part); } if (callback != NULL) *************** *** 3915,3920 **** --- 3953,3968 ---- 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) { *** ../vim-7.4.1856/src/testdir/test_channel.vim 2016-05-24 17:33:29.139206088 +0200 --- src/testdir/test_channel.vim 2016-05-29 15:55:59.973344043 +0200 *************** *** 676,682 **** endtry endfunc ! func Run_test_pipe_to_buffer(use_name) if !has('job') return endif --- 676,682 ---- endtry endfunc ! func Run_test_pipe_to_buffer(use_name, nomod) if !has('job') return endif *************** *** 691,696 **** --- 691,699 ---- 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,710 **** --- 708,718 ---- $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,725 **** endfunc func Test_pipe_to_buffer_name() ! call Run_test_pipe_to_buffer(1) endfunc func Test_pipe_to_buffer_nr() ! call Run_test_pipe_to_buffer(0) endfunc ! func Run_test_pipe_err_to_buffer(use_name) if !has('job') return endif --- 720,737 ---- endfunc func Test_pipe_to_buffer_name() ! call Run_test_pipe_to_buffer(1, 0) endfunc func Test_pipe_to_buffer_nr() ! call Run_test_pipe_to_buffer(0, 0) ! endfunc ! ! 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,739 **** --- 746,754 ---- 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,750 **** --- 760,770 ---- 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,762 **** endfunc func Test_pipe_err_to_buffer_name() ! call Run_test_pipe_err_to_buffer(1) endfunc func Test_pipe_err_to_buffer_nr() ! call Run_test_pipe_err_to_buffer(0) endfunc func Test_pipe_both_to_buffer() --- 772,786 ---- endfunc func Test_pipe_err_to_buffer_name() ! 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, 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() *** ../vim-7.4.1856/runtime/doc/channel.txt 2016-03-14 23:22:31.219768924 +0100 --- runtime/doc/channel.txt 2016-05-29 15:58:48.653341722 +0200 *************** *** 571,588 **** "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_name": "/path/file" the name of the file or buffer to write to "out_buf": number the number of the buffer to write to *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_name": "/path/file" the name of the file or buffer to write to "err_buf": number the number of the buffer to write to Writing to a buffer ~ --- 625,649 ---- "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 (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 (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 Writing to a buffer ~ *************** *** 606,611 **** --- 667,681 ---- 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. *** ../vim-7.4.1856/src/version.c 2016-05-28 22:47:08.546193208 +0200 --- src/version.c 2016-05-29 15:56:31.177343613 +0200 *************** *** 755,756 **** --- 755,758 ---- { /* Add new patch number below this line */ + /**/ + 1857, /**/ -- How To Keep A Healthy Level Of Insanity: 7. Finish all your sentences with "in accordance with the prophecy". /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///