diff options
author | oni-link <knil.ino@gmail.com> | 2015-08-11 13:40:07 +0200 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2015-08-11 09:36:06 -0400 |
commit | c6af09c5663f31a43bbf02f16089437fe41574f7 (patch) | |
tree | 806945c59fb2135270147426a3ebf63d47b0609a | |
parent | 7d9472ab1b7dc4eb2bb838fb8febcc7a1aab649d (diff) | |
download | rneovim-c6af09c5663f31a43bbf02f16089437fe41574f7.tar.gz rneovim-c6af09c5663f31a43bbf02f16089437fe41574f7.tar.bz2 rneovim-c6af09c5663f31a43bbf02f16089437fe41574f7.zip |
shell.c: A full RBuffer with no NL can freeze shell output. #3156
out_data_cb() can return without emptying the full RBuffer (no NL was
seen). Because the shell output stream is stopped until space in the
Rbuffer is freed up, no more shell output is written.
To prevent this, output the full RBuffer when write_output() did not
write anything.
write_output() can also process the same RBuffer content more than once,
if no NL was seen. To prevent NUL bytes from producing new lines (if
lines are not written to a buffer), translate NUL to SOH(1).
Fixes #2983
-rw-r--r-- | src/nvim/os/shell.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index e0d67d4951..b9c5db4261 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -297,14 +297,22 @@ static void system_data_cb(Stream *stream, RBuffer *buf, void *data, bool eof) static void out_data_cb(Stream *stream, RBuffer *buf, void *data, bool eof) { - RBUFFER_UNTIL_EMPTY(buf, ptr, len) { - size_t written = write_output(ptr, len, false, - eof && len <= rbuffer_size(buf)); - if (written) { - rbuffer_consumed(buf, written); - } else { - break; - } + size_t cnt; + char *ptr = rbuffer_read_ptr(buf, &cnt); + + if (!cnt) { + return; + } + + size_t written = write_output(ptr, cnt, false, eof); + // No output written, force emptying the Rbuffer if it is full. + if (!written && rbuffer_size(buf) == rbuffer_capacity(buf)) { + screen_del_lines(0, 0, 1, (int)Rows, NULL); + screen_puts_len((char_u *)ptr, (int)cnt, (int)Rows - 1, 0, 0); + written = cnt; + } + if (written) { + rbuffer_consumed(buf, written); } } @@ -421,6 +429,7 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, if (!output) { return 0; } + char replacement_NUL = to_buffer ? NL : 1; char *start = output; size_t off = 0; @@ -428,9 +437,10 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, while (off < remaining) { if (output[off] == NL) { // Insert the line - output[off] = NUL; if (to_buffer) { - ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false); + 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); @@ -444,7 +454,7 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, if (output[off] == NUL) { // Translate NUL to NL - output[off] = NL; + output[off] = replacement_NUL; } off++; } |