mirror of
https://github.com/neovim/neovim.git
synced 2025-11-15 14:59:20 +00:00
feat(f_msgpackdump): support dumping to Blob
This commit is contained in:
@@ -2534,7 +2534,7 @@ min({expr}) Number minimum value of items in {expr}
|
|||||||
mkdir({name} [, {path} [, {prot}]])
|
mkdir({name} [, {path} [, {prot}]])
|
||||||
Number create directory {name}
|
Number create directory {name}
|
||||||
mode([expr]) String current editing mode
|
mode([expr]) String current editing mode
|
||||||
msgpackdump({list}) List dump a list of objects to msgpack
|
msgpackdump({list} [, {type}]) List/Blob dump objects to msgpack
|
||||||
msgpackparse({list}) List parse msgpack to a list of objects
|
msgpackparse({list}) List parse msgpack to a list of objects
|
||||||
nextnonblank({lnum}) Number line nr of non-blank line >= {lnum}
|
nextnonblank({lnum}) Number line nr of non-blank line >= {lnum}
|
||||||
nr2char({expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr}
|
nr2char({expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr}
|
||||||
@@ -6824,11 +6824,15 @@ mode([expr]) Return a string that indicates the current mode.
|
|||||||
the leading character(s).
|
the leading character(s).
|
||||||
Also see |visualmode()|.
|
Also see |visualmode()|.
|
||||||
|
|
||||||
msgpackdump({list}) *msgpackdump()*
|
msgpackdump({list} [, {type}]) *msgpackdump()*
|
||||||
Convert a list of VimL objects to msgpack. Returned value is
|
Convert a list of VimL objects to msgpack. Returned value is a
|
||||||
|readfile()|-style list. Example: >
|
|readfile()|-style list. When {type} contains "B", a |Blob| is
|
||||||
|
returned instead. Example: >
|
||||||
call writefile(msgpackdump([{}]), 'fname.mpack', 'b')
|
call writefile(msgpackdump([{}]), 'fname.mpack', 'b')
|
||||||
< This will write the single 0x80 byte to `fname.mpack` file
|
< or, using a |Blob|: >
|
||||||
|
call writefile(msgpackdump([{}], 'B'), 'fname.mpack')
|
||||||
|
<
|
||||||
|
This will write the single 0x80 byte to a `fname.mpack` file
|
||||||
(dictionary with zero items is represented by 0x80 byte in
|
(dictionary with zero items is represented by 0x80 byte in
|
||||||
messagepack).
|
messagepack).
|
||||||
|
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ return {
|
|||||||
min={args=1, base=1},
|
min={args=1, base=1},
|
||||||
mkdir={args={1, 3}},
|
mkdir={args={1, 3}},
|
||||||
mode={args={0, 1}},
|
mode={args={0, 1}},
|
||||||
msgpackdump={args=1},
|
msgpackdump={args={1, 2}},
|
||||||
msgpackparse={args=1},
|
msgpackparse={args=1},
|
||||||
nextnonblank={args=1},
|
nextnonblank={args=1},
|
||||||
nr2char={args={1, 2}},
|
nr2char={args={1, 2}},
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ const char *const encode_special_var_names[] = {
|
|||||||
# include "eval/encode.c.generated.h"
|
# include "eval/encode.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Msgpack callback for writing to a Blob
|
||||||
|
int encode_blob_write(void *const data, const char *const buf, const size_t len)
|
||||||
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
|
{
|
||||||
|
ga_concat_len(&((blob_T *)data)->bv_ga, buf, len);
|
||||||
|
return (int)len;
|
||||||
|
}
|
||||||
|
|
||||||
/// Msgpack callback for writing to readfile()-style list
|
/// Msgpack callback for writing to readfile()-style list
|
||||||
int encode_list_write(void *const data, const char *const buf, const size_t len)
|
int encode_list_write(void *const data, const char *const buf, const size_t len)
|
||||||
FUNC_ATTR_NONNULL_ARG(1)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
|
|||||||
@@ -6506,9 +6506,16 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
EMSG2(_(e_listarg), "msgpackdump()");
|
EMSG2(_(e_listarg), "msgpackdump()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
|
|
||||||
list_T *const list = argvars[0].vval.v_list;
|
list_T *const list = argvars[0].vval.v_list;
|
||||||
msgpack_packer *lpacker = msgpack_packer_new(ret_list, &encode_list_write);
|
msgpack_packer *packer;
|
||||||
|
if (argvars[1].v_type != VAR_UNKNOWN
|
||||||
|
&& strequal(tv_get_string(&argvars[1]), "B")) {
|
||||||
|
tv_blob_alloc_ret(rettv);
|
||||||
|
packer = msgpack_packer_new(rettv->vval.v_blob, &encode_blob_write);
|
||||||
|
} else {
|
||||||
|
packer = msgpack_packer_new(tv_list_alloc_ret(rettv, kListLenMayKnow),
|
||||||
|
&encode_list_write);
|
||||||
|
}
|
||||||
const char *const msg = _("msgpackdump() argument, index %i");
|
const char *const msg = _("msgpackdump() argument, index %i");
|
||||||
// Assume that translation will not take more then 4 times more space
|
// Assume that translation will not take more then 4 times more space
|
||||||
char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN];
|
char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN];
|
||||||
@@ -6516,11 +6523,11 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
TV_LIST_ITER(list, li, {
|
TV_LIST_ITER(list, li, {
|
||||||
vim_snprintf(msgbuf, sizeof(msgbuf), (char *)msg, idx);
|
vim_snprintf(msgbuf, sizeof(msgbuf), (char *)msg, idx);
|
||||||
idx++;
|
idx++;
|
||||||
if (encode_vim_to_msgpack(lpacker, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) {
|
if (encode_vim_to_msgpack(packer, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
msgpack_packer_free(lpacker);
|
msgpack_packer_free(packer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "msgpackparse" function
|
/// "msgpackparse" function
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
local helpers = require('test.functional.helpers')(after_each)
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
local clear = helpers.clear
|
local clear = helpers.clear
|
||||||
local funcs = helpers.funcs
|
|
||||||
local eval, eq = helpers.eval, helpers.eq
|
local eval, eq = helpers.eval, helpers.eq
|
||||||
local command = helpers.command
|
local command = helpers.command
|
||||||
local nvim = helpers.nvim
|
local nvim = helpers.nvim
|
||||||
@@ -511,13 +510,22 @@ end)
|
|||||||
describe('msgpackdump() function', function()
|
describe('msgpackdump() function', function()
|
||||||
before_each(clear)
|
before_each(clear)
|
||||||
|
|
||||||
|
local dump_eq = function(exp_list, arg_expr)
|
||||||
|
local l = {}
|
||||||
|
for i,v in ipairs(exp_list) do
|
||||||
|
l[i] = v:gsub('\n', '\000')
|
||||||
|
end
|
||||||
|
local exp_blobstr = table.concat(l, '\n')
|
||||||
|
eq(exp_list, eval('msgpackdump(' .. arg_expr .. ')'))
|
||||||
|
eq(exp_blobstr, eval('msgpackdump(' .. arg_expr .. ', "B")'))
|
||||||
|
end
|
||||||
|
|
||||||
it('dumps string as BIN 8', function()
|
it('dumps string as BIN 8', function()
|
||||||
nvim('set_var', 'obj', {'Test'})
|
dump_eq({'\196\004Test'}, '["Test"]')
|
||||||
eq({"\196\004Test"}, eval('msgpackdump(obj)'))
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('dumps blob as BIN 8', function()
|
it('dumps blob as BIN 8', function()
|
||||||
eq({'\196\005Bl\nb!'}, eval('msgpackdump([0z426c006221])'))
|
dump_eq({'\196\005Bl\nb!'}, '[0z426c006221]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump generic mapping with generic mapping keys and values', function()
|
it('can dump generic mapping with generic mapping keys and values', function()
|
||||||
@@ -525,56 +533,56 @@ describe('msgpackdump() function', function()
|
|||||||
command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||||
command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
|
||||||
command('call add(todump._VAL, [todumpv1, todumpv2])')
|
command('call add(todump._VAL, [todumpv1, todumpv2])')
|
||||||
eq({'\129\128\128'}, eval('msgpackdump([todump])'))
|
dump_eq({'\129\128\128'}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump v:true', function()
|
it('can dump v:true', function()
|
||||||
eq({'\195'}, funcs.msgpackdump({true}))
|
dump_eq({'\195'}, '[v:true]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump v:false', function()
|
it('can dump v:false', function()
|
||||||
eq({'\194'}, funcs.msgpackdump({false}))
|
dump_eq({'\194'}, '[v:false]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can v:null', function()
|
it('can dump v:null', function()
|
||||||
command('let todump = v:null')
|
dump_eq({'\192'}, '[v:null]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump special bool mapping (true)', function()
|
it('can dump special bool mapping (true)', function()
|
||||||
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
|
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
|
||||||
eq({'\195'}, eval('msgpackdump([todump])'))
|
dump_eq({'\195'}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump special bool mapping (false)', function()
|
it('can dump special bool mapping (false)', function()
|
||||||
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
|
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
|
||||||
eq({'\194'}, eval('msgpackdump([todump])'))
|
dump_eq({'\194'}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump special nil mapping', function()
|
it('can dump special nil mapping', function()
|
||||||
command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
|
command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
|
||||||
eq({'\192'}, eval('msgpackdump([todump])'))
|
dump_eq({'\192'}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump special ext mapping', function()
|
it('can dump special ext mapping', function()
|
||||||
command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
|
command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
|
||||||
eq({'\212\005', ''}, eval('msgpackdump([todump])'))
|
dump_eq({'\212\005', ''}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump special array mapping', function()
|
it('can dump special array mapping', function()
|
||||||
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
|
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
|
||||||
eq({'\146\005\145\196\n'}, eval('msgpackdump([todump])'))
|
dump_eq({'\146\005\145\196\n'}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump special UINT64_MAX mapping', function()
|
it('can dump special UINT64_MAX mapping', function()
|
||||||
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||||
command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
|
command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
|
||||||
eq({'\207\255\255\255\255\255\255\255\255'}, eval('msgpackdump([todump])'))
|
dump_eq({'\207\255\255\255\255\255\255\255\255'}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump special INT64_MIN mapping', function()
|
it('can dump special INT64_MIN mapping', function()
|
||||||
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
command('let todump = {"_TYPE": v:msgpack_types.integer}')
|
||||||
command('let todump._VAL = [-1, 2, 0, 0]')
|
command('let todump._VAL = [-1, 2, 0, 0]')
|
||||||
eq({'\211\128\n\n\n\n\n\n\n'}, eval('msgpackdump([todump])'))
|
dump_eq({'\211\128\n\n\n\n\n\n\n'}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails to dump a function reference', function()
|
it('fails to dump a function reference', function()
|
||||||
@@ -613,13 +621,13 @@ describe('msgpackdump() function', function()
|
|||||||
it('can dump dict with two same dicts inside', function()
|
it('can dump dict with two same dicts inside', function()
|
||||||
command('let inter = {}')
|
command('let inter = {}')
|
||||||
command('let todump = {"a": inter, "b": inter}')
|
command('let todump = {"a": inter, "b": inter}')
|
||||||
eq({"\130\161a\128\161b\128"}, eval('msgpackdump([todump])'))
|
dump_eq({"\130\161a\128\161b\128"}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump list with two same lists inside', function()
|
it('can dump list with two same lists inside', function()
|
||||||
command('let inter = []')
|
command('let inter = []')
|
||||||
command('let todump = [inter, inter]')
|
command('let todump = [inter, inter]')
|
||||||
eq({"\146\144\144"}, eval('msgpackdump([todump])'))
|
dump_eq({"\146\144\144"}, '[todump]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails to dump a recursive list in a special dict', function()
|
it('fails to dump a recursive list in a special dict', function()
|
||||||
@@ -670,9 +678,9 @@ describe('msgpackdump() function', function()
|
|||||||
exc_exec('call msgpackdump()'))
|
exc_exec('call msgpackdump()'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails when called with two arguments', function()
|
it('fails when called with three arguments', function()
|
||||||
eq('Vim(call):E118: Too many arguments for function: msgpackdump',
|
eq('Vim(call):E118: Too many arguments for function: msgpackdump',
|
||||||
exc_exec('call msgpackdump(["", ""], 1)'))
|
exc_exec('call msgpackdump(["", ""], 1, 2)'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails to dump a string', function()
|
it('fails to dump a string', function()
|
||||||
@@ -714,9 +722,9 @@ describe('msgpackdump() function', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump NULL string', function()
|
it('can dump NULL string', function()
|
||||||
eq({'\196\n'}, eval('msgpackdump([$XXX_UNEXISTENT_VAR_XXX])'))
|
dump_eq({'\196\n'}, '[$XXX_UNEXISTENT_VAR_XXX]')
|
||||||
eq({'\196\n'}, eval('msgpackdump([{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}])'))
|
dump_eq({'\196\n'}, '[{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]')
|
||||||
eq({'\160'}, eval('msgpackdump([{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}])'))
|
dump_eq({'\160'}, '[{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can dump NULL blob', function()
|
it('can dump NULL blob', function()
|
||||||
|
|||||||
Reference in New Issue
Block a user