aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua/xdiff.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/lua/xdiff.c')
-rw-r--r--src/nvim/lua/xdiff.c147
1 files changed, 109 insertions, 38 deletions
diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c
index b2b5dfedee..857b159af5 100644
--- a/src/nvim/lua/xdiff.c
+++ b/src/nvim/lua/xdiff.c
@@ -1,21 +1,26 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-#include <errno.h>
#include <lauxlib.h>
#include <lua.h>
-#include <lualib.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
+#include "luaconf.h"
+#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/linematch.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
#include "nvim/lua/xdiff.h"
+#include "nvim/macros.h"
+#include "nvim/memory.h"
#include "nvim/vim.h"
#include "xdiff/xdiff.h"
+#define COMPARED_BUFFER0 (1 << 0)
+#define COMPARED_BUFFER1 (1 << 1)
+
typedef enum {
kNluaXdiffModeUnified = 0,
kNluaXdiffModeOnHunkCB,
@@ -25,12 +30,81 @@ typedef enum {
typedef struct {
lua_State *lstate;
Error *err;
+ mmfile_t *ma;
+ mmfile_t *mb;
+ bool linematch;
+ bool iwhite;
} hunkpriv_t;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/xdiff.c.generated.h"
#endif
+static void lua_pushhunk(lua_State *lstate, long start_a, long count_a, long start_b, long count_b)
+{
+ // Mimic extra offsets done by xdiff, see:
+ // src/xdiff/xemit.c:284
+ // src/xdiff/xutils.c:(356,368)
+ if (count_a > 0) {
+ start_a += 1;
+ }
+ if (count_b > 0) {
+ start_b += 1;
+ }
+ lua_createtable(lstate, 0, 0);
+ lua_pushinteger(lstate, start_a);
+ lua_rawseti(lstate, -2, 1);
+ lua_pushinteger(lstate, count_a);
+ lua_rawseti(lstate, -2, 2);
+ lua_pushinteger(lstate, start_b);
+ lua_rawseti(lstate, -2, 3);
+ lua_pushinteger(lstate, count_b);
+ lua_rawseti(lstate, -2, 4);
+ lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2) + 1);
+}
+
+static void get_linematch_results(lua_State *lstate, mmfile_t *ma, mmfile_t *mb, long start_a,
+ long count_a, long start_b, long count_b, bool iwhite)
+{
+ // get the pointer to char of the start of the diff to pass it to linematch algorithm
+ const char *diff_begin[2] = { ma->ptr, mb->ptr };
+ int diff_length[2] = { (int)count_a, (int)count_b };
+
+ fastforward_buf_to_lnum(&diff_begin[0], start_a + 1);
+ fastforward_buf_to_lnum(&diff_begin[1], start_b + 1);
+
+ int *decisions = NULL;
+ size_t decisions_length = linematch_nbuffers(diff_begin, diff_length, 2, &decisions, iwhite);
+
+ long lnuma = start_a, lnumb = start_b;
+
+ long hunkstarta = lnuma;
+ long hunkstartb = lnumb;
+ long hunkcounta = 0;
+ long hunkcountb = 0;
+ for (size_t i = 0; i < decisions_length; i++) {
+ if (i && (decisions[i - 1] != decisions[i])) {
+ lua_pushhunk(lstate, hunkstarta, hunkcounta, hunkstartb, hunkcountb);
+
+ hunkstarta = lnuma;
+ hunkstartb = lnumb;
+ hunkcounta = 0;
+ hunkcountb = 0;
+ // create a new hunk
+ }
+ if (decisions[i] & COMPARED_BUFFER0) {
+ lnuma++;
+ hunkcounta++;
+ }
+ if (decisions[i] & COMPARED_BUFFER1) {
+ lnumb++;
+ hunkcountb++;
+ }
+ }
+ lua_pushhunk(lstate, hunkstarta, hunkcounta, hunkstartb, hunkcountb);
+ xfree(decisions);
+}
+
static int write_string(void *priv, mmbuffer_t *mb, int nbuf)
{
luaL_Buffer *buf = (luaL_Buffer *)priv;
@@ -52,30 +126,15 @@ static int write_string(void *priv, mmbuffer_t *mb, int nbuf)
// hunk_func callback used when opts.hunk_lines = true
static int hunk_locations_cb(long start_a, long count_a, long start_b, long count_b, void *cb_data)
{
- // Mimic extra offsets done by xdiff, see:
- // src/xdiff/xemit.c:284
- // src/xdiff/xutils.c:(356,368)
- if (count_a > 0) {
- start_a += 1;
- }
- if (count_b > 0) {
- start_b += 1;
+ hunkpriv_t *priv = (hunkpriv_t *)cb_data;
+ lua_State *lstate = priv->lstate;
+ if (priv->linematch) {
+ get_linematch_results(lstate, priv->ma, priv->mb, start_a, count_a, start_b, count_b,
+ priv->iwhite);
+ } else {
+ lua_pushhunk(lstate, start_a, count_a, start_b, count_b);
}
- lua_State *lstate = (lua_State *)cb_data;
- lua_createtable(lstate, 0, 0);
-
- lua_pushinteger(lstate, start_a);
- lua_rawseti(lstate, -2, 1);
- lua_pushinteger(lstate, count_a);
- lua_rawseti(lstate, -2, 2);
- lua_pushinteger(lstate, start_b);
- lua_rawseti(lstate, -2, 3);
- lua_pushinteger(lstate, count_b);
- lua_rawseti(lstate, -2, 4);
-
- lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2) + 1);
-
return 0;
}
@@ -149,7 +208,7 @@ static bool check_xdiff_opt(ObjectType actType, ObjectType expType, const char *
}
static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, xpparam_t *params,
- Error *err)
+ bool *linematch, Error *err)
{
const DictionaryOf(LuaRef) opts = nlua_pop_Dictionary(lstate, true, err);
@@ -205,6 +264,11 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg,
goto exit_1;
}
cfg->interhunkctxlen = v->data.integer;
+ } else if (strequal("linematch", k.data)) {
+ *linematch = api_object_to_bool(*v, "linematch", false, err);
+ if (ERROR_SET(err)) {
+ goto exit_1;
+ }
} else {
struct {
const char *name;
@@ -244,10 +308,8 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg,
if (had_on_hunk) {
mode = kNluaXdiffModeOnHunkCB;
- cfg->hunk_func = call_on_hunk_cb;
} else if (had_result_type_indices) {
mode = kNluaXdiffModeLocations;
- cfg->hunk_func = hunk_locations_cb;
}
exit_1:
@@ -268,6 +330,7 @@ int nlua_xdl_diff(lua_State *lstate)
xdemitconf_t cfg;
xpparam_t params;
xdemitcb_t ecb;
+ bool linematch = false;
CLEAR_FIELD(cfg);
CLEAR_FIELD(params);
@@ -280,7 +343,7 @@ int nlua_xdl_diff(lua_State *lstate)
return luaL_argerror(lstate, 3, "expected table");
}
- mode = process_xdl_diff_opts(lstate, &cfg, &params, &err);
+ mode = process_xdl_diff_opts(lstate, &cfg, &params, &linematch, &err);
if (ERROR_SET(&err)) {
goto exit_0;
@@ -288,7 +351,7 @@ int nlua_xdl_diff(lua_State *lstate)
}
luaL_Buffer buf;
- hunkpriv_t *priv = NULL;
+ hunkpriv_t priv;
switch (mode) {
case kNluaXdiffModeUnified:
luaL_buffinit(lstate, &buf);
@@ -296,14 +359,24 @@ int nlua_xdl_diff(lua_State *lstate)
ecb.out_line = write_string;
break;
case kNluaXdiffModeOnHunkCB:
- priv = xmalloc(sizeof(*priv));
- priv->lstate = lstate;
- priv->err = &err;
- ecb.priv = priv;
+ cfg.hunk_func = call_on_hunk_cb;
+ priv = (hunkpriv_t) {
+ .lstate = lstate,
+ .err = &err,
+ };
+ ecb.priv = &priv;
break;
case kNluaXdiffModeLocations:
+ cfg.hunk_func = hunk_locations_cb;
+ priv = (hunkpriv_t) {
+ .lstate = lstate,
+ .ma = &ma,
+ .mb = &mb,
+ .linematch = linematch,
+ .iwhite = (params.flags & XDF_IGNORE_WHITESPACE) > 0
+ };
+ ecb.priv = &priv;
lua_createtable(lstate, 0, 0);
- ecb.priv = lstate;
break;
}
@@ -314,8 +387,6 @@ int nlua_xdl_diff(lua_State *lstate)
}
}
- XFREE_CLEAR(priv);
-
exit_0:
if (ERROR_SET(&err)) {
luaL_where(lstate, 1);