mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	lua: docs and tests for vim.schedule
This commit is contained in:
		@@ -203,6 +203,8 @@ User reloads the buffer with ":edit", emits: >
 | 
				
			|||||||
In-process lua plugins can also recieve buffer updates, in the form of lua
 | 
					In-process lua plugins can also recieve buffer updates, in the form of lua
 | 
				
			||||||
callbacks. These callbacks are called frequently in various contexts, buffer
 | 
					callbacks. These callbacks are called frequently in various contexts, buffer
 | 
				
			||||||
contents or window layout should not be changed inside these |textlock|.
 | 
					contents or window layout should not be changed inside these |textlock|.
 | 
				
			||||||
 | 
					|lua-vim.schedule| can be used to defer these operations to the main loop,
 | 
				
			||||||
 | 
					where they are allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
|nvim_buf_attach| will take keyword args for the callbacks. "on_lines" will
 | 
					|nvim_buf_attach| will take keyword args for the callbacks. "on_lines" will
 | 
				
			||||||
receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline}, {new_lastline}).
 | 
					receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline}, {new_lastline}).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -379,6 +379,12 @@ vim.stricmp(a, b)					*lua-vim.stricmp*
 | 
				
			|||||||
	string arguments and returns 0, 1 or -1 if strings are equal, a is 
 | 
						string arguments and returns 0, 1 or -1 if strings are equal, a is 
 | 
				
			||||||
	greater then b or a is lesser then b respectively.
 | 
						greater then b or a is lesser then b respectively.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vim.schedule(callback)					*lua-vim.schedule*
 | 
				
			||||||
 | 
						Schedule `callback` to be called soon by the main event loop. This is
 | 
				
			||||||
 | 
					        useful in contexts where some functionality is blocked, like an
 | 
				
			||||||
 | 
					        autocommand or callback running with |textlock|. Then the scheduled
 | 
				
			||||||
 | 
					        callback could invoke this functionality later when it is allowed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vim.type_idx						*lua-vim.type_idx*
 | 
					vim.type_idx						*lua-vim.type_idx*
 | 
				
			||||||
	Type index for use in |lua-special-tbl|.  Specifying one of the 
 | 
						Type index for use in |lua-special-tbl|.  Specifying one of the 
 | 
				
			||||||
	values from |lua-vim.types| allows typing the empty table (it is 
 | 
						values from |lua-vim.types| allows typing the empty table (it is 
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,12 +36,6 @@ typedef struct {
 | 
				
			|||||||
  String lua_err_str;
 | 
					  String lua_err_str;
 | 
				
			||||||
} LuaError;
 | 
					} LuaError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// We use this to store Lua callbacks
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
  // TODO: store more info for debugging, traceback?
 | 
					 | 
				
			||||||
  int cb;
 | 
					 | 
				
			||||||
} nlua_ctx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
 | 
					#ifdef INCLUDE_GENERATED_DECLARATIONS
 | 
				
			||||||
# include "lua/vim_module.generated.h"
 | 
					# include "lua/vim_module.generated.h"
 | 
				
			||||||
# include "lua/executor.c.generated.h"
 | 
					# include "lua/executor.c.generated.h"
 | 
				
			||||||
@@ -114,33 +108,32 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
 | 
				
			|||||||
  return 1;
 | 
					  return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void nlua_schedule_cb(void **argv)
 | 
					static void nlua_schedule_event(void **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  nlua_ctx *ctx = argv[0];
 | 
					  LuaRef cb = (LuaRef)(ptrdiff_t)argv[0];
 | 
				
			||||||
  lua_State *const lstate = nlua_enter();
 | 
					  lua_State *const lstate = nlua_enter();
 | 
				
			||||||
  lua_rawgeti(lstate, LUA_REGISTRYINDEX, ctx->cb);
 | 
					  nlua_pushref(lstate, cb);
 | 
				
			||||||
  luaL_unref(lstate, LUA_REGISTRYINDEX, ctx->cb);
 | 
					  nlua_unref(lstate, cb);
 | 
				
			||||||
  lua_pcall(lstate, 0, 0, 0);
 | 
					  if (lua_pcall(lstate, 0, 0, 0)) {
 | 
				
			||||||
  free(ctx);
 | 
					    nlua_error(lstate, _("Error executing vim.schedule lua callback: %.*s"));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Schedule Lua callback on main loop's event queue
 | 
					/// Schedule Lua callback on main loop's event queue
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// This is used to make sure nvim API is called at the right moment.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// @param  lstate  Lua interpreter state.
 | 
					/// @param  lstate  Lua interpreter state.
 | 
				
			||||||
/// @param[in]  msg  Message base, must contain one `%s`.
 | 
					 | 
				
			||||||
static int nlua_schedule(lua_State *const lstate)
 | 
					static int nlua_schedule(lua_State *const lstate)
 | 
				
			||||||
  FUNC_ATTR_NONNULL_ALL
 | 
					  FUNC_ATTR_NONNULL_ALL
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // TODO: report error using nlua_error instead
 | 
					  if (lua_type(lstate, 1) != LUA_TFUNCTION) {
 | 
				
			||||||
  luaL_checktype(lstate, 1, LUA_TFUNCTION);
 | 
					    lua_pushliteral(lstate, "vim.schedule: expected function");
 | 
				
			||||||
 | 
					    return lua_error(lstate);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  nlua_ctx* ctx = (nlua_ctx*)malloc(sizeof(nlua_ctx));
 | 
					  LuaRef cb = nlua_ref(lstate, 1);
 | 
				
			||||||
  lua_pushvalue(lstate, 1);
 | 
					 | 
				
			||||||
  ctx->cb = luaL_ref(lstate, LUA_REGISTRYINDEX);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  multiqueue_put(main_loop.events, nlua_schedule_cb, 1, ctx);
 | 
					  multiqueue_put(main_loop.events, nlua_schedule_event,
 | 
				
			||||||
 | 
					                 1, (void *)(ptrdiff_t)cb);
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,13 @@ local funcs = helpers.funcs
 | 
				
			|||||||
local meths = helpers.meths
 | 
					local meths = helpers.meths
 | 
				
			||||||
local clear = helpers.clear
 | 
					local clear = helpers.clear
 | 
				
			||||||
local eq = helpers.eq
 | 
					local eq = helpers.eq
 | 
				
			||||||
 | 
					local eval = helpers.eval
 | 
				
			||||||
 | 
					local feed = helpers.feed
 | 
				
			||||||
 | 
					local meth_pcall = helpers.meth_pcall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
before_each(clear)
 | 
					before_each(clear)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('vim.stricmp', function()
 | 
					describe('lua function', function()
 | 
				
			||||||
  -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has
 | 
					  -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has
 | 
				
			||||||
  --    length 2 (in bytes).
 | 
					  --    length 2 (in bytes).
 | 
				
			||||||
  -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has
 | 
					  -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has
 | 
				
			||||||
@@ -17,7 +20,7 @@ describe('vim.stricmp', function()
 | 
				
			|||||||
  -- Note: 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems.
 | 
					  -- Note: 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems.
 | 
				
			||||||
  -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works
 | 
					  -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works
 | 
				
			||||||
  --       only on ASCII characters.
 | 
					  --       only on ASCII characters.
 | 
				
			||||||
  it('works', function()
 | 
					  it('vim.stricmp', function()
 | 
				
			||||||
    eq(0, funcs.luaeval('vim.stricmp("a", "A")'))
 | 
					    eq(0, funcs.luaeval('vim.stricmp("a", "A")'))
 | 
				
			||||||
    eq(0, funcs.luaeval('vim.stricmp("A", "a")'))
 | 
					    eq(0, funcs.luaeval('vim.stricmp("A", "a")'))
 | 
				
			||||||
    eq(0, funcs.luaeval('vim.stricmp("a", "a")'))
 | 
					    eq(0, funcs.luaeval('vim.stricmp("a", "a")'))
 | 
				
			||||||
@@ -106,10 +109,35 @@ describe('vim.stricmp', function()
 | 
				
			|||||||
    eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")'))
 | 
					    eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")'))
 | 
				
			||||||
    eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")'))
 | 
					    eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")'))
 | 
				
			||||||
  end)
 | 
					  end)
 | 
				
			||||||
end)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("vim.split", function()
 | 
					  it("vim.schedule", function()
 | 
				
			||||||
  it("works", function()
 | 
					    meths.execute_lua([[
 | 
				
			||||||
 | 
					      test_table = {}
 | 
				
			||||||
 | 
					      vim.schedule(function()
 | 
				
			||||||
 | 
					        table.insert(test_table, "xx")
 | 
				
			||||||
 | 
					      end)
 | 
				
			||||||
 | 
					      table.insert(test_table, "yy")
 | 
				
			||||||
 | 
					    ]], {})
 | 
				
			||||||
 | 
					    eq({"yy","xx"}, meths.execute_lua("return test_table", {}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    -- type checked args
 | 
				
			||||||
 | 
					    eq({false, 'Error executing lua: vim.schedule: expected function'},
 | 
				
			||||||
 | 
					       meth_pcall(meths.execute_lua, "vim.schedule('stringly')", {}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eq({false, 'Error executing lua: vim.schedule: expected function'},
 | 
				
			||||||
 | 
					       meth_pcall(meths.execute_lua, "vim.schedule()", {}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    meths.execute_lua([[
 | 
				
			||||||
 | 
					      vim.schedule(function()
 | 
				
			||||||
 | 
					        error("big failure\nvery async")
 | 
				
			||||||
 | 
					      end)
 | 
				
			||||||
 | 
					    ]], {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    feed("<cr>")
 | 
				
			||||||
 | 
					    eq('Error executing vim.schedule lua callback: [string "<nvim>"]:2: big failure\nvery async', eval("v:errmsg"))
 | 
				
			||||||
 | 
					  end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it("vim.split", function()
 | 
				
			||||||
    local split = function(str, sep)
 | 
					    local split = function(str, sep)
 | 
				
			||||||
      return meths.execute_lua('return vim.split(...)', {str, sep})
 | 
					      return meths.execute_lua('return vim.split(...)', {str, sep})
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -141,10 +169,8 @@ describe("vim.split", function()
 | 
				
			|||||||
      assert(string.match(err, "Infinite loop detected"))
 | 
					      assert(string.match(err, "Infinite loop detected"))
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end)
 | 
					  end)
 | 
				
			||||||
end)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("vim.trim", function()
 | 
					  it('vim.trim', function()
 | 
				
			||||||
  it('works', function()
 | 
					 | 
				
			||||||
    local trim = function(s)
 | 
					    local trim = function(s)
 | 
				
			||||||
      return meths.execute_lua('return vim.trim(...)', { s })
 | 
					      return meths.execute_lua('return vim.trim(...)', { s })
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
@@ -164,10 +190,8 @@ describe("vim.trim", function()
 | 
				
			|||||||
    eq(false, status)
 | 
					    eq(false, status)
 | 
				
			||||||
    assert(string.match(err, "Only strings can be trimmed"))
 | 
					    assert(string.match(err, "Only strings can be trimmed"))
 | 
				
			||||||
  end)
 | 
					  end)
 | 
				
			||||||
end)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("vim.inspect", function()
 | 
					  it('vim.inspect', function()
 | 
				
			||||||
  it('works', function()
 | 
					 | 
				
			||||||
    -- just make sure it basically works, it has its own test suite
 | 
					    -- just make sure it basically works, it has its own test suite
 | 
				
			||||||
    local inspect = function(t, opts)
 | 
					    local inspect = function(t, opts)
 | 
				
			||||||
      return meths.execute_lua('return vim.inspect(...)', { t, opts })
 | 
					      return meths.execute_lua('return vim.inspect(...)', { t, opts })
 | 
				
			||||||
@@ -187,10 +211,8 @@ describe("vim.inspect", function()
 | 
				
			|||||||
      end})
 | 
					      end})
 | 
				
			||||||
    ]], {}))
 | 
					    ]], {}))
 | 
				
			||||||
  end)
 | 
					  end)
 | 
				
			||||||
end)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe("vim.deepcopy", function()
 | 
					  it("vim.deepcopy", function()
 | 
				
			||||||
  it("works", function()
 | 
					 | 
				
			||||||
    local is_dc = meths.execute_lua([[
 | 
					    local is_dc = meths.execute_lua([[
 | 
				
			||||||
      local a = { x = { 1, 2 }, y = 5}
 | 
					      local a = { x = { 1, 2 }, y = 5}
 | 
				
			||||||
      local b = vim.deepcopy(a)
 | 
					      local b = vim.deepcopy(a)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user