54
54
Typically the index number will be valid only inside this weave and
55
55
the version-id is used to reference it in the larger world.
57
The weave is represented as a list mixing edit instructions and
58
literal text. Each entry in _l can be either a string (or
59
unicode), or a tuple. If a string, it means that the given line
60
should be output in the currently active revisions.
62
If a tuple, it gives a processing instruction saying in which
63
revisions the enclosed lines are active. The tuple has the form
64
(instruction, version).
66
The instruction can be '{' or '}' for an insertion block, and '['
67
and ']' for a deletion block respectively. The version is the
68
integer version index.
72
* A later version can delete lines that were introduced by any
73
number of ancestor versions; this implies that deletion
74
instructions can span insertion blocks without regard to the
75
insertion block's nesting.
77
* Similarly, deletions need not be properly nested.
58
List of edit instructions.
60
Each line is stored as a tuple of (index-id, text). The line
61
is present in the version equal to index-id.
64
84
List of versions, indexed by index number.
83
103
Sequence of lines to be added in the new version."""
84
if not isinstance(text, list):
85
raise ValueError("text should be a list, not %s" % type(text))
87
104
self._check_versions(parents)
105
self._check_lines(text)
89
107
idx = len(self._v)
106
124
raise NotImplementedError("can't handle replacing weave [%d:%d] yet"
109
for line in newlines:
110
self._l.insert(i1 + offset, (idx, line))
127
self._l.insert(i1 + offset, ('{', idx))
129
self._l[i:i] = newlines
130
self._l.insert(i + 1, ('}', idx))
131
offset += 2 + len(newlines)
113
133
self._v.append(VerInfo(parents))
115
135
# special case; adding with no parents revision; can do this
116
136
# more quickly by just appending unconditionally
118
self._l.append((idx, line))
137
self._l.append(('{', idx))
139
self._l.append(('}', idx))
120
141
self._v.append(VerInfo())
146
def _check_lines(self, text):
147
if not isinstance(text, list):
148
raise ValueError("text should be a list, not %s" % type(text))
151
if not isinstance(l, basestring):
152
raise ValueError("text line should be a string or unicode, not %s" % type(l))
125
156
def _check_versions(self, indexes):
126
157
"""Check everything in the sequence of indexes is valid"""
127
158
for i in indexes:
145
176
raise IndexError('version index %d out of range' % index)
146
177
included = set(vi.included)
147
178
included.add(index)
148
return iter(self._extract(included))
179
for origin, lineno, text in self._extract(included):
151
183
def _extract(self, included):
152
184
"""Yield annotation of lines in included set.
186
Yields a sequence of tuples (origin, lineno, text), where
187
origin is the origin version, lineno the index in the weave,
188
and text the text of the line.
154
190
The set typically but not necessarily corresponds to a version.
156
for origin, line in self._l:
157
if origin in included:
197
if isinstance(l, tuple):
201
isactive = (v in included)
203
oldc, oldv = stack.pop()
206
isactive == stack and (stack[-1][1] in included)
208
raise ValueError("invalid processing instruction %r" % (l,))
210
assert isinstance(l, basestring)
212
origin = stack[-1][1]
213
yield origin, lineno, l
162
217
def getiter(self, index):
220
275
##print 'my lines:'
221
276
##pprint(self._l)
224
for origin, line in self._l:
225
if origin in included:
226
basis.append((lineno, line))
229
assert lineno == len(self._l)
278
basis = list(self._extract(included))
231
280
# now make a parallel list with only the text, to pass to the differ
232
basis_lines = [line for (lineno, line) in basis]
281
basis_lines = [line for (origin, lineno, line) in basis]
234
283
# add a sentinal, because we can also match against the final line
235
284
basis.append((len(self._l), None))