comparison mercurial/filemerge.py @ 29774:a7f8939641aa

merge: use labels in prompts to the user Now that we persist the labels, we can consistently use the labels in prompts for the user without risk of confusion. This changes a huge amount of command output: This means that merge prompts like: no tool found to merge a keep (l)ocal, take (o)ther, or leave (u)nresolved? u and remote changed a which local deleted use (c)hanged version, leave (d)eleted, or leave (u)nresolved? c become: no tool found to merge a keep (l)ocal [working copy], take (o)ther [destination], or leave (u)nresolved? u and remote [source] changed a which local [dest] deleted use (c)hanged version, leave (d)eleted, or leave (u)nresolved? c where "working copy" and "destination" were supplied by the command that requested the merge as labels for conflict markers, and thus should be human-friendly.
author Simon Farnsworth <simonfar@fb.com>
date Fri, 12 Aug 2016 06:01:42 -0700
parents 99b50346b750
children 978b907d9b36
comparison
equal deleted inserted replaced
29773:f2241c13d5a1 29774:a7f8939641aa
228 newdata = data.replace(style, tostyle) 228 newdata = data.replace(style, tostyle)
229 if newdata != data: 229 if newdata != data:
230 util.writefile(file, newdata) 230 util.writefile(file, newdata)
231 231
232 @internaltool('prompt', nomerge) 232 @internaltool('prompt', nomerge)
233 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf): 233 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf, labels=None):
234 """Asks the user which of the local `p1()` or the other `p2()` version to 234 """Asks the user which of the local `p1()` or the other `p2()` version to
235 keep as the merged version.""" 235 keep as the merged version."""
236 ui = repo.ui 236 ui = repo.ui
237 fd = fcd.path() 237 fd = fcd.path()
238 238
239 prompts = partextras(labels)
240 prompts['fd'] = fd
239 try: 241 try:
240 if fco.isabsent(): 242 if fco.isabsent():
241 index = ui.promptchoice( 243 index = ui.promptchoice(
242 _("local changed %s which remote deleted\n" 244 _("local%(l)s changed %(fd)s which remote%(o)s deleted\n"
243 "use (c)hanged version, (d)elete, or leave (u)nresolved?" 245 "use (c)hanged version, (d)elete, or leave (u)nresolved?"
244 "$$ &Changed $$ &Delete $$ &Unresolved") % fd, 2) 246 "$$ &Changed $$ &Delete $$ &Unresolved") % prompts, 2)
245 choice = ['local', 'other', 'unresolved'][index] 247 choice = ['local', 'other', 'unresolved'][index]
246 elif fcd.isabsent(): 248 elif fcd.isabsent():
247 index = ui.promptchoice( 249 index = ui.promptchoice(
248 _("remote changed %s which local deleted\n" 250 _("remote%(o)s changed %(fd)s which local%(l)s deleted\n"
249 "use (c)hanged version, leave (d)eleted, or " 251 "use (c)hanged version, leave (d)eleted, or "
250 "leave (u)nresolved?" 252 "leave (u)nresolved?"
251 "$$ &Changed $$ &Deleted $$ &Unresolved") % fd, 2) 253 "$$ &Changed $$ &Deleted $$ &Unresolved") % prompts, 2)
252 choice = ['other', 'local', 'unresolved'][index] 254 choice = ['other', 'local', 'unresolved'][index]
253 else: 255 else:
254 index = ui.promptchoice( 256 index = ui.promptchoice(
255 _("no tool found to merge %s\n" 257 _("no tool found to merge %(fd)s\n"
256 "keep (l)ocal, take (o)ther, or leave (u)nresolved?" 258 "keep (l)ocal%(l)s, take (o)ther%(o)s, or leave (u)nresolved?"
257 "$$ &Local $$ &Other $$ &Unresolved") % fd, 2) 259 "$$ &Local $$ &Other $$ &Unresolved") % prompts, 2)
258 choice = ['local', 'other', 'unresolved'][index] 260 choice = ['local', 'other', 'unresolved'][index]
259 261
260 if choice == 'other': 262 if choice == 'other':
261 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf) 263 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf,
264 labels)
262 elif choice == 'local': 265 elif choice == 'local':
263 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf) 266 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf,
267 labels)
264 elif choice == 'unresolved': 268 elif choice == 'unresolved':
265 return _ifail(repo, mynode, orig, fcd, fco, fca, toolconf) 269 return _ifail(repo, mynode, orig, fcd, fco, fca, toolconf,
270 labels)
266 except error.ResponseExpected: 271 except error.ResponseExpected:
267 ui.write("\n") 272 ui.write("\n")
268 return _ifail(repo, mynode, orig, fcd, fco, fca, toolconf) 273 return _ifail(repo, mynode, orig, fcd, fco, fca, toolconf,
274 labels)
269 275
270 @internaltool('local', nomerge) 276 @internaltool('local', nomerge)
271 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf): 277 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf, labels=None):
272 """Uses the local `p1()` version of files as the merged version.""" 278 """Uses the local `p1()` version of files as the merged version."""
273 return 0, fcd.isabsent() 279 return 0, fcd.isabsent()
274 280
275 @internaltool('other', nomerge) 281 @internaltool('other', nomerge)
276 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf): 282 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf, labels=None):
277 """Uses the other `p2()` version of files as the merged version.""" 283 """Uses the other `p2()` version of files as the merged version."""
278 if fco.isabsent(): 284 if fco.isabsent():
279 # local changed, remote deleted -- 'deleted' picked 285 # local changed, remote deleted -- 'deleted' picked
280 repo.wvfs.unlinkpath(fcd.path()) 286 repo.wvfs.unlinkpath(fcd.path())
281 deleted = True 287 deleted = True
283 repo.wwrite(fcd.path(), fco.data(), fco.flags()) 289 repo.wwrite(fcd.path(), fco.data(), fco.flags())
284 deleted = False 290 deleted = False
285 return 0, deleted 291 return 0, deleted
286 292
287 @internaltool('fail', nomerge) 293 @internaltool('fail', nomerge)
288 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf): 294 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf, labels=None):
289 """ 295 """
290 Rather than attempting to merge files that were modified on both 296 Rather than attempting to merge files that were modified on both
291 branches, it marks them as unresolved. The resolve command must be 297 branches, it marks them as unresolved. The resolve command must be
292 used to resolve these conflicts.""" 298 used to resolve these conflicts."""
293 # for change/delete conflicts write out the changed version, then fail 299 # for change/delete conflicts write out the changed version, then fail
535 _formatconflictmarker(repo, co, tmpl, labels[1], pad)] 541 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
536 if len(labels) > 2: 542 if len(labels) > 2:
537 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad)) 543 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
538 return newlabels 544 return newlabels
539 545
546 def partextras(labels):
547 """Return a dictionary of extra labels for use in prompts to the user
548
549 Intended use is in strings of the form "(l)ocal%(l)s".
550 """
551 if labels is None:
552 return {
553 "l": "",
554 "o": "",
555 }
556
557 return {
558 "l": " [%s]" % labels[0],
559 "o": " [%s]" % labels[1],
560 }
561
540 def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None): 562 def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None):
541 """perform a 3-way merge in the working directory 563 """perform a 3-way merge in the working directory
542 564
543 premerge = whether this is a premerge 565 premerge = whether this is a premerge
544 mynode = parent node before merge 566 mynode = parent node before merge
586 precheck = None 608 precheck = None
587 609
588 toolconf = tool, toolpath, binary, symlink 610 toolconf = tool, toolpath, binary, symlink
589 611
590 if mergetype == nomerge: 612 if mergetype == nomerge:
591 r, deleted = func(repo, mynode, orig, fcd, fco, fca, toolconf) 613 r, deleted = func(repo, mynode, orig, fcd, fco, fca, toolconf, labels)
592 return True, r, deleted 614 return True, r, deleted
593 615
594 if premerge: 616 if premerge:
595 if orig != fco.path(): 617 if orig != fco.path():
596 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd)) 618 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))