如何在VimScript中序列化变量?

rhfm7lfc  于 2023-06-23  发布在  其他
关注(0)|答案(4)|浏览(93)

我想保存一个随机的Vim字典,比如说:

let dico = {'a' : [[1,2], [3]], 'b' : {'in': "str", 'out' : 51}}

有什么更好的方法吗?我可以使用的东西,如:

call SaveVariable(dico, "safe.vimData")
let recover = ReadVariable("safe.vimData")

或者我应该自己构建一些只有文本文件的东西?

k10s72fa

k10s72fa1#

您可以充分利用:string()函数。测试这些:

let g:dico = {'a' : [[1,2], [3]], 'b' : {'in': "str", 'out' : 51}}
let str_dico = 'let g:dico_copy = ' . string(dico)
echo str_dico
execute str_dico
echo g:dico_copy

...因此您可以将 str_dico 字符串保存为vimscript文件的一行(例如使用writefile()),然后直接source vim文件。

mfpqipee

mfpqipee2#

多亏了VanLaser(cheers),我已经能够使用stringwritefilereadfile实现这些函数。这不是二进制序列化,但它工作得很好:)

function! SaveVariable(var, file)
    " turn the var to a string that vimscript understands
    let serialized = string(a:var)
    " dump this string to a file
    call writefile([serialized], a:file)
endfun

function! ReadVariable(file)
    " retrieve string from the file
    let serialized = readfile(a:file)[0]
    " turn it back to a vimscript variable
    execute "let result = " . serialized
    return result
endfun

这样使用它们:

call SaveVariable(anyvar, "safe.vimData")
let restore = ReadVariable("safe.vimData")

好好享受吧!

blpfk2vs

blpfk2vs3#

Vim内置了JSON序列化:

let dico = { "a" : 10, "b" : 20, }
call writefile(json_encode(dico)->split(), 'saved.json')
let recover = json_decode(readfile('saved.json')->join())

使用仅数据格式存储字典可以避免代码注入。
要支持旧版本的vim,请参阅this answer

uplii1fm

uplii1fm4#

我在几年前写的一个剧本中使用了@iago-lito的答案。昨天我花了一些时间来改进它。vim字典与JSON对象非常相似,但是:
1.当我打开文件和set filetype=json时,linter抱怨字符串周围的单引号,并且

  1. JSON格式化程序将文本分割成多行,并缩进它们以创建一个漂亮的文件。因此,只阅读文本的第0行并不能给予完整的dictionary对象。
    以下是我的修改,以解决这两个问题。
function! SaveVariable(var, file)
    " Change all single quotes to double quotes.
    " {'x':'O''Toole','y':['A',2,'d']} -> {"x":"O""Toole","y":["A",2,"d"]}
    let serialized = substitute(string(a:var),"'",'"','g')
    " Change all escaped double quotes back to apostrophes.
    " {"x":"O""Toole","y":["A",2,"d"]} -> {"x":"O'Toole","y":["A",2,"d"]}
    let serialized = substitute(serialized,'""', "'",'g')
    call writefile([serialized], a:file)
endfunction

function! ReadVariable(file)
    execute 'let result = [' . join(readfile(a:file),'') . ']'
    return result[0]
endfunction

这似乎适用于所有类型的数据。我用一个对象、一个列表、数字和字符串标量值测试了它。
陌生人,危险!
这里有一个警告,沿着着这个和任何其他动态生成的代码。@iago-lito和我的解决方案都容易受到代码注入的攻击,如果您正在阅读超出您控制范围的文件,那么您的机器可能会发生不好的事情。例如,如果有人偷偷将以下内容放入文件中:

42|call system('rmdir /s /q c:\')|call system('rm -rf /')

调用@iago-lito的ReadVariable()将返回42,但您的计算机将被吐司,无论是Windows,Mac还是Linux机器。我的版本也失败了,尽管使用了更复杂的语句版本:

42]|call system('rmdir /s /q c:\')|call system('rm -rf /')|let x=[

一个合适的解决方案是解析文本,查找实际数据的结尾,并转储它之后的所有内容。这意味着你失去了这种方法的简单性。Vim和Neovim近年来取得了长足的进步。据我所知,luapython比以往更容易集成到vimscript中。如果这两种语言中的任何一种对这个问题都有内置的答案,我不会感到惊讶。

相关问题