texdiff 0.2.1__tar.gz → 0.2.2__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.1/src/texdiff.egg-info → texdiff-0.2.2}/PKG-INFO +1 -1
- {texdiff-0.2.1 → texdiff-0.2.2}/pyproject.toml +1 -1
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/__init__.py +1 -1
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/align.py +8 -5
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/emit.py +52 -1
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/tables.py +20 -12
- {texdiff-0.2.1 → texdiff-0.2.2/src/texdiff.egg-info}/PKG-INFO +1 -1
- {texdiff-0.2.1 → texdiff-0.2.2}/LICENSE +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/README.md +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/setup.cfg +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/api.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/check.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/cli.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/flatten.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/newlines.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/nodes.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/oldlines.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/parse.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/preamble.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff/textdiff.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff.egg-info/SOURCES.txt +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff.egg-info/dependency_links.txt +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff.egg-info/entry_points.txt +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff.egg-info/requires.txt +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/src/texdiff.egg-info/top_level.txt +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_align.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_alignment.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_api.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_check.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_cli.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_corpus.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_emit.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_flatten.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_parse.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_preamble.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_table_head_order.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_tables.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_tables_render.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_textdiff.py +0 -0
- {texdiff-0.2.1 → texdiff-0.2.2}/tests/test_verbatim.py +0 -0
|
@@ -834,9 +834,13 @@ def _table_keyed_pair_rescue(edits: "list[Edit]", _pair) -> "list[Edit]":
|
|
|
834
834
|
by key with a LATER insert's table rows, convert the pair into a
|
|
835
835
|
Modify so the emit layer's inline row markup applies.
|
|
836
836
|
|
|
837
|
-
Row keys compare by
|
|
838
|
-
|
|
839
|
-
the
|
|
837
|
+
Row keys compare by the FULL first cell: an HDF-EOS grid
|
|
838
|
+
rename (NPP_Grid_IMG_2D -> VIIRS_Grid_IMG_2D) changes every
|
|
839
|
+
row's path prefix, and the resulting Modify would render as two
|
|
840
|
+
wholesale blocks (all rows struck, then all re-added) inside
|
|
841
|
+
one table - worse than leaving the pair as a clean whole-table
|
|
842
|
+
retire + reintroduction. Regenerated tables keep their row
|
|
843
|
+
keys; only wholesale renames are left alone.
|
|
840
844
|
"""
|
|
841
845
|
import re
|
|
842
846
|
|
|
@@ -845,8 +849,7 @@ def _table_keyed_pair_rescue(edits: "list[Edit]", _pair) -> "list[Edit]":
|
|
|
845
849
|
return set()
|
|
846
850
|
keys = set()
|
|
847
851
|
for m in re.finditer(r"^\s*([^&%\n]+?)\s*&", node.text or "", re.M):
|
|
848
|
-
|
|
849
|
-
keys.add(key.rsplit("/", 1)[-1])
|
|
852
|
+
keys.add(m.group(1).strip().replace("\\_", "_"))
|
|
850
853
|
return keys
|
|
851
854
|
|
|
852
855
|
dels = [
|
|
@@ -162,7 +162,9 @@ def render(edits: list[Edit], markup: LatexdiffMarkup = LatexdiffMarkup()) -> st
|
|
|
162
162
|
else:
|
|
163
163
|
out.append(_wrap_node(edit.old, markup, added=False))
|
|
164
164
|
out.append(_wrap_node(edit.new, markup, added=True))
|
|
165
|
-
return
|
|
165
|
+
return _collapse_repeated_hlines(
|
|
166
|
+
_normalize_endmark_colours("".join(out))
|
|
167
|
+
)
|
|
166
168
|
|
|
167
169
|
|
|
168
170
|
# inline end-marker tokens of longtable HEAD material; NOT preceded
|
|
@@ -225,6 +227,55 @@ def _normalize_endmark_colours(text: str) -> str:
|
|
|
225
227
|
return _ENDMARK_COLOR_RE.sub(_insert_reset, text)
|
|
226
228
|
|
|
227
229
|
|
|
230
|
+
# invisible-to-the-typesetter material that can sit between two
|
|
231
|
+
# \hline rules: blank lines, %DIFDELCMD-style comments and the
|
|
232
|
+
# no-op FL markers of flush-left diff regions
|
|
233
|
+
_INVISIBLE_BETWEEN_RULES = (
|
|
234
|
+
r"(?:[ \t]*%[^\n]*\n?|[ \t]*\n|"
|
|
235
|
+
r"\\DIF(?:add|del)(?:begin|end)FL\n?|\\DIF(?:add|del)(?:begin|end)\n?)*"
|
|
236
|
+
)
|
|
237
|
+
# two consecutive \hline rules separated only by invisible material
|
|
238
|
+
# (a deleted row's tail rule + the skeleton rule of the material
|
|
239
|
+
# that follows): both draw the SAME grid line - longtable stacks
|
|
240
|
+
# them with zero offset and the boundary prints twice as thick.
|
|
241
|
+
# The pair is CONSUMED and replaced by a single rule (a lookahead
|
|
242
|
+
# replacement would be a no-op: group 1 is identical to the match).
|
|
243
|
+
# Iteration in _collapse_repeated_hlines handles longer runs.
|
|
244
|
+
_REPEATED_HLINE_RE = re.compile(
|
|
245
|
+
r"\\hline" + _INVISIBLE_BETWEEN_RULES + r"[ \t]*\\hline"
|
|
246
|
+
)
|
|
247
|
+
# same-line adjacency: rules glued to one line by the row split
|
|
248
|
+
# ("\hline\hline") or separated only by spaces/tabs draw on top of
|
|
249
|
+
# each other just the same
|
|
250
|
+
_REPEATED_HLINE_INLINE_RE = re.compile(r"\\hline[ \t]*\\hline")
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _collapse_repeated_hlines(text: str) -> str:
|
|
254
|
+
"""Merge grid rules that land on top of each other.
|
|
255
|
+
|
|
256
|
+
Row-region emitters keep skeleton ``\\hline``s on both sides of
|
|
257
|
+
their material: a retired (deleted) row region ends with its
|
|
258
|
+
trailing rule while the following region's lead already carries
|
|
259
|
+
one, and blank lines / ``%DIFDELCMD`` comments / no-op ``FL``
|
|
260
|
+
markers sit between them. Two rules with only invisible
|
|
261
|
+
material between them draw the same grid line - longtable
|
|
262
|
+
typesets them stacked at zero offset, printing a border twice
|
|
263
|
+
as thick as every other rule in the table.
|
|
264
|
+
|
|
265
|
+
One rule of each such pair is dropped. Visible material
|
|
266
|
+
(content, colour declarations) between two rules keeps both -
|
|
267
|
+
they delimit a real row.
|
|
268
|
+
"""
|
|
269
|
+
if "\\hline" not in text:
|
|
270
|
+
return text
|
|
271
|
+
while True:
|
|
272
|
+
new = _REPEATED_HLINE_INLINE_RE.sub(r"\\hline", text)
|
|
273
|
+
new = _REPEATED_HLINE_RE.sub(r"\\hline", new)
|
|
274
|
+
if new == text:
|
|
275
|
+
return new
|
|
276
|
+
text = new
|
|
277
|
+
|
|
278
|
+
|
|
228
279
|
def _hoist_retired_tables(edits: list[Edit]) -> list[Edit]:
|
|
229
280
|
"""Reorder ``Insert(new table) ... Delete(old table)`` pairs.
|
|
230
281
|
|
|
@@ -355,12 +355,27 @@ def rows_pair_by_key(old_text: str, new_text: str, min_frac: float = 0.5) -> boo
|
|
|
355
355
|
generation changes type names, shapes and every attribute), so
|
|
356
356
|
word similarity collapses and the pair looks mutually
|
|
357
357
|
unrecognizable - while the logical row structure (one row per
|
|
358
|
-
variable: ``lat``, ``lon``, ``crs``, ...) is intact. When at
|
|
359
|
-
``min_frac`` of the smaller side's rows have a first cell
|
|
360
|
-
also appears as a first cell on the other side, the table is the
|
|
358
|
+
variable: ``lat``, ``lon``, ``crs``, ...) is intact. When at
|
|
359
|
+
least ``min_frac`` of the smaller side's rows have a first cell
|
|
360
|
+
that also appears as a first cell on the other side, the table is the
|
|
361
361
|
SAME table with edited cells: inline row markup (red struck cell,
|
|
362
362
|
blue replacement right after) reads far better than retiring the
|
|
363
363
|
whole table and reintroducing it blue.
|
|
364
|
+
|
|
365
|
+
The FULL key must match - a whole-prefix rename (an HDF-EOS
|
|
366
|
+
grid renamed ``NPP_Grid_IMG_2D`` -> ``VIIRS_Grid_IMG_2D``)
|
|
367
|
+
changes every row's path without making the rows unrelated, but
|
|
368
|
+
the row-level machinery (_row_key_of / _segment_ids) keys on the
|
|
369
|
+
full first cell: with near-zero full-key overlap the pairing
|
|
370
|
+
never happens and the inline path degrades to two wholesale
|
|
371
|
+
blocks (all rows struck, then all rows re-added) in one table.
|
|
372
|
+
Such near-total renames read better as one clean whole-table
|
|
373
|
+
retire and one blue reintroduction, which the caller
|
|
374
|
+
(merge_tables / render_restructured) provides - so they are
|
|
375
|
+
rejected here even though their LAST path components still
|
|
376
|
+
match. Regenerated grouped tables keep ~75% full-key overlap
|
|
377
|
+
(the attribute keys repeat per group) and stay above the gate;
|
|
378
|
+
renamed-grid tables sit at ~25% or below.
|
|
364
379
|
"""
|
|
365
380
|
lo = [
|
|
366
381
|
_first_cell(r)
|
|
@@ -377,15 +392,8 @@ def rows_pair_by_key(old_text: str, new_text: str, min_frac: float = 0.5) -> boo
|
|
|
377
392
|
# structural repeats (header rows repeated via \endhead) must not
|
|
378
393
|
# count twice per side
|
|
379
394
|
lo, ln = set(lo), set(ln)
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
# data field itself: rows also pair when their last path
|
|
383
|
-
# component matches
|
|
384
|
-
def _last(k: str) -> str:
|
|
385
|
-
return k.rsplit("/", 1)[-1] if "/" in k else k
|
|
386
|
-
lo_last, ln_last = {_last(k) for k in lo}, {_last(k) for k in ln}
|
|
387
|
-
shared = len(lo_last & ln_last)
|
|
388
|
-
return shared >= min_frac * min(len(lo_last), len(ln_last)) and shared >= 2
|
|
395
|
+
shared = len(lo & ln)
|
|
396
|
+
return shared >= min_frac * min(len(lo), len(ln)) and shared >= 2
|
|
389
397
|
|
|
390
398
|
|
|
391
399
|
_SPEC_RE = re.compile(r"\\begin\{longtable\*?\}\s*\{")
|
|
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
|