diff options
| author | b-r-o-c-k <brockmammen@gmail.com> | 2018-04-14 14:17:51 -0500 | 
|---|---|---|
| committer | b-r-o-c-k <brockmammen@gmail.com> | 2018-04-14 14:17:51 -0500 | 
| commit | ad999eaa775d7d4b0cacedb30c6ea3a0ee699a6f (patch) | |
| tree | 92de2079e80f5f289dd87a54af123cb7d90c3058 /src/nvim/os/shell.c | |
| parent | 78bc52ea5397c092d01cd08296fe1dc85d998329 (diff) | |
| parent | ef4feab0e75be19c5f41d70a001db980b72090f5 (diff) | |
| download | rneovim-ad999eaa775d7d4b0cacedb30c6ea3a0ee699a6f.tar.gz rneovim-ad999eaa775d7d4b0cacedb30c6ea3a0ee699a6f.tar.bz2 rneovim-ad999eaa775d7d4b0cacedb30c6ea3a0ee699a6f.zip  | |
Merge branch 'master' into s-dash-stdin
Diffstat (limited to 'src/nvim/os/shell.c')
| -rw-r--r-- | src/nvim/os/shell.c | 147 | 
1 files changed, 66 insertions, 81 deletions
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index e32c6e05d2..04f59d7522 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -123,6 +123,9 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)      if (opts & kShellOptRead) {        output_ptr = &output;        forward_output = false; +    } else if (opts & kShellOptDoOut) { +      // Caller has already redirected output +      forward_output = false;      }    } @@ -133,7 +136,7 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)    xfree(input.data);    if (output) { -    (void)write_output(output, nread, true, true); +    (void)write_output(output, nread, true);      xfree(output);    } @@ -189,6 +192,7 @@ static int do_os_system(char **argv,  {    out_data_decide_throttle(0);  // Initialize throttle decider.    out_data_ring(NULL, 0);       // Initialize output ring-buffer. +  bool has_input = (input != NULL && input[0] != '\0');    // the output buffer    DynamicBuffer buf = DYNAMIC_BUFFER_INIT; @@ -212,7 +216,7 @@ static int do_os_system(char **argv,    MultiQueue *events = multiqueue_new_child(main_loop.events);    proc->events = events;    proc->argv = argv; -  int status = process_spawn(proc, input != NULL, true, true); +  int status = process_spawn(proc, has_input, true, true);    if (status) {      loop_poll_events(&main_loop, 0);      // Failed, probably 'shell' is not executable. @@ -231,7 +235,7 @@ static int do_os_system(char **argv,    // deal with stream events as fast a possible.  It prevents closing the    // streams while there's still data in the OS buffer (due to the process    // exiting before all data is read). -  if (input != NULL) { +  if (has_input) {      wstream_init(&proc->in, 0);    }    rstream_init(&proc->out, 0); @@ -240,8 +244,8 @@ static int do_os_system(char **argv,    rstream_start(&proc->err, data_cb, &buf);    // write the input, if any -  if (input) { -    WBuffer *input_buffer = wstream_new_buffer((char *) input, len, 1, NULL); +  if (has_input) { +    WBuffer *input_buffer = wstream_new_buffer((char *)input, len, 1, NULL);      if (!wstream_write(&proc->in, input_buffer)) {        // couldn't write, stop the process and tell the user about it @@ -256,11 +260,25 @@ static int do_os_system(char **argv,    // busy state.    ui_busy_start();    ui_flush(); +  if (forward_output) { +    msg_sb_eol(); +    msg_start(); +    msg_no_more = true; +    lines_left = -1; +  }    int exitcode = process_wait(proc, -1, NULL);    if (!got_int && out_data_decide_throttle(0)) {      // Last chunk of output was skipped; display it now.      out_data_ring(NULL, SIZE_MAX);    } +  if (forward_output) { +    // caller should decide if wait_return is invoked +    no_wait_return++; +    msg_end(); +    no_wait_return--; +    msg_no_more = false; +  } +    ui_busy_stop();    // prepare the out parameters if requested @@ -370,10 +388,10 @@ static bool out_data_decide_throttle(size_t size)    pulse_msg[1] = (tick == 0 || 1 == tick) ? ' ' : '.';    pulse_msg[2] = (tick == 0 || 1 == tick || 2 == tick) ? ' ' : '.';    if (visit == 1) { -    screen_del_lines(0, 0, 1, (int)Rows, NULL); +    msg_putchar('\n');    } -  int lastrow = (int)Rows - 1; -  screen_puts_len((char_u *)pulse_msg, ARRAY_SIZE(pulse_msg), lastrow, 0, 0); +  msg_putchar('\r');  // put cursor at start of line +  msg_puts(pulse_msg);    ui_flush();    return true;  } @@ -404,7 +422,7 @@ static void out_data_ring(char *output, size_t size)    }    if (output == NULL && size == SIZE_MAX) {   // Print mode -    out_data_append_to_screen(last_skipped, last_skipped_len, true); +    out_data_append_to_screen(last_skipped, &last_skipped_len, true);      return;    } @@ -432,60 +450,40 @@ static void out_data_ring(char *output, size_t size)  /// @param output       Data to append to screen lines.  /// @param remaining    Size of data.  /// @param new_line     If true, next data output will be on a new line. -static void out_data_append_to_screen(char *output, size_t remaining, -                                      bool new_line) +static void out_data_append_to_screen(char *output, size_t *count, +                                      bool eof)  { -  static colnr_T last_col = 0;  // Column of last row to append to. - -  size_t off = 0; -  int last_row = (int)Rows - 1; - -  while (output != NULL && off < remaining) { -    // Found end of line? -    if (output[off] == NL) { -      // Can we start a new line or do we need to continue the last one? -      if (last_col == 0) { -        screen_del_lines(0, 0, 1, (int)Rows, NULL); +  char *p = output, *end = output + *count; +  while (p < end) { +    if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) { +      msg_putchar_attr((uint8_t)(*p), 0); +      p++; +    } else { +      // Note: this is not 100% precise: +      // 1. we don't check if received continuation bytes are already invalid +      //    and we thus do some buffering that could be avoided +      // 2. we don't compose chars over buffer boundaries, even if we see an +      //    incomplete UTF-8 sequence that could be composing with the last +      //    complete sequence. +      // This will be corrected when we switch to vterm based implementation +      int i = *p ? mb_ptr2len_len((char_u *)p, (int)(end-p)) : 1; +      if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end-p)) { +        *count = (size_t)(p - output); +        goto end;        } -      screen_puts_len((char_u *)output, (int)off, last_row, last_col, 0); -      last_col = 0; -      size_t skip = off + 1; -      output += skip; -      remaining -= skip; -      off = 0; -      continue; -    } - -    // TODO(bfredl): using msg_puts would be better until -    // terminal emulation is implemented. -    if (output[off] < 0x20) { -      output[off] = ' '; -    } - -    off++; -  } - -  if (output != NULL && remaining) { -    if (last_col == 0) { -      screen_del_lines(0, 0, 1, (int)Rows, NULL); +      (void)msg_outtrans_len_attr((char_u *)p, i, 0); +      p += i;      } -    screen_puts_len((char_u *)output, (int)remaining, last_row, last_col, 0); -    last_col += (colnr_T)remaining; -  } - -  if (new_line) { -    last_col = 0;    } +end:    ui_flush();  }  static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,      bool eof)  { -  // We always output the whole buffer, so the buffer can never -  // wrap around.    size_t cnt;    char *ptr = rbuffer_read_ptr(buf, &cnt); @@ -494,12 +492,16 @@ static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,      // Save the skipped output. If it is the final chunk, we display it later.      out_data_ring(ptr, cnt);    } else { -    out_data_append_to_screen(ptr, cnt, eof); +    out_data_append_to_screen(ptr, &cnt, eof);    }    if (cnt) {      rbuffer_consumed(buf, cnt);    } + +  // Move remaining data to start of buffer, so the buffer can never +  // wrap around. +  rbuffer_reset(buf);  }  /// Parses a command string into a sequence of words, taking quotes into @@ -588,14 +590,10 @@ static void read_input(DynamicBuffer *buf)      if (len == l) {        // Finished a line, add a NL, unless this line should not have one. -      // FIXME need to make this more readable        if (lnum != curbuf->b_op_end.lnum -          || (!curbuf->b_p_bin -            && curbuf->b_p_fixeol) +          || (!curbuf->b_p_bin && curbuf->b_p_fixeol)            || (lnum != curbuf->b_no_eol_lnum -            && (lnum != -              curbuf->b_ml.ml_line_count -              || curbuf->b_p_eol))) { +              && (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) {          dynamic_buffer_ensure(buf, buf->len + 1);          buf->data[buf->len++] = NL;        } @@ -611,28 +609,20 @@ static void read_input(DynamicBuffer *buf)    }  } -static size_t write_output(char *output, size_t remaining, bool to_buffer, -                           bool eof) +static size_t write_output(char *output, size_t remaining, bool eof)  {    if (!output) {      return 0;    } -  char replacement_NUL = to_buffer ? NL : 1;    char *start = output;    size_t off = 0; -  int lastrow = (int)Rows - 1;    while (off < remaining) {      if (output[off] == NL) {        // Insert the line -      if (to_buffer) { -        output[off] = NUL; -        ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1, -                  false); -      } else { -        screen_del_lines(0, 0, 1, (int)Rows, NULL); -        screen_puts_len((char_u *)output, (int)off, lastrow, 0, 0); -      } +      output[off] = NUL; +      ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1, +                false);        size_t skip = off + 1;        output += skip;        remaining -= skip; @@ -642,24 +632,19 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,      if (output[off] == NUL) {        // Translate NUL to NL -      output[off] = replacement_NUL; +      output[off] = NL;      }      off++;    }    if (eof) {      if (remaining) { -      if (to_buffer) { -        // append unfinished line -        ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false); -        // remember that the NL was missing -        curbuf->b_no_eol_lnum = curwin->w_cursor.lnum; -      } else { -        screen_del_lines(0, 0, 1, (int)Rows, NULL); -        screen_puts_len((char_u *)output, (int)remaining, lastrow, 0, 0); -      } +      // append unfinished line +      ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false); +      // remember that the NL was missing +      curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;        output += remaining; -    } else if (to_buffer) { +    } else {        curbuf->b_no_eol_lnum = 0;      }    }  | 
