Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/simplemerge.py @ 48603:77e24ee8994b
simplemerge: take arguments as annotated context objects
The labels we put in conflict markers are formatted so the part before
the ':' (typically says things like "local") is padded so the ':' is
aligned among the labels. That means that if you specify a long label
for "base" but the conflict marker style is "merge" (i.e. 2-way), the
other two will have unwanted padding. We often don't specify a label
for the base, so we don't notice the problem (and it may very well be
that it didn't exist before my D11972).
I think the best fix is to pass the labels along with the context
objects, so the low-level code that switches on the marker style to
use (i.e. `simplemerge`) can do the formatting. This patch starts
doing that by passing a fully-formatted label to `simplemerge`. A
coming patch will move the formatting to `simplemerge`.
Differential Revision: https://phab.mercurial-scm.org/D12013
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Thu, 20 Jan 2022 11:00:30 -0800 |
parents | 50de08904c63 |
children | 3c8cc987672e |
comparison
equal
deleted
inserted
replaced
48602:62682662346c | 48603:77e24ee8994b |
---|---|
17 # s: "i hate that." | 17 # s: "i hate that." |
18 | 18 |
19 from __future__ import absolute_import | 19 from __future__ import absolute_import |
20 | 20 |
21 from .i18n import _ | 21 from .i18n import _ |
22 from .thirdparty import attr | |
22 from . import ( | 23 from . import ( |
23 error, | 24 error, |
24 mdiff, | 25 mdiff, |
25 pycompat, | 26 pycompat, |
26 ) | 27 ) |
282 if not opts.get('text'): | 283 if not opts.get('text'): |
283 raise error.Abort(msg) | 284 raise error.Abort(msg) |
284 return text | 285 return text |
285 | 286 |
286 | 287 |
287 def _picklabels(overrides): | 288 def _format_labels(*inputs): |
288 if len(overrides) > 3: | 289 labels = [] |
289 raise error.Abort(_(b"can only specify three labels.")) | 290 for input in inputs: |
290 result = [None, None, None] | 291 if input.label: |
291 for i, override in enumerate(overrides): | 292 labels.append(input.label) |
292 result[i] = override | 293 else: |
293 return result | 294 labels.append(None) |
295 return labels | |
294 | 296 |
295 | 297 |
296 def _detect_newline(m3): | 298 def _detect_newline(m3): |
297 if len(m3.a) > 0: | 299 if len(m3.a) > 0: |
298 if m3.a[0].endswith(b'\r\n'): | 300 if m3.a[0].endswith(b'\r\n'): |
460 else: | 462 else: |
461 lines.extend(group_lines) | 463 lines.extend(group_lines) |
462 return lines | 464 return lines |
463 | 465 |
464 | 466 |
465 def simplemerge(ui, localctx, basectx, otherctx, **opts): | 467 @attr.s |
468 class MergeInput(object): | |
469 fctx = attr.ib() | |
470 label = attr.ib(default=None) | |
471 | |
472 | |
473 def simplemerge(ui, local, base, other, **opts): | |
466 """Performs the simplemerge algorithm. | 474 """Performs the simplemerge algorithm. |
467 | 475 |
468 The merged result is written into `localctx`. | 476 The merged result is written into `localctx`. |
469 """ | 477 """ |
470 | 478 |
477 # it'd be worth considering whether merging encoded data (what the | 485 # it'd be worth considering whether merging encoded data (what the |
478 # repository usually sees) might be more useful. | 486 # repository usually sees) might be more useful. |
479 return _verifytext(ctx.decodeddata(), ctx.path(), ui, opts) | 487 return _verifytext(ctx.decodeddata(), ctx.path(), ui, opts) |
480 | 488 |
481 try: | 489 try: |
482 localtext = readctx(localctx) | 490 localtext = readctx(local.fctx) |
483 basetext = readctx(basectx) | 491 basetext = readctx(base.fctx) |
484 othertext = readctx(otherctx) | 492 othertext = readctx(other.fctx) |
485 except error.Abort: | 493 except error.Abort: |
486 return True | 494 return True |
487 | 495 |
488 m3 = Merge3Text(basetext, localtext, othertext) | 496 m3 = Merge3Text(basetext, localtext, othertext) |
489 conflicts = False | 497 conflicts = False |
493 elif mode == b'local': | 501 elif mode == b'local': |
494 lines = _resolve(m3, (1,)) | 502 lines = _resolve(m3, (1,)) |
495 elif mode == b'other': | 503 elif mode == b'other': |
496 lines = _resolve(m3, (2,)) | 504 lines = _resolve(m3, (2,)) |
497 else: | 505 else: |
498 name_a, name_b, name_base = _picklabels(opts.get('label', [])) | |
499 if mode == b'mergediff': | 506 if mode == b'mergediff': |
500 lines, conflicts = render_mergediff(m3, name_a, name_b, name_base) | 507 labels = _format_labels(local, other, base) |
508 lines, conflicts = render_mergediff(m3, *labels) | |
501 elif mode == b'merge3': | 509 elif mode == b'merge3': |
502 lines, conflicts = render_merge3(m3, name_a, name_b, name_base) | 510 labels = _format_labels(local, other, base) |
511 lines, conflicts = render_merge3(m3, *labels) | |
503 else: | 512 else: |
504 lines, conflicts = render_minimized(m3, name_a, name_b) | 513 labels = _format_labels(local, other) |
514 lines, conflicts = render_minimized(m3, *labels) | |
505 | 515 |
506 mergedtext = b''.join(lines) | 516 mergedtext = b''.join(lines) |
507 if opts.get('print'): | 517 if opts.get('print'): |
508 ui.fout.write(mergedtext) | 518 ui.fout.write(mergedtext) |
509 else: | 519 else: |
510 # localctx.flags() already has the merged flags (done in | 520 # local.fctx.flags() already has the merged flags (done in |
511 # mergestate.resolve()) | 521 # mergestate.resolve()) |
512 localctx.write(mergedtext, localctx.flags()) | 522 local.fctx.write(mergedtext, local.fctx.flags()) |
513 | 523 |
514 return conflicts | 524 return conflicts |