aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2024-02-11 19:13:38 +0100
committerbfredl <bjorn.linse@gmail.com>2024-02-13 11:54:44 +0100
commit1a3a8d903e9705ce41867e1cbc629a85c7cb6252 (patch)
tree1eeeedcb0370d7c156f60ee53017149c8aac8c28
parent0353dd3029f9ce31c3894530385443a90f6677ee (diff)
downloadrneovim-1a3a8d903e9705ce41867e1cbc629a85c7cb6252.tar.gz
rneovim-1a3a8d903e9705ce41867e1cbc629a85c7cb6252.tar.bz2
rneovim-1a3a8d903e9705ce41867e1cbc629a85c7cb6252.zip
refactor(lua): use a keyset for vim.diff opts parsing
-rw-r--r--runtime/lua/vim/_meta/api_keysets.lua14
-rw-r--r--src/nvim/api/keysets_defs.h16
-rw-r--r--src/nvim/lua/xdiff.c171
-rw-r--r--test/functional/lua/xdiff_spec.lua2
4 files changed, 91 insertions, 112 deletions
diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua
index 0442a89e3f..ab0d3aafe8 100644
--- a/runtime/lua/vim/_meta/api_keysets.lua
+++ b/runtime/lua/vim/_meta/api_keysets.lua
@@ -297,3 +297,17 @@ error('Cannot require a meta file')
--- @field end_row? integer
--- @field start_vcol? integer
--- @field end_vcol? integer
+
+--- @class vim.api.keyset.xdl_diff
+--- @field on_hunk? function
+--- @field result_type? string
+--- @field algorithm? string
+--- @field ctxlen? integer
+--- @field interhunkctxlen? integer
+--- @field linematch? any
+--- @field ignore_whitespace? boolean
+--- @field ignore_whitespace_change? boolean
+--- @field ignore_whitespace_change_at_eol? boolean
+--- @field ignore_cr_at_eol? boolean
+--- @field ignore_blank_lines? boolean
+--- @field indent_heuristic? boolean
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index 0ba33ca9a7..c5aa5ce0f1 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -358,3 +358,19 @@ typedef struct {
OptionalKeys is_set__complete_set_;
String info;
} Dict(complete_set);
+
+typedef struct {
+ OptionalKeys is_set__xdl_diff_;
+ LuaRef on_hunk;
+ String result_type;
+ String algorithm;
+ Integer ctxlen;
+ Integer interhunkctxlen;
+ Object linematch;
+ Boolean ignore_whitespace;
+ Boolean ignore_whitespace_change;
+ Boolean ignore_whitespace_change_at_eol;
+ Boolean ignore_cr_at_eol;
+ Boolean ignore_blank_lines;
+ Boolean indent_heuristic;
+} Dict(xdl_diff);
diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c
index f5a5949ab6..035c171a14 100644
--- a/src/nvim/lua/xdiff.c
+++ b/src/nvim/lua/xdiff.c
@@ -5,7 +5,9 @@
#include <string.h>
#include "luaconf.h"
+#include "nvim/api/keysets_defs.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/linematch.h"
#include "nvim/lua/converter.h"
@@ -187,137 +189,84 @@ static mmfile_t get_string_arg(lua_State *lstate, int idx)
return mf;
}
-// Helper function for validating option types
-static bool check_xdiff_opt(ObjectType actType, ObjectType expType, const char *name, Error *err)
-{
- if (actType != expType) {
- const char *type_str =
- expType == kObjectTypeString
- ? "string" : (expType == kObjectTypeInteger
- ? "integer" : (expType == kObjectTypeBoolean
- ? "boolean" : (expType == kObjectTypeLuaRef
- ? "function" : "NA")));
-
- api_set_error(err, kErrorTypeValidation, "%s is not a %s", name,
- type_str);
- return true;
- }
-
- return false;
-}
-
static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, xpparam_t *params,
int64_t *linematch, Error *err)
{
- // TODO: this is very much a keydict..
- const DictionaryOf(LuaRef) opts = nlua_pop_Dictionary(lstate, true, NULL, err);
+ Dict(xdl_diff) opts = KEYDICT_INIT;
+ char *err_param = NULL;
+ KeySetLink *KeyDict_xdl_diff_get_field(const char *str, size_t len);
+ nlua_pop_keydict(lstate, &opts, KeyDict_xdl_diff_get_field, &err_param, NULL, err);
NluaXdiffMode mode = kNluaXdiffModeUnified;
- bool had_on_hunk = false;
bool had_result_type_indices = false;
- for (size_t i = 0; i < opts.size; i++) {
- String k = opts.items[i].key;
- Object *v = &opts.items[i].value;
- if (strequal("on_hunk", k.data)) {
- if (check_xdiff_opt(v->type, kObjectTypeLuaRef, "on_hunk", err)) {
- goto exit_1;
- }
- had_on_hunk = true;
- nlua_pushref(lstate, v->data.luaref);
- } else if (strequal("result_type", k.data)) {
- if (check_xdiff_opt(v->type, kObjectTypeString, "result_type", err)) {
- goto exit_1;
- }
- if (strequal("unified", v->data.string.data)) {
- // the default
- } else if (strequal("indices", v->data.string.data)) {
- had_result_type_indices = true;
- } else {
- api_set_error(err, kErrorTypeValidation, "not a valid result_type");
- goto exit_1;
- }
- } else if (strequal("algorithm", k.data)) {
- if (check_xdiff_opt(v->type, kObjectTypeString, "algorithm", err)) {
- goto exit_1;
- }
- if (strequal("myers", v->data.string.data)) {
- // default
- } else if (strequal("minimal", v->data.string.data)) {
- params->flags |= XDF_NEED_MINIMAL;
- } else if (strequal("patience", v->data.string.data)) {
- params->flags |= XDF_PATIENCE_DIFF;
- } else if (strequal("histogram", v->data.string.data)) {
- params->flags |= XDF_HISTOGRAM_DIFF;
- } else {
- api_set_error(err, kErrorTypeValidation, "not a valid algorithm");
- goto exit_1;
- }
- } else if (strequal("ctxlen", k.data)) {
- if (check_xdiff_opt(v->type, kObjectTypeInteger, "ctxlen", err)) {
- goto exit_1;
- }
- cfg->ctxlen = (long)v->data.integer;
- } else if (strequal("interhunkctxlen", k.data)) {
- if (check_xdiff_opt(v->type, kObjectTypeInteger, "interhunkctxlen",
- err)) {
- goto exit_1;
- }
- cfg->interhunkctxlen = (long)v->data.integer;
- } else if (strequal("linematch", k.data)) {
- if (v->type == kObjectTypeBoolean) {
- *linematch = v->data.boolean ? INT64_MAX : 0;
- } else if (v->type == kObjectTypeInteger) {
- *linematch = v->data.integer;
- } else {
- api_set_error(err, kErrorTypeValidation, "linematch must be a boolean or integer");
- goto exit_1;
- }
+
+ if (HAS_KEY(&opts, xdl_diff, result_type)) {
+ if (strequal("unified", opts.result_type.data)) {
+ // the default
+ } else if (strequal("indices", opts.result_type.data)) {
+ had_result_type_indices = true;
} 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_blank_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 (check_xdiff_opt(v->type, kObjectTypeBoolean, flags[j].name,
- err)) {
- goto exit_1;
- }
- if (v->data.boolean) {
- params->flags |= flags[j].value;
- }
- key_used = true;
- break;
- }
- }
+ api_set_error(err, kErrorTypeValidation, "not a valid result_type");
+ goto exit_1;
+ }
+ }
- if (key_used) {
- continue;
- }
+ if (HAS_KEY(&opts, xdl_diff, algorithm)) {
+ if (strequal("myers", opts.algorithm.data)) {
+ // default
+ } else if (strequal("minimal", opts.algorithm.data)) {
+ params->flags |= XDF_NEED_MINIMAL;
+ } else if (strequal("patience", opts.algorithm.data)) {
+ params->flags |= XDF_PATIENCE_DIFF;
+ } else if (strequal("histogram", opts.algorithm.data)) {
+ params->flags |= XDF_HISTOGRAM_DIFF;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "not a valid algorithm");
+ goto exit_1;
+ }
+ }
- api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ if (HAS_KEY(&opts, xdl_diff, ctxlen)) {
+ cfg->ctxlen = (long)opts.ctxlen;
+ }
+
+ if (HAS_KEY(&opts, xdl_diff, interhunkctxlen)) {
+ cfg->interhunkctxlen = (long)opts.interhunkctxlen;
+ }
+
+ if (HAS_KEY(&opts, xdl_diff, linematch)) {
+ if (opts.linematch.type == kObjectTypeBoolean) {
+ *linematch = opts.linematch.data.boolean ? INT64_MAX : 0;
+ } else if (opts.linematch.type == kObjectTypeInteger) {
+ *linematch = opts.linematch.data.integer;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "linematch must be a boolean or integer");
goto exit_1;
}
}
- if (had_on_hunk) {
+ params->flags |= opts.ignore_whitespace ? XDF_IGNORE_WHITESPACE : 0;
+ params->flags |= opts.ignore_whitespace_change ? XDF_IGNORE_WHITESPACE_CHANGE : 0;
+ params->flags |= opts.ignore_whitespace_change_at_eol ? XDF_IGNORE_WHITESPACE_AT_EOL : 0;
+ params->flags |= opts.ignore_cr_at_eol ? XDF_IGNORE_CR_AT_EOL : 0;
+ params->flags |= opts.ignore_blank_lines ? XDF_IGNORE_BLANK_LINES : 0;
+ params->flags |= opts.indent_heuristic ? XDF_INDENT_HEURISTIC : 0;
+
+ if (HAS_KEY(&opts, xdl_diff, on_hunk)) {
mode = kNluaXdiffModeOnHunkCB;
+ nlua_pushref(lstate, opts.on_hunk);
+ if (lua_type(lstate, -1) != LUA_TFUNCTION) {
+ api_set_error(err, kErrorTypeValidation, "on_hunk is not a function");
+ }
} else if (had_result_type_indices) {
mode = kNluaXdiffModeLocations;
}
exit_1:
- api_free_dictionary(opts);
+ api_free_string(opts.result_type);
+ api_free_string(opts.algorithm);
+ api_free_luaref(opts.on_hunk);
return mode;
}
diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua
index 0563161adb..c21309c2e4 100644
--- a/test/functional/lua/xdiff_spec.lua
+++ b/test/functional/lua/xdiff_spec.lua
@@ -165,7 +165,7 @@ describe('xdiff bindings', function()
pcall_err(exec_lua, [[vim.diff('a', 'b', true)]])
)
- eq([[unexpected key: bad_key]], pcall_err(exec_lua, [[vim.diff('a', 'b', { bad_key = true })]]))
+ eq([[invalid key: bad_key]], pcall_err(exec_lua, [[vim.diff('a', 'b', { bad_key = true })]]))
eq(
[[on_hunk is not a function]],