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; } } |