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(