texdiff 0.2.3__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {texdiff-0.2.3/src/texdiff.egg-info → texdiff-0.2.4}/PKG-INFO +1 -1
- {texdiff-0.2.3 → texdiff-0.2.4}/pyproject.toml +1 -1
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/__init__.py +1 -1
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/emit.py +15 -2
- {texdiff-0.2.3 → texdiff-0.2.4/src/texdiff.egg-info}/PKG-INFO +1 -1
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_tables_render.py +58 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/LICENSE +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/README.md +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/setup.cfg +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/align.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/api.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/check.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/cli.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/flatten.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/newlines.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/nodes.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/oldlines.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/parse.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/preamble.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/tables.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff/textdiff.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff.egg-info/SOURCES.txt +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff.egg-info/dependency_links.txt +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff.egg-info/entry_points.txt +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff.egg-info/requires.txt +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/src/texdiff.egg-info/top_level.txt +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_align.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_alignment.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_api.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_check.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_cli.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_corpus.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_emit.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_flatten.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_parse.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_preamble.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_table_head_order.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_tables.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_textdiff.py +0 -0
- {texdiff-0.2.3 → texdiff-0.2.4}/tests/test_verbatim.py +0 -0
|
@@ -1556,7 +1556,13 @@ def _is_safe_inline(text: str) -> bool:
|
|
|
1556
1556
|
return False
|
|
1557
1557
|
if "\n" in text:
|
|
1558
1558
|
return False
|
|
1559
|
-
|
|
1559
|
+
# decoration macros (\\emph, \\textbf, ...) with pure-text
|
|
1560
|
+
# arguments are LR-safe inside \\DIFdel/\\DIFadd - font commands
|
|
1561
|
+
# survive \\sout/\\uwave. Mask them before the macro-argument
|
|
1562
|
+
# probe or cells like ``\\emph{valid\\_min} to \\emph{valid\\_max}``
|
|
1563
|
+
# degrade to the colour-only fallback: red but never struck.
|
|
1564
|
+
probe = _SAFE_DECOR_RE.sub(lambda m: m.group(2), text)
|
|
1565
|
+
if _ARG_MACRO_RE.search(probe) or _ARG_MACRO_BR_RE.search(probe):
|
|
1560
1566
|
return False
|
|
1561
1567
|
if _LIST_ITEM_RE.search(text):
|
|
1562
1568
|
# \item / \par inside a strikeout/wave is LR-mode illegal
|
|
@@ -2239,6 +2245,11 @@ def _escape_cell_pair(old_cell: str, new_cell: str) -> str:
|
|
|
2239
2245
|
if _is_safe_inline(new_cell):
|
|
2240
2246
|
return f"\\DIFadd{{{new_cell}}}"
|
|
2241
2247
|
return f"\\DIFaddbegin{{}} {new_cell} \\DIFaddend{{}}"
|
|
2248
|
+
if not new_cell:
|
|
2249
|
+
# text -> empty: strike the old cell (blue adds nothing)
|
|
2250
|
+
if _is_safe_inline(old_cell):
|
|
2251
|
+
return f"\\DIFdel{{{old_cell}}}"
|
|
2252
|
+
return f"\\DIFdelbegin{{}} {old_cell} \\DIFdelend{{}}"
|
|
2242
2253
|
# underscore-escape-only difference: the OLD ADS generator emits
|
|
2243
2254
|
# raw ``_`` in variable paths while the NEW one escapes it as
|
|
2244
2255
|
# ``\_`` - both render identically in LaTeX. A cell pair that
|
|
@@ -2459,7 +2470,9 @@ def _merge_keyed_rows(
|
|
|
2459
2470
|
parts: list[str] = []
|
|
2460
2471
|
for oc, nc in zip(old_cells, new_cells):
|
|
2461
2472
|
oc_s, nc_s = oc.strip(), nc.strip()
|
|
2462
|
-
if oc_s == nc_s
|
|
2473
|
+
if oc_s == nc_s:
|
|
2474
|
+
parts.append(oc)
|
|
2475
|
+
elif not nc_s and not oc_s:
|
|
2463
2476
|
parts.append(oc)
|
|
2464
2477
|
else:
|
|
2465
2478
|
parts.append(_escape_cell_pair(oc_s, nc_s))
|
|
@@ -1018,3 +1018,61 @@ class TestGroupedPairingRegressions:
|
|
|
1018
1018
|
assert name in out[nearest : nearest + 12], (
|
|
1019
1019
|
f"{unit} merged into the wrong group"
|
|
1020
1020
|
)
|
|
1021
|
+
|
|
1022
|
+
def test_decorated_macro_cell_strikes_not_just_colours(self):
|
|
1023
|
+
r"""Range-cell case: \emph{..} cells must strike, not just colour.
|
|
1024
|
+
|
|
1025
|
+
A changed cell containing only decoration macros with
|
|
1026
|
+
pure-text arguments (``\emph{valid\_min} to
|
|
1027
|
+
\emph{valid\_max}``) is LR-safe inside \DIFdel/\DIFadd:
|
|
1028
|
+
font commands survive \sout/\uwave. It must render with the
|
|
1029
|
+
inline strike markup, not degrade to the colour-switch-only
|
|
1030
|
+
fallback (\DIFdelbegin..\DIFdelend), which paints the old
|
|
1031
|
+
text red without striking it.
|
|
1032
|
+
"""
|
|
1033
|
+
old_src = (
|
|
1034
|
+
"\\documentclass{article}\\begin{document}\n"
|
|
1035
|
+
"\\begin{longtable}{ll}\n\\caption{vars}\\\\\n"
|
|
1036
|
+
"\\rowcolor{lightcyan} \\textbf{lat} & Latitude & float & "
|
|
1037
|
+
"\\emph{valid\\_min} to \\emph{valid\\_max} & d1\\\\\n"
|
|
1038
|
+
"\\end{longtable}\\end{document}\n"
|
|
1039
|
+
)
|
|
1040
|
+
new_src = old_src.replace(
|
|
1041
|
+
"\\emph{valid\\_min} to \\emph{valid\\_max} & d1",
|
|
1042
|
+
"defined by \\emph{valid\\_range} & lat",
|
|
1043
|
+
)
|
|
1044
|
+
out = diff_documents(old_src, new_src, inject_preamble=False).marked_up
|
|
1045
|
+
# the old range cell is STRUCK inside \DIFdel{..}, not merely
|
|
1046
|
+
# coloured by the block fallback
|
|
1047
|
+
assert "\\DIFdel{\\emph{valid\\_min} to \\emph{valid\\_max}}" in out
|
|
1048
|
+
# no colour-only degradation for the pair
|
|
1049
|
+
assert "\\DIFdelbegin{} \\emph{valid" not in out
|
|
1050
|
+
# new side waves its markup too
|
|
1051
|
+
assert "\\DIFadd{defined by \\emph{valid\\_range}}" in out
|
|
1052
|
+
|
|
1053
|
+
def test_text_to_empty_cell_change_is_marked(self):
|
|
1054
|
+
r"""Text->empty cell change must strike the old cell.
|
|
1055
|
+
|
|
1056
|
+
When a cell's content is removed entirely (the regenerated
|
|
1057
|
+
spec leaves the Range column blank), the per-cell merge used
|
|
1058
|
+
to emit the OLD cell verbatim with no markup at all: the
|
|
1059
|
+
retired value silently appeared as unchanged text. It must
|
|
1060
|
+
render struck red (and its counterpart, empty->text, wavy
|
|
1061
|
+
blue).
|
|
1062
|
+
"""
|
|
1063
|
+
old_src = (
|
|
1064
|
+
"\\documentclass{article}\\begin{document}\n"
|
|
1065
|
+
"\\begin{longtable}{lll}\n"
|
|
1066
|
+
"z0 & 0 & 0 \\\\\n"
|
|
1067
|
+
"z1 & 1 & 1 \\\\\n"
|
|
1068
|
+
"\\rowcolor{lightcyan} \\textbf{day} & Date of Day & "
|
|
1069
|
+
"\\emph{valid\\_min} to \\emph{valid\\_max} \\\\\n"
|
|
1070
|
+
"w & 5 & 6 \\\\\n"
|
|
1071
|
+
"\\end{longtable}\\end{document}\n"
|
|
1072
|
+
)
|
|
1073
|
+
new_src = old_src.replace(
|
|
1074
|
+
"\\emph{valid\\_min} to \\emph{valid\\_max} \\\\",
|
|
1075
|
+
" \\\\",
|
|
1076
|
+
)
|
|
1077
|
+
out = diff_documents(old_src, new_src, inject_preamble=False).marked_up
|
|
1078
|
+
assert "\\DIFdel{\\emph{valid\\_min} to \\emph{valid\\_max}}" in out
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|