mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 10:45:16 -07:00
Compare commits
3 Commits
644dbfca43
...
fa5110b18b
Author | SHA1 | Date | |
---|---|---|---|
|
fa5110b18b | ||
|
5b410d1e49 | ||
|
c792dbc013 |
@ -2010,15 +2010,21 @@ NOTE: These commands cannot be used with |:global| or |:vglobal|.
|
||||
|
||||
*:r!* *:read!*
|
||||
:[range]r[ead] [++opt] !{cmd}
|
||||
Execute {cmd} and insert its standard output below
|
||||
the cursor or the specified line. A temporary file is
|
||||
used to store the output of the command which is then
|
||||
read into the buffer. 'shellredir' is used to save
|
||||
the output of the command, which can be set to include
|
||||
stderr or not. {cmd} is executed like with ":!{cmd}",
|
||||
any '!' is replaced with the previous command |:!|.
|
||||
Execute shell {cmd} and insert its standard output
|
||||
below the cursor or the specified line. A temporary
|
||||
file is used to store the output of the command which
|
||||
is then read into the buffer. 'shellredir' is used to
|
||||
save the output of the command, which can be set to
|
||||
include stderr or not. {cmd} is executed like with
|
||||
":!{cmd}", any '!' is replaced with the previous
|
||||
command |:!|.
|
||||
See |++opt| for the possible values of [++opt].
|
||||
|
||||
*:r:* *:read:*
|
||||
:[range]r[ead] :{cmd}
|
||||
Execute Ex command {cmd} and insert its output below
|
||||
the cursor or the specified line.
|
||||
|
||||
These commands insert the contents of a file, or the output of a command,
|
||||
into the buffer. They can be undone. They cannot be repeated with the "."
|
||||
command. They work on a line basis, insertion starts below the line in which
|
||||
|
@ -217,6 +217,8 @@ EDITOR
|
||||
"~/" are now expanded to the user's profile directory, not a relative path
|
||||
to a literal "~" directory.
|
||||
• |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup.
|
||||
• |:read:| reads the output of an Ex command into the buffer. Example:>
|
||||
:read :ls
|
||||
|
||||
EVENTS
|
||||
|
||||
|
@ -12,8 +12,10 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include "auto/config.h"
|
||||
#include "klib/kvec.h"
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/api/vim.h"
|
||||
#include "nvim/arglist.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/autocmd.h"
|
||||
@ -5826,6 +5828,31 @@ static void ex_syncbind(exarg_T *eap)
|
||||
}
|
||||
}
|
||||
|
||||
void do_read_cmd(exarg_T *eap)
|
||||
{
|
||||
Object cmd = CSTR_AS_OBJ(eap->arg + 1);
|
||||
String cmd_var_name = cstr_as_string("_ex_cmd");
|
||||
StringBuilder put_cmd = KV_INITIAL_VALUE;
|
||||
Error error = ERROR_INIT;
|
||||
nvim_set_var(cmd_var_name, cmd, &error);
|
||||
if (error.type != kErrorTypeNone) {
|
||||
emsg(error.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
kv_printf(put_cmd, "%dput=execute(g:%s) | ", eap->line2, cmd_var_name.data);
|
||||
kv_printf(put_cmd, "execute 'norm! )`.' | ");
|
||||
kv_printf(put_cmd, "execute 'd _' | ");
|
||||
|
||||
do_cmdline(put_cmd.items, eap->ea_getline, eap->cookie, eap->flags);
|
||||
kv_destroy(put_cmd);
|
||||
nvim_del_var(cmd_var_name, &error);
|
||||
if (error.type != kErrorTypeNone) {
|
||||
emsg(error.msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ex_read(exarg_T *eap)
|
||||
{
|
||||
int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
|
||||
@ -5835,6 +5862,11 @@ static void ex_read(exarg_T *eap)
|
||||
return;
|
||||
}
|
||||
|
||||
if (*eap->arg == ':') {
|
||||
do_read_cmd(eap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) {
|
||||
return;
|
||||
}
|
||||
|
94
test/functional/ex_cmds/read_spec.lua
Normal file
94
test/functional/ex_cmds/read_spec.lua
Normal file
@ -0,0 +1,94 @@
|
||||
local t = require('test.testutil')
|
||||
local n = require('test.functional.testnvim')()
|
||||
|
||||
local eq, write_file, clear, pcall_err = t.eq, t.write_file, n.clear, t.pcall_err
|
||||
local fn = n.fn
|
||||
local setline, getline, setcharpos, execute = fn.setline, fn.getline, fn.setcharpos, fn.execute
|
||||
|
||||
local tmp_file = 'text.txt'
|
||||
local original_text = { 'First', 'Last' }
|
||||
local read_text = { ' This is a line starts with a space', ' This one starts with two spaces.' }
|
||||
local inserted_middle = { original_text[1], read_text[1], read_text[2], original_text[2] }
|
||||
local inserted_start = { read_text[1], read_text[2], original_text[1], original_text[2] }
|
||||
|
||||
local function test_read(cmd, expected)
|
||||
setline(1, original_text)
|
||||
setcharpos('.', { 0, 0, 0 })
|
||||
execute(cmd)
|
||||
for i, e in ipairs(expected) do
|
||||
eq(e, getline(i))
|
||||
end
|
||||
end
|
||||
|
||||
local function test_undo(cmd)
|
||||
setline(1, original_text)
|
||||
execute(cmd)
|
||||
execute('undo')
|
||||
eq(original_text, { getline(1), getline(2) })
|
||||
end
|
||||
|
||||
describe(':read', function()
|
||||
local function cleanup()
|
||||
os.remove(tmp_file)
|
||||
end
|
||||
before_each(function()
|
||||
clear()
|
||||
cleanup()
|
||||
write_file(tmp_file, table.concat(read_text, '\n'), true)
|
||||
end)
|
||||
after_each(cleanup)
|
||||
it('inserts text from file', function()
|
||||
test_read('read ' .. tmp_file, inserted_middle)
|
||||
eq({ 0, 2, 2, 0 }, fn.getpos('.'))
|
||||
end)
|
||||
it('inserts text from shell', function()
|
||||
test_read('read !cat ' .. tmp_file, inserted_middle)
|
||||
eq({ 0, 3, 3, 0 }, fn.getpos('.'))
|
||||
end)
|
||||
it('inserts text from Ex command', function()
|
||||
local make_lines = string.format('let lines="%s"', table.concat(read_text, '\\n'))
|
||||
execute(make_lines)
|
||||
test_read('read :echo lines', inserted_middle)
|
||||
end)
|
||||
it('inserts text from file at specific position', function()
|
||||
test_read('0read ' .. tmp_file, inserted_start)
|
||||
eq({ 0, 1, 2, 0 }, fn.getpos('.'))
|
||||
end)
|
||||
it('inserts text from shell cmd at specific position', function()
|
||||
test_read('0read !cat ' .. tmp_file, inserted_start)
|
||||
eq({ 0, 2, 3, 0 }, fn.getpos('.'))
|
||||
end)
|
||||
it('executes next command when using |', function()
|
||||
local make_lines = string.format('let lines="%s"', table.concat(read_text, '\\n'))
|
||||
execute(make_lines)
|
||||
execute("let guard = 'fail'")
|
||||
test_read("read :echo lines | let guard='pass'", inserted_middle)
|
||||
eq('pass', vim.trim(execute('echo guard')))
|
||||
end)
|
||||
it('sets fileformat, fileencoding, bomb correctly', function()
|
||||
execute('set fileformat=dos')
|
||||
execute('set fileencoding=latin1')
|
||||
execute('set bomb')
|
||||
execute('read ++edit ' .. tmp_file)
|
||||
eq('fileformat=unix', vim.trim(execute('set fileformat?')))
|
||||
eq('fileencoding=utf-8', vim.trim(execute('set fileencoding?')))
|
||||
eq('nobomb', vim.trim(execute('set bomb?')))
|
||||
end)
|
||||
it('file reads can be undone', function()
|
||||
test_undo('read ' .. tmp_file)
|
||||
end)
|
||||
it('shell reads can be undone', function()
|
||||
test_undo('read !cat ' .. tmp_file)
|
||||
end)
|
||||
it('command reads can be undone', function()
|
||||
local make_lines = string.format('let lines="%s"', table.concat(read_text, '\\n'))
|
||||
execute(make_lines)
|
||||
test_undo('read :echo lines')
|
||||
end)
|
||||
it('errors out correctly when a non-existant file is used', function()
|
||||
eq("Vim(read):E484: Can't open file asdfasdf", pcall_err(execute, ':read asdfasdf'))
|
||||
end)
|
||||
it('errors out correctly when an invalid command is used', function()
|
||||
eq('Vim:E492: Not an editor command: asdfasdf', pcall_err(execute, ':read :asdfasdf'))
|
||||
end)
|
||||
end)
|
Loading…
Reference in New Issue
Block a user