mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
simplemerge: unify the interface of automerge algorithms
Summary: This diff we unify the interface of automerge algorithms (trywordmerge, merge_adjacent_changes): ``` def automerge_algo(base_lines, a_lines, b_lines) -> Optional[List[bytes]]: pass ``` Reviewed By: quark-zju Differential Revision: D48845460 fbshipit-source-id: e018d1e6d6eb468d0a6eefed9905facb774055d6
This commit is contained in:
parent
812d0b2e6d
commit
667c59bd7f
@ -5,6 +5,7 @@
|
||||
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional
|
||||
|
||||
from edenscm import commands, error, mdiff, registrar, scmutil
|
||||
from edenscm.i18n import _
|
||||
@ -16,20 +17,10 @@ command = registrar.command(cmdtable)
|
||||
A, B, BASE = range(3)
|
||||
|
||||
|
||||
class Conflict:
|
||||
def __init__(self, base_lines, a_lines, b_lines):
|
||||
self.base_lines = base_lines
|
||||
self.a_lines = a_lines
|
||||
self.b_lines = b_lines
|
||||
self.merged_lines = []
|
||||
|
||||
|
||||
def merge_adjacent_changes(c: Conflict) -> bool:
|
||||
base_lines, a_lines, b_lines = c.base_lines, c.a_lines, c.b_lines
|
||||
|
||||
def merge_adjacent_changes(base_lines, a_lines, b_lines) -> Optional[List[bytes]]:
|
||||
# require something to be changed
|
||||
if not base_lines:
|
||||
return False
|
||||
return None
|
||||
|
||||
ablocks = unmatching_blocks(base_lines, a_lines)
|
||||
bblocks = unmatching_blocks(base_lines, b_lines)
|
||||
@ -40,11 +31,11 @@ def merge_adjacent_changes(c: Conflict) -> bool:
|
||||
while indexes[A] < len(ablocks) and indexes[B] < len(bblocks):
|
||||
ablock, bblock = ablocks[indexes[A]], bblocks[indexes[B]]
|
||||
if is_overlap(ablock[0], ablock[1], bblock[0], bblock[1]):
|
||||
return False
|
||||
return None
|
||||
elif is_non_unique_separator_for_insertion(
|
||||
base_lines, a_lines, b_lines, ablock, bblock
|
||||
):
|
||||
return False
|
||||
return None
|
||||
|
||||
i, block, lines = (
|
||||
(A, ablock, a_lines) if ablock[0] < bblock[0] else (B, bblock, b_lines)
|
||||
@ -73,9 +64,7 @@ def merge_adjacent_changes(c: Conflict) -> bool:
|
||||
|
||||
# add base lines at the end of block
|
||||
merged_lines.extend(base_lines[k:])
|
||||
c.merged_lines = merged_lines
|
||||
|
||||
return True
|
||||
return merged_lines
|
||||
|
||||
|
||||
class SmartMerge3Text(Merge3Text):
|
||||
@ -85,18 +74,7 @@ class SmartMerge3Text(Merge3Text):
|
||||
|
||||
def __init__(self, basetext, atext, btext, wordmerge=wordmergemode.disabled):
|
||||
Merge3Text.__init__(self, basetext, atext, btext, wordmerge=wordmerge)
|
||||
|
||||
def resolve_conflict(self, base_lines, a_lines, b_lines):
|
||||
"""Try automerge algorithms to resolve the conflict region.
|
||||
|
||||
Return resolved lines, or None if auto resolution failed.
|
||||
"""
|
||||
c = Conflict(base_lines, a_lines, b_lines)
|
||||
|
||||
if merge_adjacent_changes(c):
|
||||
return c.merged_lines
|
||||
|
||||
return None
|
||||
self.automerge_fns.append(merge_adjacent_changes)
|
||||
|
||||
|
||||
def is_non_unique_separator_for_insertion(
|
||||
|
@ -80,13 +80,17 @@ class wordmergemode:
|
||||
return cls.disabled
|
||||
|
||||
|
||||
def trywordmerge(basetext, atext, btext):
|
||||
def trywordmerge(base_lines, a_lines, b_lines):
|
||||
"""Try resolve conflicts using wordmerge.
|
||||
Return resolved text, or None if merge failed.
|
||||
Return resolved lines, or None if merge failed.
|
||||
"""
|
||||
basetext = b"".join(base_lines)
|
||||
atext = b"".join(a_lines)
|
||||
btext = b"".join(b_lines)
|
||||
try:
|
||||
m3 = Merge3Text(basetext, atext, btext, wordmerge=wordmergemode.enforced)
|
||||
return b"".join(render_markers(m3)[0])
|
||||
text = b"".join(render_markers(m3)[0])
|
||||
return text.splitlines(True)
|
||||
except CantShowWordConflicts:
|
||||
return None
|
||||
|
||||
@ -130,16 +134,14 @@ class Merge3Text:
|
||||
self.a = split(atext)
|
||||
self.b = split(btext)
|
||||
self.wordmerge = wordmerge
|
||||
|
||||
def resolve_conflict(self, base_lines, a_lines, b_lines):
|
||||
"""Try automerge algorithms to resolve the conflict region.
|
||||
|
||||
Return resolved lines, or None if auto resolution failed.
|
||||
"""
|
||||
return None
|
||||
self.automerge_fns = (
|
||||
[trywordmerge] if wordmerge == wordmergemode.ondemand else []
|
||||
)
|
||||
|
||||
def merge_groups(self, automerge=False):
|
||||
"""Yield sequence of line groups. Each one is a tuple:
|
||||
"""Yield sequence of line groups.
|
||||
|
||||
Each one is a tuple:
|
||||
|
||||
'unchanged', lines
|
||||
Lines unchanged from base
|
||||
@ -168,31 +170,21 @@ class Merge3Text:
|
||||
elif what == "b":
|
||||
yield what, self.b[t[1] : t[2]]
|
||||
elif what == "conflict":
|
||||
if self.wordmerge is wordmergemode.enforced:
|
||||
raise CantShowWordConflicts()
|
||||
|
||||
base_lines = self.base[t[1] : t[2]]
|
||||
a_lines = self.a[t[3] : t[4]]
|
||||
b_lines = self.b[t[5] : t[6]]
|
||||
|
||||
merged_lines = None
|
||||
if automerge:
|
||||
if self.wordmerge is wordmergemode.enforced:
|
||||
raise CantShowWordConflicts()
|
||||
elif self.wordmerge is wordmergemode.ondemand:
|
||||
# Try resolve the conflicted region using word merge
|
||||
subbasetext = b"".join(base_lines)
|
||||
subatext = b"".join(a_lines)
|
||||
subbtext = b"".join(b_lines)
|
||||
text = trywordmerge(subbasetext, subatext, subbtext)
|
||||
if text:
|
||||
merged_lines = text.splitlines(True)
|
||||
else:
|
||||
merged_lines = self.resolve_conflict(
|
||||
base_lines, a_lines, b_lines
|
||||
)
|
||||
|
||||
if merged_lines is not None:
|
||||
yield "automerge", merged_lines
|
||||
else:
|
||||
yield what, (base_lines, a_lines, b_lines)
|
||||
for fn in self.automerge_fns:
|
||||
merged_lines = fn(base_lines, a_lines, b_lines)
|
||||
if merged_lines is not None:
|
||||
yield "automerge", merged_lines
|
||||
break
|
||||
if merged_lines is None:
|
||||
yield (what, (base_lines, a_lines, b_lines))
|
||||
else:
|
||||
raise ValueError(what)
|
||||
|
||||
@ -430,8 +422,8 @@ def render_markers(
|
||||
lines = []
|
||||
for what, group_lines in merge_groups:
|
||||
if what == "conflict":
|
||||
base_lines, a_lines, b_lines = group_lines
|
||||
conflictscount += 1
|
||||
base_lines, a_lines, b_lines = group_lines
|
||||
if start_marker is not None:
|
||||
lines.append(start_marker + newline)
|
||||
lines.extend(a_lines)
|
||||
|
Loading…
Reference in New Issue
Block a user