mirror of
https://github.com/neovim/neovim.git
synced 2026-07-17 14:41:33 +00:00
fix(shell): preserve CR when :! outputs to binary-mode buffer #39558
Problem:
When `:!` writes shell output to a buffer, write_output() splits on `\r`, `\n`,
and `\r\n`, replacing the terminator byte with NUL. For a binary-mode buffer
this is wrong: `\r` should be preserved verbatim, not treated as a line
terminator. This wrong behavior causes a file like `\r\n` round-trips through
`:%!cat` to `\n`.
This was masked when 'shelltemp' was enabled, because output went through a temp
file and the regular file I/O path handled binary-mode correctly. Switching the
default to 'noshelltemp' exposed the bug, since output is now piped directly
into write_output().
Solution:
In `write_output()`, skip the `\r` and `\r\n` splits for a binary-mode buffer;
only split on `\n`.
(cherry picked from commit 832a68835b)
This commit is contained in:
committed by
github-actions[bot]
parent
d8a94658f5
commit
2389cf2e39
@@ -1254,7 +1254,8 @@ static size_t write_output(char *output, size_t remaining, bool eof)
|
|||||||
size_t off = 0;
|
size_t off = 0;
|
||||||
while (off < remaining) {
|
while (off < remaining) {
|
||||||
// CRLF
|
// CRLF
|
||||||
if (output[off] == CAR && output[off + 1] == NL) {
|
// special case: for binary mode, don't remove CR.
|
||||||
|
if (output[off] == CAR && output[off + 1] == NL && !curbuf->b_p_bin) {
|
||||||
output[off] = NUL;
|
output[off] = NUL;
|
||||||
ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false);
|
ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false);
|
||||||
size_t skip = off + 2;
|
size_t skip = off + 2;
|
||||||
@@ -1262,7 +1263,7 @@ static size_t write_output(char *output, size_t remaining, bool eof)
|
|||||||
remaining -= skip;
|
remaining -= skip;
|
||||||
off = 0;
|
off = 0;
|
||||||
continue;
|
continue;
|
||||||
} else if (output[off] == CAR || output[off] == NL) {
|
} else if ((output[off] == CAR && !curbuf->b_p_bin) || output[off] == NL) {
|
||||||
// Insert the line
|
// Insert the line
|
||||||
output[off] = NUL;
|
output[off] = NUL;
|
||||||
ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false);
|
ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false);
|
||||||
|
|||||||
@@ -567,6 +567,25 @@ end)
|
|||||||
describe('shell :!', function()
|
describe('shell :!', function()
|
||||||
before_each(clear)
|
before_each(clear)
|
||||||
|
|
||||||
|
it('preserves newlines (including CR) in binary-mode buffer #39424', function()
|
||||||
|
local fname = 'Xbinaryfile'
|
||||||
|
finally(function()
|
||||||
|
os.remove(fname)
|
||||||
|
end)
|
||||||
|
|
||||||
|
t.write_file(fname, '\r\n', true)
|
||||||
|
command('edit ++bin ' .. fname)
|
||||||
|
command('%!cat')
|
||||||
|
command('w')
|
||||||
|
eq('\r\n', t.read_file(fname))
|
||||||
|
|
||||||
|
t.write_file(fname, '\r', true)
|
||||||
|
command('edit ++bin ' .. fname)
|
||||||
|
command('%!cat')
|
||||||
|
command('w')
|
||||||
|
eq('\r', t.read_file(fname))
|
||||||
|
end)
|
||||||
|
|
||||||
it(':{range}! works when the first char is NUL #34163', function()
|
it(':{range}! works when the first char is NUL #34163', function()
|
||||||
api.nvim_buf_set_lines(0, 0, -1, true, { '\0hello', 'hello' })
|
api.nvim_buf_set_lines(0, 0, -1, true, { '\0hello', 'hello' })
|
||||||
command('%!cat')
|
command('%!cat')
|
||||||
|
|||||||
Reference in New Issue
Block a user