Mercurial > public > mercurial-scm > hg
comparison mercurial/filemerge.py @ 48587:3c8cc987672e
simplemerge: take over formatting of label from `filemerge`
The padding we do of conflict labels depends on which conflict marker
style is used. For two-way conflict markers (the default), the length
of the base label shouldn't matter. It does before this patch,
however. This patch moves the formatting from `filemerge` to
`simplemerge`. The latter knows which conflict marker style to use, so
it can easily decide about the padding.
This change will allow us to use more descriptive "base" labels
without causing illogical padding in 2-way markers. I'll do that next.
One wrinkle is that we pass the same labels to external merge tools. I
decided to change that in this patch to be simpler: no padding, and no
ellipsis to fit within 80 columns. My reasoning is that the typical
external, 3-or-4-panel merge tool doesn't show the labels on top of
each others, so the padding doesn't make sense there. The ellipsis is
probably not necessary because the external tools probably have their
own way of dealing with long labels. Also, we limit them to "80 - 8"
to fit the "<<<<<<< " before, which is almost definitely not what an
external tool would put there.
Differential Revision: https://phab.mercurial-scm.org/D12019
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Thu, 20 Jan 2022 11:06:52 -0800 |
parents | fd9fe2658cda |
children | d9af7c1fb619 |
comparison
equal
deleted
inserted
replaced
48586:fd9fe2658cda | 48587:3c8cc987672e |
---|---|
38 util, | 38 util, |
39 ) | 39 ) |
40 | 40 |
41 from .utils import ( | 41 from .utils import ( |
42 procutil, | 42 procutil, |
43 stringutil, | |
44 ) | 43 ) |
45 | 44 |
46 | 45 |
47 def _toolstr(ui, tool, part, *args): | 46 def _toolstr(ui, tool, part, *args): |
48 return ui.config(b"merge-tools", tool + b"." + part, *args) | 47 return ui.config(b"merge-tools", tool + b"." + part, *args) |
722 with _maketempfiles( | 721 with _maketempfiles( |
723 repo, fco, fca, repo.wvfs.join(backup.path()), b"$output" in args | 722 repo, fco, fca, repo.wvfs.join(backup.path()), b"$output" in args |
724 ) as temppaths: | 723 ) as temppaths: |
725 basepath, otherpath, localoutputpath = temppaths | 724 basepath, otherpath, localoutputpath = temppaths |
726 outpath = b"" | 725 outpath = b"" |
726 | |
727 def format_label(input): | |
728 if input.label_detail: | |
729 return b'%s: %s' % (input.label, input.label_detail) | |
730 else: | |
731 return input.label | |
732 | |
727 env = { | 733 env = { |
728 b'HG_FILE': fcd.path(), | 734 b'HG_FILE': fcd.path(), |
729 b'HG_MY_NODE': short(mynode), | 735 b'HG_MY_NODE': short(mynode), |
730 b'HG_OTHER_NODE': short(fco.changectx().node()), | 736 b'HG_OTHER_NODE': short(fco.changectx().node()), |
731 b'HG_BASE_NODE': short(fca.changectx().node()), | 737 b'HG_BASE_NODE': short(fca.changectx().node()), |
732 b'HG_MY_ISLINK': b'l' in fcd.flags(), | 738 b'HG_MY_ISLINK': b'l' in fcd.flags(), |
733 b'HG_OTHER_ISLINK': b'l' in fco.flags(), | 739 b'HG_OTHER_ISLINK': b'l' in fco.flags(), |
734 b'HG_BASE_ISLINK': b'l' in fca.flags(), | 740 b'HG_BASE_ISLINK': b'l' in fca.flags(), |
735 b'HG_MY_LABEL': local.label, | 741 b'HG_MY_LABEL': format_label(local), |
736 b'HG_OTHER_LABEL': other.label, | 742 b'HG_OTHER_LABEL': format_label(other), |
737 b'HG_BASE_LABEL': base.label, | 743 b'HG_BASE_LABEL': format_label(base), |
738 } | 744 } |
739 ui = repo.ui | 745 ui = repo.ui |
740 | 746 |
741 if b"$output" in args: | 747 if b"$output" in args: |
742 # read input from backup, write to original | 748 # read input from backup, write to original |
745 replace = { | 751 replace = { |
746 b'local': localpath, | 752 b'local': localpath, |
747 b'base': basepath, | 753 b'base': basepath, |
748 b'other': otherpath, | 754 b'other': otherpath, |
749 b'output': outpath, | 755 b'output': outpath, |
750 b'labellocal': local.label, | 756 b'labellocal': format_label(local), |
751 b'labelother': other.label, | 757 b'labelother': format_label(other), |
752 b'labelbase': base.label, | 758 b'labelbase': format_label(base), |
753 } | 759 } |
754 args = util.interpolate( | 760 args = util.interpolate( |
755 br'\$', | 761 br'\$', |
756 replace, | 762 replace, |
757 args, | 763 args, |
799 r = 1 | 805 r = 1 |
800 repo.ui.debug(b'merge tool returned: %d\n' % r) | 806 repo.ui.debug(b'merge tool returned: %d\n' % r) |
801 return True, r, False | 807 return True, r, False |
802 | 808 |
803 | 809 |
804 def _populate_label_detail(input, template, pad): | 810 def _populate_label_detail(input, template): |
805 """Applies the given template to the ctx, prefixed by the label. | 811 """Applies the given template to the ctx and stores it in the input.""" |
806 | |
807 Pad is the minimum width of the label prefix, so that multiple markers | |
808 can have aligned templated parts. | |
809 """ | |
810 ctx = input.fctx.changectx() | 812 ctx = input.fctx.changectx() |
811 if ctx.node() is None: | 813 if ctx.node() is None: |
812 ctx = ctx.p1() | 814 ctx = ctx.p1() |
813 | 815 |
814 props = {b'ctx': ctx} | 816 props = {b'ctx': ctx} |
815 templateresult = template.renderdefault(props) | 817 templateresult = template.renderdefault(props) |
816 | 818 input.label_detail = templateresult.splitlines()[0] # split for safety |
817 label = (b'%s:' % input.label).ljust(pad + 1) | |
818 mark = b'%s %s' % (label, templateresult) | |
819 mark = mark.splitlines()[0] # split for safety | |
820 | |
821 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ') | |
822 input.label = stringutil.ellipsis(mark, 80 - 8) | |
823 | 819 |
824 | 820 |
825 def _populate_label_details(repo, inputs, tool=None): | 821 def _populate_label_details(repo, inputs, tool=None): |
826 """Formats the given labels using the conflict marker template. | 822 """Populates the label details using the conflict marker template.""" |
827 | |
828 Returns a list of formatted labels. | |
829 """ | |
830 ui = repo.ui | 823 ui = repo.ui |
831 template = ui.config(b'command-templates', b'mergemarker') | 824 template = ui.config(b'command-templates', b'mergemarker') |
832 if tool is not None: | 825 if tool is not None: |
833 template = _toolstr(ui, tool, b'mergemarkertemplate', template) | 826 template = _toolstr(ui, tool, b'mergemarkertemplate', template) |
834 template = templater.unquotestring(template) | 827 template = templater.unquotestring(template) |
835 tres = formatter.templateresources(ui, repo) | 828 tres = formatter.templateresources(ui, repo) |
836 tmpl = formatter.maketemplater( | 829 tmpl = formatter.maketemplater( |
837 ui, template, defaults=templatekw.keywords, resources=tres | 830 ui, template, defaults=templatekw.keywords, resources=tres |
838 ) | 831 ) |
839 | 832 |
840 pad = max(len(input.label) for input in inputs) | |
841 | |
842 for input in inputs: | 833 for input in inputs: |
843 _populate_label_detail(input, tmpl, pad) | 834 _populate_label_detail(input, tmpl) |
844 | 835 |
845 | 836 |
846 def partextras(labels): | 837 def partextras(labels): |
847 """Return a dictionary of extra labels for use in prompts to the user | 838 """Return a dictionary of extra labels for use in prompts to the user |
848 | 839 |
1109 # we're done if premerge was successful (r is 0) | 1100 # we're done if premerge was successful (r is 0) |
1110 if not r: | 1101 if not r: |
1111 return r, False | 1102 return r, False |
1112 | 1103 |
1113 # Reset to basic labels | 1104 # Reset to basic labels |
1114 local.label = labels[0] | 1105 local.label_detail = None |
1115 other.label = labels[1] | 1106 other.label_detail = None |
1116 base.label = labels[2] | 1107 base.label_detail = None |
1117 | 1108 |
1118 if markerstyle != b'basic': | 1109 if markerstyle != b'basic': |
1119 _populate_label_details(repo, [local, other, base], tool=tool) | 1110 _populate_label_details(repo, [local, other, base], tool=tool) |
1120 | 1111 |
1121 needcheck, r, deleted = func( | 1112 needcheck, r, deleted = func( |