mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +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
	 Björn Linse
					Björn Linse