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`.
This commit is contained in:
Alexej Kowalew
2026-05-08 09:54:30 +02:00
committed by GitHub
parent a61c8f3580
commit 832a68835b
2 changed files with 22 additions and 2 deletions

View File

@@ -567,6 +567,25 @@ end)
describe('shell :!', function()
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()
api.nvim_buf_set_lines(0, 0, -1, true, { '\0hello', 'hello' })
command('%!cat')