Wikia

Vim Tips Wiki

Changes: Back up Lists and Dictionaries to viminfo

Edit

Back to page

(Comments)
(Bug fixes)
Line 18: Line 18:
 
There are a few interesting bits here:
 
There are a few interesting bits here:
   
*<code>Ctrl-A</code> lists all possible completions. We can get a list of all global variables via <code>:let g:<c-a></code>. This list can then be written to a variable by going back and changing the line to <code>:let varlist=...</code>
+
*<code>Ctrl-A</code> lists all possible completions. We can get a list of all global variables via <code>:let g:<c-a></code>. This list can then be written to a variable by going back and changing the line to <code>:let v=...</code>
   
*<code>type()</code> returns a 3 or 4 if a variable is a list or a dictionary.
+
*<code>type()</code> > 1 means everything except for strings and numbers, ie, funcref, list, dic, float
   
 
*<code>==#</code> compares strings case sensitively, allowing us to check whether a variable's name remains the same when converted to uppercase.
 
*<code>==#</code> compares strings case sensitively, allowing us to check whether a variable's name remains the same when converted to uppercase.
   
*<code>string()</code> converts a list or dictionary into the command used to produce it. Writing the string <code>"let v=..."</code> rather than the raw data is a convenient way to store variables since in order to recover the variables we can simply <code>:source</code> the file.
+
*<code>string()</code> converts a list or dictionary into the command used to produce it. Writing the string <code>"let var=..."</code> rather than the raw data is a convenient way to store variables since in order to recover the variables we can simply <code>:source</code> the file.
   
*<code>split(...,"\n")</code> splits variables containing the "\n" character. For some reason directly writing a variable containing "\n" produces errors when sourcing the file.
+
*<code>substitute(...)</code> For some reason directly writing a variable containing "\n" produces errors when sourcing the file, vim treats it as an actual line break. We have to substitute the \n char with the string <code>'."\n".'</code>
   
 
*<code>au VimLeavePre</code> automatically calls this function on exiting vim.
 
*<code>au VimLeavePre</code> automatically calls this function on exiting vim.
Line 34: Line 34:
 
<pre>
 
<pre>
 
fun! WriteVars(filename)
 
fun! WriteVars(filename)
sil! exe "norm! :let g:\<c-a>'\<c-b>\<right>\<right>
+
sil exe "norm! :let g:\<c-a>'\<c-b>\<right>\<right>\<right>\<right>v='\<cr>"
\\<right>\<right>varlist='\<cr>"
+
let list=[]
let saves=filter(split(varlist),
+
for name in split(v)
\'abs(type(eval(v:val))-3.5)<1 && v:val[2:]==#toupper(v:val[2:])')
+
if name[2:]==#toupper(name[2:]) && eval("type(".name.")") > 1
let list=[]
+
call add(list,substitute("let ".name."="
for key in saves
+
\.eval("string(".name.")"),"\n",'''."\\n".''',"g"))
if exists(key)
+
en
let splitlist=split('let '.key.'='.string(eval(key)),"\n")
+
endfor
call add(list,splitlist[0])
+
call writefile(list,a:filename)
for line in splitlist[1:]
 
call add(list,"\\".line)
 
endfor
 
en
 
endfor
 
call writefile(list,a:filename)
 
 
endfun
 
endfun
+
 
au VimLeavePre * call WriteVars('vimlistsave')
 
au VimLeavePre * call WriteVars('vimlistsave')
 
if filereadable('vimlistsave')
 
if filereadable('vimlistsave')

Revision as of 23:16, October 10, 2012

The "!" option in set viminfo stores string and number variables with all uppercase names to the viminfo file. It's possible to extend this behavior to dictionaries and lists too, writing to a file other than viminfo.

LIMITATION There is no easy way to back up lists that are equivalent to each other, ie, this will make identical lists copies of each other. Before saving:

let G=[1,2] 
let H=G
let G[0]=3
ec H[0]
"This will print 3

And after restoring:

let G[1]=4
ec H[1]
"This will print 2

There are a few interesting bits here:

  • Ctrl-A lists all possible completions. We can get a list of all global variables via :let g:<c-a>. This list can then be written to a variable by going back and changing the line to :let v=...
  • type() > 1 means everything except for strings and numbers, ie, funcref, list, dic, float
  • ==# compares strings case sensitively, allowing us to check whether a variable's name remains the same when converted to uppercase.
  • string() converts a list or dictionary into the command used to produce it. Writing the string "let var=..." rather than the raw data is a convenient way to store variables since in order to recover the variables we can simply :source the file.
  • substitute(...) For some reason directly writing a variable containing "\n" produces errors when sourcing the file, vim treats it as an actual line break. We have to substitute the \n char with the string '."\n".'
  • au VimLeavePre automatically calls this function on exiting vim.

Script

The following script can be placed in your vimrc.

fun! WriteVars(filename)
    sil exe "norm! :let g:\<c-a>'\<c-b>\<right>\<right>\<right>\<right>v='\<cr>"
    let list=[]
    for name in split(v)
        if name[2:]==#toupper(name[2:]) && eval("type(".name.")") > 1
            call add(list,substitute("let ".name."="
            \.eval("string(".name.")"),"\n",'''."\\n".''',"g"))
        en
    endfor
    call writefile(list,a:filename)
endfun
 
au VimLeavePre * call WriteVars('vimlistsave')
if filereadable('vimlistsave')
	source vimlistsave
endif

References

Comments

Does this script do anything not done by built-in Vim functionality, after version 7.3.30? --Fritzophrenic (talk) 04:49, October 7, 2012 (UTC)

I'm still running 7.3 compiled by someone long ago for android -- I don't have the means to compile a newer version. Also, the Windows version linked to from the vim.org website isn't patched. I haven't tested the patched version, the help file diff says "Nested List and Dict items may not be read back correctly, you end up with a string representation instead.". I'm not sure what they mean by "may", but this method does nested lists just fine.

It still doesn't do "pointers to the same list" of course, which probably can't be done in vimscript and would definitely require a patch. In my own vimrc file, I've added something along the lines of

if has_key(eval('dictname'),"reinitafterstorate")
	call add(list,"call ".dictname.".reinitafterstorage()")
end

into WriteVar(), so that the reinitafterstorage function would reinitialize any lists in the dictionary so that they point to the same address. I remember being really confused the first time this happened. --Q335r49 October 7, 2012

Around Wikia's network

Random Wiki