Add support for rewriting hunks if only specific lines match
This commit is contained in:
parent
56d1f03c83
commit
8ebcba623e
2 changed files with 87 additions and 22 deletions
|
|
@ -4,9 +4,9 @@ import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def should_include_change(
|
def filter_change_block(
|
||||||
change_lines: list[str], search: str, replace: str
|
change_lines: list[str], search: str, replace: str
|
||||||
) -> bool:
|
) -> tuple[list[str] | None, bool]:
|
||||||
removed_lines = []
|
removed_lines = []
|
||||||
added_lines = []
|
added_lines = []
|
||||||
phase = "minus"
|
phase = "minus"
|
||||||
|
|
@ -23,33 +23,66 @@ def should_include_change(
|
||||||
added_lines.append(line[1:])
|
added_lines.append(line[1:])
|
||||||
continue
|
continue
|
||||||
raise ValueError("Unexpected non-change line in change block.")
|
raise ValueError("Unexpected non-change line in change block.")
|
||||||
|
|
||||||
transformed_removed = [
|
transformed_removed = [
|
||||||
re.sub(search, replace, line) for line in removed_lines
|
re.sub(search, replace, line) for line in removed_lines
|
||||||
]
|
]
|
||||||
return transformed_removed == added_lines
|
if transformed_removed == added_lines:
|
||||||
|
return change_lines, False
|
||||||
|
|
||||||
|
if len(removed_lines) != len(added_lines):
|
||||||
|
return None, True
|
||||||
|
|
||||||
|
kept_lines = []
|
||||||
|
for removed, added in zip(removed_lines, added_lines):
|
||||||
|
if re.sub(search, replace, removed) == added:
|
||||||
|
kept_lines.append(f"-{removed}")
|
||||||
|
kept_lines.append(f"+{added}")
|
||||||
|
else:
|
||||||
|
kept_lines.append(f" {removed}")
|
||||||
|
|
||||||
|
if not kept_lines:
|
||||||
|
return None, True
|
||||||
|
|
||||||
|
return kept_lines, True
|
||||||
|
|
||||||
|
|
||||||
def should_include_hunk(hunk_text: str, search: str, replace: str) -> bool:
|
def filter_hunk(
|
||||||
lines = hunk_text.splitlines()
|
hunk_lines: list[str], search: str, replace: str
|
||||||
if not lines:
|
) -> tuple[list[str] | None, bool]:
|
||||||
return True
|
if not hunk_lines:
|
||||||
|
return None, False
|
||||||
|
|
||||||
change = []
|
header = hunk_lines[0]
|
||||||
for line in lines[1:]:
|
body = hunk_lines[1:]
|
||||||
|
output_body: list[str] = []
|
||||||
|
left_out = False
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(body):
|
||||||
|
line = body[i]
|
||||||
if line.startswith(("+", "-")):
|
if line.startswith(("+", "-")):
|
||||||
change.append(line)
|
block = []
|
||||||
|
while i < len(body) and body[i].startswith(("+", "-")):
|
||||||
|
block.append(body[i])
|
||||||
|
i += 1
|
||||||
|
kept_block, block_left_out = filter_change_block(
|
||||||
|
block, search, replace
|
||||||
|
)
|
||||||
|
if kept_block:
|
||||||
|
output_body.extend(kept_block)
|
||||||
|
else:
|
||||||
|
left_out = True
|
||||||
|
if block_left_out:
|
||||||
|
left_out = True
|
||||||
continue
|
continue
|
||||||
|
output_body.append(line)
|
||||||
|
i += 1
|
||||||
|
|
||||||
if change:
|
if not any(line.startswith(("+", "-")) for line in output_body):
|
||||||
if not should_include_change(change, search, replace):
|
return None, True
|
||||||
return False
|
|
||||||
change = []
|
|
||||||
|
|
||||||
if change:
|
return [header] + output_body, left_out
|
||||||
if not should_include_change(change, search, replace):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|
@ -97,11 +130,15 @@ def main() -> None:
|
||||||
|
|
||||||
kept_hunks = []
|
kept_hunks = []
|
||||||
for hunk_lines in section["hunks"]:
|
for hunk_lines in section["hunks"]:
|
||||||
hunk_text = "".join(hunk_lines)
|
filtered, hunk_left_out = filter_hunk(
|
||||||
if should_include_hunk(hunk_text, search, replace):
|
hunk_lines, search, replace
|
||||||
kept_hunks.append(hunk_lines)
|
)
|
||||||
|
if filtered:
|
||||||
|
kept_hunks.append(filtered)
|
||||||
else:
|
else:
|
||||||
left_out = True
|
left_out = True
|
||||||
|
if hunk_left_out:
|
||||||
|
left_out = True
|
||||||
|
|
||||||
if not kept_hunks:
|
if not kept_hunks:
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -128,3 +128,31 @@ setup() {
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "$(cat "$BATS_TEST_TMPDIR/diff")"
|
assert_output "$(cat "$BATS_TEST_TMPDIR/diff")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "keeps only matching line in a consecutive change block" {
|
||||||
|
cat >"$BATS_TEST_TMPDIR/old" <<-'EOF'
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
baz
|
||||||
|
EOF
|
||||||
|
sed \
|
||||||
|
-e 's/foo/foo_changed/' \
|
||||||
|
-e 's/bar/bar_changed/' \
|
||||||
|
"$BATS_TEST_TMPDIR/old" >"$BATS_TEST_TMPDIR/new"
|
||||||
|
sed 's/foo/foo_changed/' "$BATS_TEST_TMPDIR/old" \
|
||||||
|
>"$BATS_TEST_TMPDIR/new_kept"
|
||||||
|
|
||||||
|
git diff --no-index "$BATS_TEST_TMPDIR/old" "$BATS_TEST_TMPDIR/new" \
|
||||||
|
>"$BATS_TEST_TMPDIR/diff_full" || true
|
||||||
|
git diff --no-index "$BATS_TEST_TMPDIR/old" "$BATS_TEST_TMPDIR/new_kept" \
|
||||||
|
>"$BATS_TEST_TMPDIR/diff_expected" || true
|
||||||
|
|
||||||
|
run mechanicaldiff.py foo foo_changed <"$BATS_TEST_TMPDIR/diff_full"
|
||||||
|
assert_failure
|
||||||
|
expected="$(sed \
|
||||||
|
-e 's/new_kept/new/g' \
|
||||||
|
-e '/^index /d' \
|
||||||
|
"$BATS_TEST_TMPDIR/diff_expected")"
|
||||||
|
output_normalized="$(printf '%s\n' "$output" | sed -e '/^index /d')"
|
||||||
|
assert_equal "$expected" "$output_normalized"
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue