diff options
Diffstat (limited to 'src/nvim/os/shell.c')
-rw-r--r-- | src/nvim/os/shell.c | 97 |
1 files changed, 47 insertions, 50 deletions
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index c205e4b3af..f650a51fe7 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; } } @@ -257,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 @@ -405,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; } @@ -433,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] = ' '; + (void)msg_outtrans_len_attr((char_u *)p, i, 0); + p += i; } - - off++; - } - - if (output != NULL && remaining) { - if (last_col == 0) { - screen_del_lines(0, 0, 1, (int)Rows, NULL); - } - 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); @@ -495,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 @@ -589,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; } |