mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +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