aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-01-29 18:40:39 +0300
committerZyX <kp-pav@yandex.ru>2017-03-27 00:12:42 +0300
commit9114d9be778b07f4a49edc078f1c159aa51320d8 (patch)
treec89808b3a62862e7893c8127d7f1b373f8916067
parentb4e2860c69a4e96fa305b535ce0dbdde37632fe1 (diff)
downloadrneovim-9114d9be778b07f4a49edc078f1c159aa51320d8.tar.gz
rneovim-9114d9be778b07f4a49edc078f1c159aa51320d8.tar.bz2
rneovim-9114d9be778b07f4a49edc078f1c159aa51320d8.zip
executor: Add :luado command
-rw-r--r--src/nvim/ex_cmds.lua2
-rw-r--r--src/nvim/macros.h9
-rw-r--r--src/nvim/viml/executor/executor.c121
-rw-r--r--test/functional/lua/luaeval_spec.lua2
4 files changed, 129 insertions, 5 deletions
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index b34975f00e..25e74ebf9b 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -1548,7 +1548,7 @@ return {
command='luado',
flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
addr_type=ADDR_LINES,
- func='ex_ni',
+ func='ex_luado',
},
{
command='luafile',
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 650bf76156..5042663041 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -19,6 +19,15 @@
# define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#endif
+/// String with length
+///
+/// For use in functions which accept (char *s, size_t len) pair in arguments.
+///
+/// @param[in] s Static string.
+///
+/// @return `s, sizeof(s) - 1`
+#define S_LEN(s) (s), (sizeof(s) - 1)
+
/*
* Position comparisons
*/
diff --git a/src/nvim/viml/executor/executor.c b/src/nvim/viml/executor/executor.c
index fb39716f5c..80f2651afc 100644
--- a/src/nvim/viml/executor/executor.c
+++ b/src/nvim/viml/executor/executor.c
@@ -12,6 +12,13 @@
#include "nvim/vim.h"
#include "nvim/ex_getln.h"
#include "nvim/message.h"
+#include "nvim/memline.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/macros.h"
+#include "nvim/screen.h"
+#include "nvim/cursor.h"
+#include "nvim/undo.h"
+#include "nvim/ascii.h"
#include "nvim/viml/executor/executor.h"
#include "nvim/viml/executor/converter.h"
@@ -38,6 +45,17 @@ typedef struct {
lua_pushcfunction(lstate, &function); \
lua_call(lstate, 0, numret); \
} while (0)
+/// Call C function which expects one argument
+///
+/// @param function Called function
+/// @param numret Number of returned arguments
+/// @param a… Supplied argument (should be a void* pointer)
+#define NLUA_CALL_C_FUNCTION_1(lstate, function, numret, a1) \
+ do { \
+ lua_pushcfunction(lstate, &function); \
+ lua_pushlightuserdata(lstate, a1); \
+ lua_call(lstate, 1, numret); \
+ } while (0)
/// Call C function which expects two arguments
///
/// @param function Called function
@@ -117,7 +135,7 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
/// of view).
static int nlua_exec_lua_string(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
- const String *const str = (String *)lua_touserdata(lstate, 1);
+ const String *const str = (const String *)lua_touserdata(lstate, 1);
typval_T *const ret_tv = (typval_T *)lua_touserdata(lstate, 2);
lua_pop(lstate, 2);
@@ -135,6 +153,79 @@ static int nlua_exec_lua_string(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return 0;
}
+/// Evaluate lua string for each line in range
+///
+/// Expects two values on the stack: string to evaluate and pointer to integer
+/// array with line range. Always returns nothing (from the lua point of view).
+static int nlua_exec_luado_string(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
+{
+ const String *const str = (const String *)lua_touserdata(lstate, 1);
+ const linenr_T *const range = (const linenr_T *)lua_touserdata(lstate, 1);
+ lua_pop(lstate, 1);
+
+#define DOSTART "return function(line, linenr) "
+#define DOEND " end"
+ const size_t lcmd_len = str->size + (sizeof(DOSTART) - 1) + (sizeof(DOEND) - 1);
+ char *lcmd;
+ if (lcmd_len < IOSIZE) {
+ lcmd = (char *)IObuff;
+ } else {
+ lcmd = xmalloc(lcmd_len);
+ }
+ memcpy(lcmd, S_LEN(DOSTART));
+ memcpy(lcmd + sizeof(DOSTART) - 1, str->data, str->size);
+ memcpy(lcmd + sizeof(DOSTART) - 1 + str->size, S_LEN(DOEND));
+#undef DOSTART
+#undef DOEND
+
+ if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) {
+ nlua_error(lstate, _("E5109: Error while creating lua chunk: %.*s"));
+ return 0;
+ }
+ if (lua_pcall(lstate, 0, 1, 0)) {
+ nlua_error(lstate, _("E5110: Error while creating lua function: %.*s"));
+ return 0;
+ }
+ for (linenr_T l = range[0]; l < range[1]; l++) {
+ if (l > curbuf->b_ml.ml_line_count) {
+ break;
+ }
+ lua_pushvalue(lstate, -1);
+ lua_pushstring(lstate, (const char *)ml_get_buf(curbuf, l, false));
+ lua_pushnumber(lstate, (lua_Number)l);
+ if (lua_pcall(lstate, 2, 1, 0)) {
+ nlua_error(lstate, _("E5111: Error while calling lua function: %.*s"));
+ break;
+ }
+ if (lua_isstring(lstate, -1)) {
+ if (sandbox) {
+ EMSG(_("E5112: Not allowed in sandbox"));
+ lua_pop(lstate, 1);
+ break;
+ }
+ size_t new_line_len;
+ const char *new_line = lua_tolstring(lstate, -1, &new_line_len);
+ char *const new_line_transformed = (
+ new_line_len < IOSIZE
+ ? memcpy(IObuff, new_line, new_line_len)
+ : xmemdupz(new_line, new_line_len));
+ new_line_transformed[new_line_len] = NUL;
+ for (size_t i = 0; i < new_line_len; i++) {
+ if (new_line_transformed[new_line_len] == NUL) {
+ new_line_transformed[new_line_len] = '\n';
+ }
+ }
+ ml_replace(l, (char_u *)new_line_transformed, true);
+ changed_bytes(l, 0);
+ }
+ lua_pop(lstate, 1);
+ }
+ lua_pop(lstate, 1);
+ check_cursor();
+ update_screen(NOT_VALID);
+ return 0;
+}
+
/// Initialize lua interpreter state
///
/// Called by lua interpreter itself to initialize state.
@@ -200,7 +291,7 @@ void executor_exec_lua(const String str, typval_T *const ret_tv)
static int nlua_eval_lua_string(lua_State *const lstate)
FUNC_ATTR_NONNULL_ALL
{
- const String *const str = (String *)lua_touserdata(lstate, 1);
+ const String *const str = (const String *)lua_touserdata(lstate, 1);
typval_T *const arg = (typval_T *)lua_touserdata(lstate, 2);
typval_T *const ret_tv = (typval_T *)lua_touserdata(lstate, 3);
lua_pop(lstate, 3);
@@ -215,7 +306,7 @@ static int nlua_eval_lua_string(lua_State *const lstate)
} else {
lcmd = xmalloc(lcmd_len);
}
- memcpy(lcmd, EVALHEADER, sizeof(EVALHEADER) - 1);
+ memcpy(lcmd, S_LEN(EVALHEADER));
memcpy(lcmd + sizeof(EVALHEADER) - 1, str->data, str->size);
lcmd[lcmd_len - 1] = ')';
#undef EVALHEADER
@@ -288,3 +379,27 @@ void ex_lua(exarg_T *const eap)
clear_tv(&tv);
xfree(code);
}
+
+/// Run lua string for each line in range
+///
+/// Used for :luado.
+///
+/// @param eap VimL command being run.
+void ex_luado(exarg_T *const eap)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (global_lstate == NULL) {
+ global_lstate = init_lua();
+ }
+ if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) {
+ EMSG(_("cannot save undo information"));
+ return;
+ }
+ const String cmd = {
+ .size = STRLEN(eap->arg),
+ .data = (char *)eap->arg,
+ };
+ const linenr_T range[] = { eap->line1, eap->line2 };
+ NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_luado_string, 0,
+ (void *)&cmd, (void *)range);
+}
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index 6132d44bee..5d0180b212 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -36,7 +36,7 @@ describe('luaeval()', function()
it('is successfully received', function()
local t = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}}
eq(t, funcs.luaeval("_A", t))
- -- Not tested: nil, funcrefs, returned object identity: behaviour will
+ -- Not tested: nil, funcrefs, returned object identity: behaviour will
-- most likely change.
end)
end)