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
|
|
|
|
|
|
2015-08-07 19:10:19 -07:00
|
|
|
|
import os
|
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
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
2015-08-07 19:10:19 -07:00
|
|
|
|
fname = sys.argv[1]
|
2015-10-18 11:08:42 -07:00
|
|
|
|
try:
|
|
|
|
|
filt = sys.argv[2]
|
|
|
|
|
except IndexError:
|
|
|
|
|
filt = lambda entry: True
|
|
|
|
|
else:
|
|
|
|
|
_filt = filt
|
|
|
|
|
filt = lambda entry: eval(_filt, globals(), {'entry': entry})
|
|
|
|
|
|
2015-08-07 19:10:19 -07:00
|
|
|
|
poswidth = len(str(os.stat(fname).st_size or 1000))
|
|
|
|
|
|
|
|
|
|
|
2015-10-18 11:08:42 -07:00
|
|
|
|
class FullEntry(dict):
|
|
|
|
|
def __init__(self, val):
|
|
|
|
|
self.__dict__.update(val)
|
|
|
|
|
|
|
|
|
|
|
2015-08-07 19:10:19 -07:00
|
|
|
|
with open(fname, 'rb') as fp:
|
2015-07-26 09:29:49 -07:00
|
|
|
|
unpacker = msgpack.Unpacker(file_like=fp, read_size=1)
|
2015-08-07 19:10:19 -07:00
|
|
|
|
max_type = max(typ.value for typ in EntryTypes)
|
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
|
|
|
|
while True:
|
|
|
|
|
try:
|
2015-07-26 09:29:49 -07:00
|
|
|
|
pos = fp.tell()
|
2015-08-07 19:10:19 -07:00
|
|
|
|
typ = unpacker.unpack()
|
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
|
|
|
|
except msgpack.OutOfData:
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
timestamp = unpacker.unpack()
|
|
|
|
|
time = datetime.fromtimestamp(timestamp)
|
|
|
|
|
length = unpacker.unpack()
|
2015-08-07 19:10:19 -07:00
|
|
|
|
if typ > max_type:
|
|
|
|
|
entry = fp.read(length)
|
|
|
|
|
typ = EntryTypes.Unknown
|
|
|
|
|
else:
|
|
|
|
|
entry = unpacker.unpack()
|
|
|
|
|
typ = EntryTypes(typ)
|
2015-10-18 11:08:42 -07:00
|
|
|
|
full_entry = FullEntry({
|
|
|
|
|
'value': entry,
|
|
|
|
|
'timestamp': timestamp,
|
|
|
|
|
'time': time,
|
|
|
|
|
'length': length,
|
|
|
|
|
'pos': pos,
|
|
|
|
|
'type': typ,
|
|
|
|
|
})
|
|
|
|
|
if not filt(full_entry):
|
|
|
|
|
continue
|
2015-08-07 19:10:19 -07:00
|
|
|
|
print('%*u %13s %s %5u %r' % (
|
|
|
|
|
poswidth, pos, typ.name, time.isoformat(), length, mnormalize(entry)))
|