mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
Merge 5b410d1e49
into 738320188f
This commit is contained in:
commit
644dbfca43
@ -2010,15 +2010,21 @@ NOTE: These commands cannot be used with |:global| or |:vglobal|.
|
|||||||
|
|
||||||
*:r!* *:read!*
|
*:r!* *:read!*
|
||||||
:[range]r[ead] [++opt] !{cmd}
|
:[range]r[ead] [++opt] !{cmd}
|
||||||
Execute {cmd} and insert its standard output below
|
Execute shell {cmd} and insert its standard output
|
||||||
the cursor or the specified line. A temporary file is
|
below the cursor or the specified line. A temporary
|
||||||
used to store the output of the command which is then
|
file is used to store the output of the command which
|
||||||
read into the buffer. 'shellredir' is used to save
|
is then read into the buffer. 'shellredir' is used to
|
||||||
the output of the command, which can be set to include
|
save the output of the command, which can be set to
|
||||||
stderr or not. {cmd} is executed like with ":!{cmd}",
|
include stderr or not. {cmd} is executed like with
|
||||||
any '!' is replaced with the previous command |:!|.
|
":!{cmd}", any '!' is replaced with the previous
|
||||||
|
command |:!|.
|
||||||
See |++opt| for the possible values of [++opt].
|
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,
|
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 "."
|
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
|
command. They work on a line basis, insertion starts below the line in which
|
||||||
|
@ -218,6 +218,8 @@ EDITOR
|
|||||||
to a literal "~" directory.
|
to a literal "~" directory.
|
||||||
• |hl-ComplMatchIns| shows matched text of the currently inserted completion.
|
• |hl-ComplMatchIns| shows matched text of the currently inserted completion.
|
||||||
• |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup.
|
• |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
|
EVENTS
|
||||||
|
|
||||||
|
@ -12,8 +12,10 @@
|
|||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
|
||||||
#include "auto/config.h"
|
#include "auto/config.h"
|
||||||
|
#include "klib/kvec.h"
|
||||||
#include "nvim/api/private/defs.h"
|
#include "nvim/api/private/defs.h"
|
||||||
#include "nvim/api/private/helpers.h"
|
#include "nvim/api/private/helpers.h"
|
||||||
|
#include "nvim/api/vim.h"
|
||||||
#include "nvim/arglist.h"
|
#include "nvim/arglist.h"
|
||||||
#include "nvim/ascii_defs.h"
|
#include "nvim/ascii_defs.h"
|
||||||
#include "nvim/autocmd.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)
|
static void ex_read(exarg_T *eap)
|
||||||
{
|
{
|
||||||
int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
|
int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
|
||||||
@ -5835,6 +5862,11 @@ static void ex_read(exarg_T *eap)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*eap->arg == ':') {
|
||||||
|
do_read_cmd(eap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) {
|
if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) {
|
||||||
return;
|
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