viminfo: First version of ShaDa file dumping
What works:
1. ShaDa file dumping: header, registers, jump list, history, search patterns,
substitute strings, variables.
2. ShaDa file reading: registers, global marks, variables.
Most was not tested.
TODO:
1. Merging.
2. Reading history, local marks, jump and buffer lists.
3. Documentation update.
4. Converting some data from &encoding.
5. Safer variant of dumping viminfo (dump to temporary file then rename).
6. Removing old viminfo code (currently masked with `#if 0` in a ShaDa file for
reference).
2015-04-25 08:47:31 -07:00
|
|
|
|
#!/usr/bin/env python3.4
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
import codecs
|
|
|
|
|
|
|
|
|
|
from enum import Enum
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from functools import reduce
|
|
|
|
|
|
|
|
|
|
import msgpack
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EntryTypes(Enum):
|
|
|
|
|
Unknown = -1
|
|
|
|
|
Missing = 0
|
|
|
|
|
Header = 1
|
|
|
|
|
SearchPattern = 2
|
|
|
|
|
SubString = 3
|
|
|
|
|
HistoryEntry = 4
|
|
|
|
|
Register = 5
|
|
|
|
|
Variable = 6
|
|
|
|
|
GlobalMark = 7
|
|
|
|
|
Jump = 8
|
|
|
|
|
BufferList = 9
|
|
|
|
|
LocalMark = 10
|
2015-06-27 22:06:16 -07:00
|
|
|
|
Change = 11
|
viminfo: First version of ShaDa file dumping
What works:
1. ShaDa file dumping: header, registers, jump list, history, search patterns,
substitute strings, variables.
2. ShaDa file reading: registers, global marks, variables.
Most was not tested.
TODO:
1. Merging.
2. Reading history, local marks, jump and buffer lists.
3. Documentation update.
4. Converting some data from &encoding.
5. Safer variant of dumping viminfo (dump to temporary file then rename).
6. Removing old viminfo code (currently masked with `#if 0` in a ShaDa file for
reference).
2015-04-25 08:47:31 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def strtrans_errors(e):
|
|
|
|
|
if not isinstance(e, UnicodeDecodeError):
|
|
|
|
|
raise NotImplementedError('don’t know how to handle {0} error'.format(
|
|
|
|
|
e.__class__.__name__))
|
|
|
|
|
return '<{0:x}>'.format(reduce((lambda a, b: a*0x100+b),
|
|
|
|
|
list(e.object[e.start:e.end]))), e.end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
codecs.register_error('strtrans', strtrans_errors)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def idfunc(o):
|
|
|
|
|
return o
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CharInt(int):
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return super(CharInt, self).__repr__() + ' (\'%s\')' % chr(self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ctable = {
|
|
|
|
|
bytes: lambda s: s.decode('utf-8', 'strtrans'),
|
|
|
|
|
dict: lambda d: dict((mnormalize(k), mnormalize(v)) for k, v in d.items()),
|
|
|
|
|
list: lambda l: list(mnormalize(i) for i in l),
|
|
|
|
|
int: lambda n: CharInt(n) if 0x20 <= n <= 0x7E else n,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def mnormalize(o):
|
|
|
|
|
return ctable.get(type(o), idfunc)(o)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with open(sys.argv[1], 'rb') as fp:
|
|
|
|
|
unpacker = msgpack.Unpacker(file_like=fp)
|
|
|
|
|
while True:
|
|
|
|
|
try:
|
|
|
|
|
typ = EntryTypes(unpacker.unpack())
|
|
|
|
|
except msgpack.OutOfData:
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
timestamp = unpacker.unpack()
|
|
|
|
|
time = datetime.fromtimestamp(timestamp)
|
|
|
|
|
length = unpacker.unpack()
|
|
|
|
|
entry = unpacker.unpack()
|
|
|
|
|
print('{0:13} {1} {2:5} {3!r}'.format(
|
|
|
|
|
typ.name, time.isoformat(), length, mnormalize(entry)))
|