-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
401 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
#include <lua.h> | ||
#include <lualib.h> | ||
#include <lauxlib.h> | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <errno.h> | ||
#include <string.h> | ||
|
||
#include "nvim/vim.h" | ||
#include "nvim/xdiff/xdiff.h" | ||
#include "nvim/lua/xdiff.h" | ||
#include "nvim/lua/converter.h" | ||
#include "nvim/lua/executor.h" | ||
#include "nvim/api/private/helpers.h" | ||
|
||
typedef struct s_hunkpriv { | ||
lua_State *lstate; | ||
Error *err; | ||
} hunkpriv_t; | ||
|
||
static int write_string(void *priv, mmbuffer_t *mb, int nbuf) | ||
{ | ||
luaL_Buffer *buf = (luaL_Buffer *)priv; | ||
for (int i = 0; i < nbuf; i++) { | ||
const long size = mb[i].size; | ||
for (long total = 0; total < size; total += LUAL_BUFFERSIZE) { | ||
const int tocopy = MIN((int)(size - total), LUAL_BUFFERSIZE); | ||
char *p = luaL_prepbuffer(buf); | ||
if (!p) { | ||
return -1; | ||
} | ||
memcpy(p, mb[i].ptr + total, (unsigned)tocopy); | ||
luaL_addsize(buf, (unsigned)tocopy); | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
static int hunk_func( | ||
long start_a, long count_a, long start_b, long count_b, void *cb_data) | ||
{ | ||
hunkpriv_t *priv = (hunkpriv_t *)cb_data; | ||
lua_State * lstate = priv->lstate; | ||
Error *err = priv->err; | ||
const int fidx = lua_gettop(lstate); | ||
lua_pushvalue(lstate, fidx); | ||
lua_pushnumber(lstate, (float)start_a); | ||
lua_pushnumber(lstate, (float)count_a); | ||
lua_pushnumber(lstate, (float)start_b); | ||
lua_pushnumber(lstate, (float)count_b); | ||
|
||
if (lua_pcall(lstate, 4, 1, 0) != 0) { | ||
api_set_error(err, kErrorTypeException, | ||
"error running function hunk_func: %s", | ||
lua_tostring(lstate, -1)); | ||
return -1; | ||
} | ||
|
||
int r = 0; | ||
if (lua_isnumber(lstate, -1)) { | ||
r = (int)lua_tonumber(lstate, -1); | ||
} | ||
|
||
lua_pop(lstate, 1); | ||
lua_settop(lstate, fidx); | ||
return r; | ||
} | ||
|
||
static mmfile_t get_string_arg(lua_State *lstate, int idx) | ||
{ | ||
if (lua_type(lstate, idx) != LUA_TSTRING) { | ||
luaL_argerror(lstate, idx, "expected string"); | ||
} | ||
mmfile_t mf; | ||
mf.ptr = (char *)lua_tolstring(lstate, idx, (size_t *)&mf.size); | ||
return mf; | ||
} | ||
|
||
static void process_xdl_diff_opts( | ||
lua_State *lstate, Error *err, xdemitconf_t *cfg, xpparam_t *params) | ||
{ | ||
const DictionaryOf(LuaRef) opts = nlua_pop_Dictionary(lstate, true, err); | ||
|
||
for (size_t i = 0; i < opts.size; i++) { | ||
String k = opts.items[i].key; | ||
Object *v = &opts.items[i].value; | ||
if (strequal("hunk_func", k.data)) { | ||
if (v->type != kObjectTypeLuaRef) { | ||
api_set_error(err, kErrorTypeValidation, "hunk_func is not a function"); | ||
goto exit_1; | ||
} | ||
nlua_pushref(lstate, v->data.luaref); | ||
cfg->hunk_func = hunk_func; | ||
} else if (strequal("algorithm", k.data)) { | ||
if (v->type != kObjectTypeString) { | ||
api_set_error(err, kErrorTypeValidation, "algorithm is not a string"); | ||
goto exit_1; | ||
} | ||
if (strequal("myers", v->data.string.data)) { | ||
// default | ||
} else if (strequal("minimal", v->data.string.data)) { | ||
cfg->flags |= XDF_NEED_MINIMAL; | ||
} else if (strequal("patience", v->data.string.data)) { | ||
cfg->flags |= XDF_PATIENCE_DIFF; | ||
} else if (strequal("histogram", v->data.string.data)) { | ||
cfg->flags |= XDF_HISTOGRAM_DIFF; | ||
} else { | ||
api_set_error(err, kErrorTypeValidation, "not a valid algorithm"); | ||
goto exit_1; | ||
} | ||
} else if (strequal("ctxlen", k.data)) { | ||
if (v->type != kObjectTypeInteger) { | ||
api_set_error(err, kErrorTypeValidation, "ctxlen is not an integer"); | ||
goto exit_1; | ||
} | ||
cfg->ctxlen = v->data.integer; | ||
} else if (strequal("interhunkctxlen", k.data)) { | ||
if (v->type != kObjectTypeInteger) { | ||
api_set_error(err, kErrorTypeValidation, | ||
"interhunkctxlen is not an integer"); | ||
goto exit_1; | ||
} | ||
cfg->interhunkctxlen = v->data.integer; | ||
} else if (strequal("emit_funcnames", k.data)) { | ||
if (v->type != kObjectTypeBoolean) { | ||
api_set_error(err, kErrorTypeValidation, | ||
"emit_funcnames is not a boolean"); | ||
goto exit_1; | ||
} | ||
if (v->data.boolean) { | ||
cfg->flags |= XDL_EMIT_FUNCNAMES; | ||
} | ||
} else if (strequal("emit_funccontext", k.data)) { | ||
if (v->type != kObjectTypeBoolean) { | ||
api_set_error(err, kErrorTypeValidation, | ||
"emit_funccontext is not a boolean"); | ||
goto exit_1; | ||
} | ||
if (v->data.boolean) { | ||
cfg->flags |= XDL_EMIT_FUNCCONTEXT; | ||
} | ||
} else { | ||
struct { | ||
const char *name; | ||
unsigned long value; | ||
} flags[] = { | ||
{ "ignore_whitespace" , XDF_IGNORE_WHITESPACE }, | ||
{ "ignore_whitespace_change" , XDF_IGNORE_WHITESPACE_CHANGE }, | ||
{ "ignore_whitespace_change_at_eol", XDF_IGNORE_WHITESPACE_AT_EOL }, | ||
{ "ignore_cr_at_eol" , XDF_IGNORE_CR_AT_EOL }, | ||
{ "ignore_self_lines" , XDF_IGNORE_BLANK_LINES }, | ||
{ "indent_heuristic" , XDF_INDENT_HEURISTIC }, | ||
{ NULL , 0 }, | ||
}; | ||
bool key_used = false; | ||
for (size_t j = 0; flags[j].name; j++) { | ||
if (strequal(flags[j].name, k.data)) { | ||
if (v->type != kObjectTypeBoolean) { | ||
api_set_error(err, kErrorTypeValidation, | ||
"%s is not a boolean", flags[j].name); | ||
goto exit_1; | ||
} | ||
if (v->data.boolean) { | ||
params->flags |= flags[j].value; | ||
} | ||
key_used = true; | ||
break; | ||
} | ||
} | ||
|
||
if (key_used) { | ||
continue; | ||
} | ||
|
||
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); | ||
goto exit_1; | ||
} | ||
} | ||
|
||
exit_1: | ||
api_free_dictionary(opts); | ||
} | ||
|
||
int nlua_xdl_diff(lua_State *lstate) | ||
{ | ||
if (lua_gettop(lstate) < 2) { | ||
return luaL_error(lstate, "Expected at least 2 arguments"); | ||
} | ||
mmfile_t ma = get_string_arg(lstate, 1); | ||
mmfile_t mb = get_string_arg(lstate, 2); | ||
|
||
Error err = ERROR_INIT; | ||
|
||
xdemitconf_t cfg; | ||
xpparam_t params; | ||
xdemitcb_t ecb; | ||
|
||
memset(&cfg , 0, sizeof(cfg)); | ||
memset(¶ms, 0, sizeof(params)); | ||
memset(&ecb , 0, sizeof(ecb)); | ||
|
||
if (lua_gettop(lstate) == 3) { | ||
if (lua_type(lstate, 3) != LUA_TTABLE) { | ||
return luaL_argerror(lstate, 3, "expected table"); | ||
} | ||
|
||
process_xdl_diff_opts(lstate, &err, &cfg, ¶ms); | ||
|
||
if (ERROR_SET(&err)) { | ||
goto exit_0; | ||
} | ||
} | ||
|
||
luaL_Buffer buf; | ||
hunkpriv_t *priv; | ||
if (cfg.hunk_func == NULL) { | ||
luaL_buffinit(lstate, &buf); | ||
ecb.priv = &buf; | ||
ecb.outf = write_string; | ||
} else { | ||
priv = xmalloc(sizeof(*priv)); | ||
priv->lstate = lstate; | ||
priv->err = &err; | ||
ecb.priv = priv; | ||
} | ||
|
||
if (xdl_diff(&ma, &mb, ¶ms, &cfg, &ecb) == -1) { | ||
if (!ERROR_SET(&err)) { | ||
api_set_error(&err, kErrorTypeException, | ||
"Error while performing diff operation"); | ||
} | ||
} | ||
|
||
exit_0: | ||
if (cfg.hunk_func != NULL) { | ||
xfree(priv); | ||
} | ||
if (ERROR_SET(&err)) { | ||
luaL_where(lstate, 1); | ||
lua_pushstring(lstate, err.msg); | ||
api_clear_error(&err); | ||
lua_concat(lstate, 2); | ||
return lua_error(lstate); | ||
} | ||
if (cfg.hunk_func == NULL) { | ||
luaL_pushresult(&buf); | ||
return 1; | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#ifndef NVIM_LUA_XDIFF_H | ||
#define NVIM_LUA_XDIFF_H | ||
|
||
#include <lua.h> | ||
#include <lualib.h> | ||
#include <lauxlib.h> | ||
|
||
int nlua_xdl_diff(lua_State *lstate); | ||
|
||
#endif // NVIM_LUA_XDIFF_H |
Oops, something went wrong.