453 |
453 |
454 # Rules |
454 # Rules |
455 rules = [] |
455 rules = [] |
456 rulelen = int(lines[index]) |
456 rulelen = int(lines[index]) |
457 index += 1 |
457 index += 1 |
458 for i in pycompat.xrange(rulelen): |
458 for i in range(rulelen): |
459 ruleaction = lines[index] |
459 ruleaction = lines[index] |
460 index += 1 |
460 index += 1 |
461 rule = lines[index] |
461 rule = lines[index] |
462 index += 1 |
462 index += 1 |
463 rules.append((ruleaction, rule)) |
463 rules.append((ruleaction, rule)) |
464 |
464 |
465 # Replacements |
465 # Replacements |
466 replacements = [] |
466 replacements = [] |
467 replacementlen = int(lines[index]) |
467 replacementlen = int(lines[index]) |
468 index += 1 |
468 index += 1 |
469 for i in pycompat.xrange(replacementlen): |
469 for i in range(replacementlen): |
470 replacement = lines[index] |
470 replacement = lines[index] |
471 original = bin(replacement[:40]) |
471 original = bin(replacement[:40]) |
472 succ = [ |
472 succ = [ |
473 bin(replacement[i : i + 40]) |
473 bin(replacement[i : i + 40]) |
474 for i in range(40, len(replacement), 40) |
474 for i in range(40, len(replacement), 40) |
489 |
489 |
490 def inprogress(self): |
490 def inprogress(self): |
491 return self.repo.vfs.exists(b'histedit-state') |
491 return self.repo.vfs.exists(b'histedit-state') |
492 |
492 |
493 |
493 |
494 class histeditaction(object): |
494 class histeditaction: |
495 def __init__(self, state, node): |
495 def __init__(self, state, node): |
496 self.state = state |
496 self.state = state |
497 self.repo = state.repo |
497 self.repo = state.repo |
498 self.node = node |
498 self.node = node |
499 |
499 |
503 ruleid = rule.strip().split(b' ', 1)[0] |
503 ruleid = rule.strip().split(b' ', 1)[0] |
504 # ruleid can be anything from rev numbers, hashes, "bookmarks" etc |
504 # ruleid can be anything from rev numbers, hashes, "bookmarks" etc |
505 # Check for validation of rule ids and get the rulehash |
505 # Check for validation of rule ids and get the rulehash |
506 try: |
506 try: |
507 rev = bin(ruleid) |
507 rev = bin(ruleid) |
508 except TypeError: |
508 except binascii.Error: |
509 try: |
509 try: |
510 _ctx = scmutil.revsingle(state.repo, ruleid) |
510 _ctx = scmutil.revsingle(state.repo, ruleid) |
511 rulehash = _ctx.hex() |
511 rulehash = _ctx.hex() |
512 rev = bin(rulehash) |
512 rev = bin(rulehash) |
513 except error.RepoLookupError: |
513 except error.RepoLookupError: |
551 {(b'templatealias', b'label(l,x)'): b"x"}, b'histedit' |
551 {(b'templatealias', b'label(l,x)'): b"x"}, b'histedit' |
552 ): |
552 ): |
553 summary = cmdutil.rendertemplate( |
553 summary = cmdutil.rendertemplate( |
554 ctx, ui.config(b'histedit', b'summary-template') |
554 ctx, ui.config(b'histedit', b'summary-template') |
555 ) |
555 ) |
556 # Handle the fact that `''.splitlines() => []` |
556 line = b'%s %s %s' % (self.verb, ctx, stringutil.firstline(summary)) |
557 summary = summary.splitlines()[0] if summary else b'' |
|
558 line = b'%s %s %s' % (self.verb, ctx, summary) |
|
559 # trim to 75 columns by default so it's not stupidly wide in my editor |
557 # trim to 75 columns by default so it's not stupidly wide in my editor |
560 # (the 5 more are left for verb) |
558 # (the 5 more are left for verb) |
561 maxlen = self.repo.ui.configint(b'histedit', b'linelen') |
559 maxlen = self.repo.ui.configint(b'histedit', b'linelen') |
562 maxlen = max(maxlen, 22) # avoid truncating hash |
560 maxlen = max(maxlen, 22) # avoid truncating hash |
563 return stringutil.ellipsis(line, maxlen) |
561 return stringutil.ellipsis(line, maxlen) |
1141 |
1139 |
1142 def screen_size(): |
1140 def screen_size(): |
1143 return struct.unpack(b'hh', fcntl.ioctl(1, termios.TIOCGWINSZ, b' ')) |
1141 return struct.unpack(b'hh', fcntl.ioctl(1, termios.TIOCGWINSZ, b' ')) |
1144 |
1142 |
1145 |
1143 |
1146 class histeditrule(object): |
1144 class histeditrule: |
1147 def __init__(self, ui, ctx, pos, action=b'pick'): |
1145 def __init__(self, ui, ctx, pos, action=b'pick'): |
1148 self.ui = ui |
1146 self.ui = ui |
1149 self.ctx = ctx |
1147 self.ctx = ctx |
1150 self.action = action |
1148 self.action = action |
1151 self.origpos = pos |
1149 self.origpos = pos |
1191 if summary: |
1189 if summary: |
1192 return summary |
1190 return summary |
1193 # This is split off from the prefix property so that we can |
1191 # This is split off from the prefix property so that we can |
1194 # separately make the description for 'roll' red (since it |
1192 # separately make the description for 'roll' red (since it |
1195 # will get discarded). |
1193 # will get discarded). |
1196 return self.ctx.description().splitlines()[0].strip() |
1194 return stringutil.firstline(self.ctx.description()) |
1197 |
1195 |
1198 def checkconflicts(self, other): |
1196 def checkconflicts(self, other): |
1199 if other.pos > self.pos and other.origpos <= self.origpos: |
1197 if other.pos > self.pos and other.origpos <= self.origpos: |
1200 if set(other.ctx.files()) & set(self.ctx.files()) != set(): |
1198 if set(other.ctx.files()) & set(self.ctx.files()) != set(): |
1201 self.conflicts.append(other) |
1199 self.conflicts.append(other) |
1290 |
1288 |
1291 bms = self.repo.nodebookmarks(ctx.node()) |
1289 bms = self.repo.nodebookmarks(ctx.node()) |
1292 line = b"bookmark: %s" % b' '.join(bms) |
1290 line = b"bookmark: %s" % b' '.join(bms) |
1293 win.addstr(3, 1, line[:length]) |
1291 win.addstr(3, 1, line[:length]) |
1294 |
1292 |
1295 line = b"summary: %s" % (ctx.description().splitlines()[0]) |
1293 line = b"summary: %s" % stringutil.firstline(ctx.description()) |
1296 win.addstr(4, 1, line[:length]) |
1294 win.addstr(4, 1, line[:length]) |
1297 |
1295 |
1298 line = b"files: " |
1296 line = b"files: " |
1299 win.addstr(5, 1, line) |
1297 win.addstr(5, 1, line) |
1300 fnx = 1 + len(line) |
1298 fnx = 1 + len(line) |
1574 rules[new_rule_pos].pos = new_rule_pos |
1572 rules[new_rule_pos].pos = new_rule_pos |
1575 rules[old_rule_pos].pos = old_rule_pos |
1573 rules[old_rule_pos].pos = old_rule_pos |
1576 |
1574 |
1577 start = min(old_rule_pos, new_rule_pos) |
1575 start = min(old_rule_pos, new_rule_pos) |
1578 end = max(old_rule_pos, new_rule_pos) |
1576 end = max(old_rule_pos, new_rule_pos) |
1579 for r in pycompat.xrange(start, end + 1): |
1577 for r in range(start, end + 1): |
1580 rules[new_rule_pos].checkconflicts(rules[r]) |
1578 rules[new_rule_pos].checkconflicts(rules[r]) |
1581 rules[old_rule_pos].checkconflicts(rules[r]) |
1579 rules[old_rule_pos].checkconflicts(rules[r]) |
1582 |
1580 |
1583 if self.selected: |
1581 if self.selected: |
1584 self.make_selection(newpos) |
1582 self.make_selection(newpos) |
2100 """This action runs when histedit is finishing its session""" |
2098 """This action runs when histedit is finishing its session""" |
2101 mergemod.update(repo[state.parentctxnode]) |
2099 mergemod.update(repo[state.parentctxnode]) |
2102 |
2100 |
2103 mapping, tmpnodes, created, ntm = processreplacement(state) |
2101 mapping, tmpnodes, created, ntm = processreplacement(state) |
2104 if mapping: |
2102 if mapping: |
2105 for prec, succs in pycompat.iteritems(mapping): |
2103 for prec, succs in mapping.items(): |
2106 if not succs: |
2104 if not succs: |
2107 ui.debug(b'histedit: %s is dropped\n' % short(prec)) |
2105 ui.debug(b'histedit: %s is dropped\n' % short(prec)) |
2108 else: |
2106 else: |
2109 ui.debug( |
2107 ui.debug( |
2110 b'histedit: %s is replaced by %s\n' |
2108 b'histedit: %s is replaced by %s\n' |
2320 ) |
2318 ) |
2321 state.backupfile = backupfile |
2319 state.backupfile = backupfile |
2322 |
2320 |
2323 |
2321 |
2324 def _getsummary(ctx): |
2322 def _getsummary(ctx): |
2325 # a common pattern is to extract the summary but default to the empty |
2323 return stringutil.firstline(ctx.description()) |
2326 # string |
|
2327 summary = ctx.description() or b'' |
|
2328 if summary: |
|
2329 summary = summary.splitlines()[0] |
|
2330 return summary |
|
2331 |
2324 |
2332 |
2325 |
2333 def bootstrapcontinue(ui, state, opts): |
2326 def bootstrapcontinue(ui, state, opts): |
2334 repo = state.repo |
2327 repo = state.repo |
2335 |
2328 |
2386 act.verb = fword |
2379 act.verb = fword |
2387 # get the target summary |
2380 # get the target summary |
2388 tsum = summary[len(fword) + 1 :].lstrip() |
2381 tsum = summary[len(fword) + 1 :].lstrip() |
2389 # safe but slow: reverse iterate over the actions so we |
2382 # safe but slow: reverse iterate over the actions so we |
2390 # don't clash on two commits having the same summary |
2383 # don't clash on two commits having the same summary |
2391 for na, l in reversed(list(pycompat.iteritems(newact))): |
2384 for na, l in reversed(list(newact.items())): |
2392 actx = repo[na.node] |
2385 actx = repo[na.node] |
2393 asum = _getsummary(actx) |
2386 asum = _getsummary(actx) |
2394 if asum == tsum: |
2387 if asum == tsum: |
2395 added = True |
2388 added = True |
2396 l.append(act) |
2389 l.append(act) |