311 programlen = self._program.__len__ |
311 programlen = self._program.__len__ |
312 oldproglen = programlen() |
312 oldproglen = programlen() |
313 appendinst = self._program.append |
313 appendinst = self._program.append |
314 |
314 |
315 # insert |
315 # insert |
|
316 blineinfos = [] |
|
317 bappend = blineinfos.append |
316 if b1 < b2: |
318 if b1 < b2: |
317 # Determine the jump target for the JGE at the start of |
319 # Determine the jump target for the JGE at the start of |
318 # the new block. |
320 # the new block. |
319 tgt = oldproglen + (b2 - b1 + 1) |
321 tgt = oldproglen + (b2 - b1 + 1) |
320 # Jump to skip the insert if we're at an older revision. |
322 # Jump to skip the insert if we're at an older revision. |
321 appendinst(_jl(rev, tgt)) |
323 appendinst(_jl(rev, tgt)) |
322 for linenum in pycompat.xrange(b1, b2): |
324 for linenum in pycompat.xrange(b1, b2): |
323 if _internal_blines is None: |
325 if _internal_blines is None: |
|
326 bappend(lineinfo(rev, linenum, programlen())) |
324 appendinst(_line(rev, linenum)) |
327 appendinst(_line(rev, linenum)) |
325 else: |
328 else: |
326 appendinst(_line(*_internal_blines[linenum])) |
329 newrev, newlinenum = _internal_blines[linenum] |
|
330 bappend(lineinfo(newrev, newlinenum, programlen())) |
|
331 appendinst(_line(newrev, newlinenum)) |
327 # delete |
332 # delete |
328 if a1 < a2: |
333 if a1 < a2: |
329 if a2 > len(ar.lines): |
334 if a2 > len(ar.lines): |
330 raise LineLogError( |
335 raise LineLogError( |
331 '%d contains %d lines, tried to access line %d' % ( |
336 '%d contains %d lines, tried to access line %d' % ( |
340 # invisible lines between a2-1 and a2 (IOW, lines that |
345 # invisible lines between a2-1 and a2 (IOW, lines that |
341 # are added later). |
346 # are added later). |
342 endaddr = ar.lines[a2 - 1]._offset + 1 |
347 endaddr = ar.lines[a2 - 1]._offset + 1 |
343 appendinst(_jge(rev, endaddr)) |
348 appendinst(_jge(rev, endaddr)) |
344 # copy instruction from a1 |
349 # copy instruction from a1 |
|
350 a1instpc = programlen() |
345 appendinst(a1inst) |
351 appendinst(a1inst) |
346 # if a1inst isn't a jump or EOF, then we need to add an unconditional |
352 # if a1inst isn't a jump or EOF, then we need to add an unconditional |
347 # jump back into the program here. |
353 # jump back into the program here. |
348 if not isinstance(a1inst, (_jump, _eof)): |
354 if not isinstance(a1inst, (_jump, _eof)): |
349 appendinst(_jump(0, a1info._offset + 1)) |
355 appendinst(_jump(0, a1info._offset + 1)) |
350 # Patch instruction at a1, which makes our patch live. |
356 # Patch instruction at a1, which makes our patch live. |
351 self._program[a1info._offset] = _jump(0, oldproglen) |
357 self._program[a1info._offset] = _jump(0, oldproglen) |
352 # For compat with the C version, re-annotate rev so that |
358 |
353 # self.annotateresult is cromulent.. We could fix up the |
359 # Update self._lastannotate in place. This serves as a cache to avoid |
354 # annotateresult in place (which is how the C version works), |
360 # expensive "self.annotate" in this function, when "replacelines" is |
355 # but for now we'll pass on that and see if it matters in |
361 # used continuously. |
356 # practice. |
362 if len(self._lastannotate.lines) > a1: |
357 self.annotate(max(self._lastannotate.rev, rev)) |
363 self._lastannotate.lines[a1]._offset = a1instpc |
|
364 else: |
|
365 assert isinstance(a1inst, _eof) |
|
366 self._lastannotate._eof = a1instpc |
|
367 self._lastannotate.lines[a1:a2] = blineinfos |
|
368 self._lastannotate.rev = max(self._lastannotate.rev, rev) |
|
369 |
358 if rev > self._maxrev: |
370 if rev > self._maxrev: |
359 self._maxrev = rev |
371 self._maxrev = rev |
360 |
372 |
361 def annotate(self, rev): |
373 def annotate(self, rev): |
362 pc = 1 |
374 pc = 1 |