]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 7.4.1857 v7.4.1857
authorBram Moolenaar <Bram@vim.org>
Sun, 29 May 2016 14:17:08 +0000 (16:17 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 29 May 2016 14:17:08 +0000 (16:17 +0200)
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.

runtime/doc/channel.txt
src/channel.c
src/structs.h
src/testdir/test_channel.vim
src/version.c

index bfb62f57b28e717e7e60efc2f7f5910f6c7ae54a..c28b90ed2cf9c2345ce8a803b301aec442a6f78e 100644 (file)
@@ -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.
index 2cc46fecb704e52e441b74e4d31bcf87226f81ef..973d234eac549db0e03ab170b24c2cd99b44222d 100644 (file)
@@ -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)
            {
index 12a8a438786ece73e3aefd8b034dc7342ef0f552..d5f8adc83af95984eb46ea682f0f98527084e01b 100644 (file)
@@ -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;
index 363b5cd9e1f290ded6c0ca59e1402a42cdc09da1..ed3fa6d4664d4c6a37b40f7f48922e06e0a71abb 100644 (file)
@@ -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 Test_pipe_to_buffer_name_nomod()
+  call Run_test_pipe_to_buffer(1, 1)
 endfunc
 
-func Run_test_pipe_err_to_buffer(use_name)
+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()
index e47ab53387f16997cd2c80002b84ce87274a1ae6..c3afbad85b40d2b0f2b9e5be657541e4b0834820 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1857,
 /**/
     1856,
 /**/