mirror of
https://github.com/neovim/neovim.git
synced 2025-09-11 13:58:18 +00:00
paste: handle 'nomodifiable'
- nvim_paste(): Marshal through luaeval() instead of nvim_execute_lua() because the latter seems to hide some errors. - Handle 'nomodifiable' in `nvim_put()` explicitly. - Require explicit `false` from `vim.paste()` in order to "cancel", otherwise assume true ("continue").
This commit is contained in:
@@ -1211,6 +1211,11 @@ Dictionary nvim_get_namespaces(void)
|
|||||||
/// Invokes the `vim.paste` handler, which handles each mode appropriately.
|
/// Invokes the `vim.paste` handler, which handles each mode appropriately.
|
||||||
/// Sets redo/undo. Faster than |nvim_input()|.
|
/// Sets redo/undo. Faster than |nvim_input()|.
|
||||||
///
|
///
|
||||||
|
/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err`
|
||||||
|
/// but do not affect the return value (which is strictly decided by
|
||||||
|
/// `vim.paste()`). On error, subsequent calls are ignored ("drained") until
|
||||||
|
/// the next paste is initiated (phase 1 or -1).
|
||||||
|
///
|
||||||
/// @param data Multiline input. May be binary (containing NUL bytes).
|
/// @param data Multiline input. May be binary (containing NUL bytes).
|
||||||
/// @param phase -1: paste in a single call (i.e. without streaming).
|
/// @param phase -1: paste in a single call (i.e. without streaming).
|
||||||
/// To "stream" a paste, call `nvim_paste` sequentially with
|
/// To "stream" a paste, call `nvim_paste` sequentially with
|
||||||
@@ -1233,6 +1238,7 @@ Boolean nvim_paste(String data, Integer phase, Error *err)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Array args = ARRAY_DICT_INIT;
|
Array args = ARRAY_DICT_INIT;
|
||||||
|
Array args2 = ARRAY_DICT_INIT;
|
||||||
Object rv = OBJECT_INIT;
|
Object rv = OBJECT_INIT;
|
||||||
if (phase == -1 || phase == 1) { // Start of paste-stream.
|
if (phase == -1 || phase == 1) { // Start of paste-stream.
|
||||||
draining = false;
|
draining = false;
|
||||||
@@ -1243,8 +1249,9 @@ Boolean nvim_paste(String data, Integer phase, Error *err)
|
|||||||
Array lines = string_to_array(data);
|
Array lines = string_to_array(data);
|
||||||
ADD(args, ARRAY_OBJ(lines));
|
ADD(args, ARRAY_OBJ(lines));
|
||||||
ADD(args, INTEGER_OBJ(phase));
|
ADD(args, INTEGER_OBJ(phase));
|
||||||
rv = nvim_execute_lua(STATIC_CSTR_AS_STRING("return vim.paste(...)"), args,
|
ADD(args2, STRING_OBJ(cstr_to_string("vim.paste(_A[1], _A[2])")));
|
||||||
err);
|
ADD(args2, ARRAY_OBJ(args2));
|
||||||
|
rv = nvim_call_function(STATIC_CSTR_AS_STRING("luaeval"), args2, err);
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
draining = true;
|
draining = true;
|
||||||
goto theend;
|
goto theend;
|
||||||
@@ -1255,7 +1262,7 @@ Boolean nvim_paste(String data, Integer phase, Error *err)
|
|||||||
}
|
}
|
||||||
// vim.paste() decides if client should cancel. Errors do NOT cancel: we
|
// vim.paste() decides if client should cancel. Errors do NOT cancel: we
|
||||||
// want to drain remaining chunks (rather than divert them to main input).
|
// want to drain remaining chunks (rather than divert them to main input).
|
||||||
cancel = (rv.type != kObjectTypeBoolean || !rv.data.boolean);
|
cancel = (rv.type == kObjectTypeBoolean && !rv.data.boolean);
|
||||||
if (!cancel && !(State & CMDLINE)) { // Dot-repeat.
|
if (!cancel && !(State & CMDLINE)) { // Dot-repeat.
|
||||||
for (size_t i = 0; i < lines.size; i++) {
|
for (size_t i = 0; i < lines.size; i++) {
|
||||||
String s = lines.items[i].data.string;
|
String s = lines.items[i].data.string;
|
||||||
@@ -1271,9 +1278,9 @@ Boolean nvim_paste(String data, Integer phase, Error *err)
|
|||||||
AppendCharToRedobuff(ESC); // Dot-repeat.
|
AppendCharToRedobuff(ESC); // Dot-repeat.
|
||||||
}
|
}
|
||||||
theend:
|
theend:
|
||||||
api_free_object(rv);
|
api_free_array(args2);
|
||||||
api_free_array(args);
|
|
||||||
if (cancel || phase == -1 || phase == 3) { // End of paste-stream.
|
if (cancel || phase == -1 || phase == 3) { // End of paste-stream.
|
||||||
|
draining = false;
|
||||||
// XXX: Tickle main loop to ensure cursor is updated.
|
// XXX: Tickle main loop to ensure cursor is updated.
|
||||||
loop_schedule_deferred(&main_loop, event_create(loop_dummy_event, 0));
|
loop_schedule_deferred(&main_loop, event_create(loop_dummy_event, 0));
|
||||||
}
|
}
|
||||||
@@ -1303,6 +1310,10 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after,
|
|||||||
api_set_error(err, kErrorTypeValidation, "Invalid type: '%s'", type.data);
|
api_set_error(err, kErrorTypeValidation, "Invalid type: '%s'", type.data);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
if (!MODIFIABLE(curbuf)) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
if (lines.size == 0) {
|
if (lines.size == 0) {
|
||||||
goto cleanup; // Nothing to do.
|
goto cleanup; // Nothing to do.
|
||||||
}
|
}
|
||||||
|
@@ -409,6 +409,11 @@ describe('API', function()
|
|||||||
expect_err("Invalid type: 'x'", request,
|
expect_err("Invalid type: 'x'", request,
|
||||||
'nvim_put', {'foo'}, 'x', false, false)
|
'nvim_put', {'foo'}, 'x', false, false)
|
||||||
end)
|
end)
|
||||||
|
it("fails if 'nomodifiable'", function()
|
||||||
|
command('set nomodifiable')
|
||||||
|
expect_err([[Buffer is not 'modifiable']], request,
|
||||||
|
'nvim_put', {'a','b'}, 'l', true, true)
|
||||||
|
end)
|
||||||
it('inserts text', function()
|
it('inserts text', function()
|
||||||
-- linewise
|
-- linewise
|
||||||
nvim('put', {'line 1','line 2','line 3'}, 'l', true, true)
|
nvim('put', {'line 1','line 2','line 3'}, 'l', true, true)
|
||||||
|
@@ -329,14 +329,27 @@ describe('TUI', function()
|
|||||||
_G.save_paste_fn = vim.paste
|
_G.save_paste_fn = vim.paste
|
||||||
vim.paste = function(lines, phase) error("fake fail") end
|
vim.paste = function(lines, phase) error("fake fail") end
|
||||||
]], {})
|
]], {})
|
||||||
|
-- Prepare something for dot-repeat/redo.
|
||||||
|
feed_data('ifoo\n\027\000')
|
||||||
|
wait_for_mode('n')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
foo |
|
||||||
|
{1: } |
|
||||||
|
{4:~ }|
|
||||||
|
{4:~ }|
|
||||||
|
{5:[No Name] [+] }|
|
||||||
|
|
|
||||||
|
{3:-- TERMINAL --} |
|
||||||
|
]]}
|
||||||
|
wait_for_mode('n')
|
||||||
-- Start pasting...
|
-- Start pasting...
|
||||||
feed_data('\027[200~line 1\nline 2\n')
|
feed_data('\027[200~line 1\nline 2\n')
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
|
foo |
|
||||||
|
|
|
|
||||||
{4:~ }|
|
{4:~ }|
|
||||||
{4:~ }|
|
|
||||||
{5: }|
|
{5: }|
|
||||||
{8:paste: Error executing lua: [string "<nvim>"]:2: f}|
|
{8:paste: Vim:E5108: Error while calling lua chunk fo}|
|
||||||
{10:Press ENTER or type command to continue}{1: } |
|
{10:Press ENTER or type command to continue}{1: } |
|
||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]]}
|
]]}
|
||||||
@@ -347,13 +360,24 @@ describe('TUI', function()
|
|||||||
-- Stop paste.
|
-- Stop paste.
|
||||||
feed_data('\027[201~')
|
feed_data('\027[201~')
|
||||||
feed_data('\n') -- <Enter>
|
feed_data('\n') -- <Enter>
|
||||||
|
--Dot-repeat/redo is not modified by failed paste.
|
||||||
|
feed_data('.')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
foo |
|
||||||
|
foo |
|
||||||
|
{1: } |
|
||||||
|
{4:~ }|
|
||||||
|
{5:[No Name] [+] }|
|
||||||
|
|
|
||||||
|
{3:-- TERMINAL --} |
|
||||||
|
]]}
|
||||||
-- Editor should still work after failed/drained paste.
|
-- Editor should still work after failed/drained paste.
|
||||||
feed_data('ityped input...\027\000')
|
feed_data('ityped input...\027\000')
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
|
foo |
|
||||||
|
foo |
|
||||||
typed input..{1:.} |
|
typed input..{1:.} |
|
||||||
{4:~ }|
|
{4:~ }|
|
||||||
{4:~ }|
|
|
||||||
{4:~ }|
|
|
||||||
{5:[No Name] [+] }|
|
{5:[No Name] [+] }|
|
||||||
|
|
|
|
||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
@@ -365,9 +389,35 @@ describe('TUI', function()
|
|||||||
feed_data('\027[200~line A\nline B\n\027[201~')
|
feed_data('\027[200~line A\nline B\n\027[201~')
|
||||||
feed_data('\n') -- <Enter>
|
feed_data('\n') -- <Enter>
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
|
foo |
|
||||||
typed input...line A |
|
typed input...line A |
|
||||||
line B |
|
line B |
|
||||||
{1: } |
|
{1: } |
|
||||||
|
{5:[No Name] [+] }|
|
||||||
|
|
|
||||||
|
{3:-- TERMINAL --} |
|
||||||
|
]]}
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("paste: 'nomodifiable' buffer", function()
|
||||||
|
child_session:request('nvim_command', 'set nomodifiable')
|
||||||
|
feed_data('\027[200~fail 1\nfail 2\n\027[201~')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
|
|
||||||
|
{5: }|
|
||||||
|
{8:paste: Vim:E5108: Error while calling lua chunk fo}|
|
||||||
|
{8:r luaeval(): [string "-- Nvim-Lua stdlib: the `vim}|
|
||||||
|
{8:` module (:help l..."]:193: Buffer is not 'modifia}|
|
||||||
|
{10:Press ENTER or type command to continue}{1: } |
|
||||||
|
{3:-- TERMINAL --} |
|
||||||
|
]]}
|
||||||
|
feed_data('\n') -- <Enter>
|
||||||
|
child_session:request('nvim_command', 'set modifiable')
|
||||||
|
feed_data('\027[200~success 1\nsuccess 2\n\027[201~')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
success 1 |
|
||||||
|
success 2 |
|
||||||
|
{1: } |
|
||||||
{4:~ }|
|
{4:~ }|
|
||||||
{5:[No Name] [+] }|
|
{5:[No Name] [+] }|
|
||||||
|
|
|
|
||||||
@@ -380,9 +430,6 @@ describe('TUI', function()
|
|||||||
-- Other modes act like CTRL-C + paste.
|
-- Other modes act like CTRL-C + paste.
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("paste: in 'nomodifiable' buffer", function()
|
|
||||||
end)
|
|
||||||
|
|
||||||
it('paste: exactly 64 bytes #10311', function()
|
it('paste: exactly 64 bytes #10311', function()
|
||||||
local expected = string.rep('z', 64)
|
local expected = string.rep('z', 64)
|
||||||
feed_data('i')
|
feed_data('i')
|
||||||
|
Reference in New Issue
Block a user