pyDiffTools 0.1.53__tar.gz → 0.1.54__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.
- {pydifftools-0.1.53/pyDiffTools.egg-info → pydifftools-0.1.54}/PKG-INFO +1 -1
- {pydifftools-0.1.53 → pydifftools-0.1.54/pyDiffTools.egg-info}/PKG-INFO +1 -1
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/line_alignment.py +50 -3
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/match_spaces.py +0 -1
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pyproject.toml +1 -1
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_line_alignment.py +184 -2
- {pydifftools-0.1.53 → pydifftools-0.1.54}/LICENSE.md +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/MANIFEST.in +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/README.rst +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/_quarto.yml +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/example.qmd +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/example.tex +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/index.qmd +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/independent.qmd +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/index.qmd +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/tasks.qmd +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/test_include.qmd +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/test_include.qmd +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pyDiffTools.egg-info/SOURCES.txt +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pyDiffTools.egg-info/dependency_links.txt +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pyDiffTools.egg-info/entry_points.txt +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pyDiffTools.egg-info/requires.txt +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pyDiffTools.egg-info/top_level.txt +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/__init__.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/bibliography.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/browser_lifecycle.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/check_numbers.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/citation_dialog.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/command_line.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/command_registry.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comment_filter_history.json +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comment_functions.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comment_migration.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comment_tags.lua +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comment_tags_margin.lua +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comment_tags_no_comments.lua +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comment_toggle.js +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comments.css +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/comments_author_colors.css +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/completions/git-mergein +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/continuous.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/copy_files.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/diff-doc.js +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/doc_contents.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/flowchart/__init__.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/flowchart/comparison.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/flowchart/dot_to_yaml.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/flowchart/graph.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/flowchart/source_jump.js +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/flowchart/svg-pan-zoom.min.js +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/flowchart/watch_graph.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/flowchart/wgrph_view.js +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/forward_search.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/git_aliases.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/git_gd.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/git_gd_history.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/git_gd_image.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/git_gd_qt.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/html_comments.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/html_uncomments.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/log_example.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/notebook/__init__.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/notebook/display.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/notebook/fast_build.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/notebook/tex_to_qmd.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/onewordify.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/onewordify_undo.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/outline.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/pdf_diff.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/rearrange_tex.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/searchacro.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/separate_comments.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/source_jump.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/split_conflict.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/unseparate_comments.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/update_check.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/wrap_sentences.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/wrapping_options.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/xml2xlsx.vbs +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/pydifftools/zotero.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/setup.cfg +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_bibliography.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_browser_lifecycle.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_check_single_use.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_command_line_help.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_comment_filters.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_comment_migration.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_continuous_shutdown.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_forward_search.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_git_gd_history.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_git_gd_image.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_git_gd_qt.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_git_mergein.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_git_pdf_diff.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_pdf_diff.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_rrng.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_source_jump.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_tex_to_qmd.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_update_check.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_wrap_check.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_wrapping.py +0 -0
- {pydifftools-0.1.53 → pydifftools-0.1.54}/tests/test_zotero.py +0 -0
|
@@ -88,7 +88,7 @@ def align_line_breaks(
|
|
|
88
88
|
):
|
|
89
89
|
"""Return changed hunks with original, linted and proposed layouts.
|
|
90
90
|
|
|
91
|
-
Align words with minimal diff, reuse
|
|
91
|
+
Align words with minimal diff, reuse equivalent source whitespace,
|
|
92
92
|
then preserve complete reference lines and enforce line linting. CPB
|
|
93
93
|
and wmatch apply the aligned layout automatically.
|
|
94
94
|
Width can be a number or a function choosing a limit after restoration.
|
|
@@ -148,6 +148,9 @@ def align_line_breaks(
|
|
|
148
148
|
margins[row] = allowed[row] and (
|
|
149
149
|
inside or (
|
|
150
150
|
margins[row] and "\t" not in indent and len(indent) < 4
|
|
151
|
+
and not (
|
|
152
|
+
row and not rows[row - 1].strip() and len(indent) >= 2
|
|
153
|
+
)
|
|
151
154
|
)
|
|
152
155
|
)
|
|
153
156
|
position += len(line)
|
|
@@ -174,7 +177,7 @@ def align_line_breaks(
|
|
|
174
177
|
if p["marker"] else "")
|
|
175
178
|
for p in prefixes
|
|
176
179
|
]
|
|
177
|
-
|
|
180
|
+
span_word = re.compile(
|
|
178
181
|
r"\$\$|\$|\\[A-Za-z]+|\\[^\s]|[A-Za-z]+|[0-9]+(?:\.[0-9]+)?|[^\s]"
|
|
179
182
|
)
|
|
180
183
|
tokens = []
|
|
@@ -186,7 +189,11 @@ def align_line_breaks(
|
|
|
186
189
|
end]
|
|
187
190
|
for left, right in zip(boundaries, boundaries[1:]):
|
|
188
191
|
in_math = region_at(equations, base + left) is not None
|
|
189
|
-
|
|
192
|
+
hidden = region_at(comments, base + left) is not None
|
|
193
|
+
# Hidden source has no rendered word boundaries. Separate
|
|
194
|
+
# punctuation there too, so layout changes do not turn
|
|
195
|
+
# "$$R_c" into unmatched "$$" and "R_c" tokens.
|
|
196
|
+
pattern = span_word if in_math or hidden else WORD
|
|
190
197
|
tokens.extend(
|
|
191
198
|
(row, match.start(), match.end())
|
|
192
199
|
for match in pattern.finditer(text, left, right)
|
|
@@ -348,6 +355,39 @@ def align_line_breaks(
|
|
|
348
355
|
whitespace = dict(gaps)
|
|
349
356
|
ending = "\r\n" if "\r\n" in before else "\n"
|
|
350
357
|
|
|
358
|
+
def equivalent_gap(number, replacement):
|
|
359
|
+
# {{{ keep rendered separators and explicit Markdown hard breaks
|
|
360
|
+
raw = gaps[number]
|
|
361
|
+
left = start + tokens[number][1]
|
|
362
|
+
right = start + tokens[number + 1][1]
|
|
363
|
+
region = region_at(current_comments, left)
|
|
364
|
+
if region is not None and right < region[1]:
|
|
365
|
+
return True
|
|
366
|
+
region = region_at(current_equations, left)
|
|
367
|
+
if region is not None and right < region[1]:
|
|
368
|
+
# Display delimiters can sit on their own source lines.
|
|
369
|
+
# All other math gaps obey the same rule as prose; no
|
|
370
|
+
# knowledge of TeX commands or text macros is needed.
|
|
371
|
+
if current[region[0]:region[0] + 2] == "$$" and (
|
|
372
|
+
tokens[number][1] + start == region[0]
|
|
373
|
+
or tokens[number + 1][2] + start == region[1]
|
|
374
|
+
):
|
|
375
|
+
return True
|
|
376
|
+
return bool(raw) == bool(replacement)
|
|
377
|
+
# Collapsing a whitespace run retains one separator. It cannot
|
|
378
|
+
# create a separator from an empty gap or remove the last one.
|
|
379
|
+
# Line margins are handled separately, with structural margins
|
|
380
|
+
# excluded. Two spaces before a newline are a Markdown hard
|
|
381
|
+
# break, and a newline after a backslash is explicit as well.
|
|
382
|
+
if any(re.search(r" {2,}\r?\n", gap)
|
|
383
|
+
for gap in (raw, replacement)) or (
|
|
384
|
+
before[tokens[number][2] - 1:tokens[number][2]] == "\\"
|
|
385
|
+
and ("\n" in raw or "\n" in replacement)
|
|
386
|
+
):
|
|
387
|
+
return raw == replacement
|
|
388
|
+
return bool(raw) == bool(replacement)
|
|
389
|
+
# }}}
|
|
390
|
+
|
|
351
391
|
# {{{ restore presentation indentation at matching line starts
|
|
352
392
|
old_first = {}
|
|
353
393
|
for number, (row, _, _) in enumerate(old_tokens):
|
|
@@ -430,6 +470,8 @@ def align_line_breaks(
|
|
|
430
470
|
old_number = candidate
|
|
431
471
|
if old_number in old_gaps:
|
|
432
472
|
raw = old_gaps[old_number]
|
|
473
|
+
if not equivalent_gap(number, raw):
|
|
474
|
+
continue
|
|
433
475
|
region = region_at(regions, start + tokens[number][1])
|
|
434
476
|
inside_region = (
|
|
435
477
|
region is not None
|
|
@@ -494,6 +536,11 @@ def align_line_breaks(
|
|
|
494
536
|
elif "\n" in proposed[number]:
|
|
495
537
|
proposed[number] = " "
|
|
496
538
|
proposed_rows = render(proposed).splitlines()
|
|
539
|
+
if any(
|
|
540
|
+
not equivalent_gap(number, proposed[number])
|
|
541
|
+
for number in needed
|
|
542
|
+
):
|
|
543
|
+
continue
|
|
497
544
|
if old_line not in {line.rstrip() for line in proposed_rows}:
|
|
498
545
|
continue
|
|
499
546
|
if any(
|
|
@@ -92,7 +92,6 @@ def match_text(
|
|
|
92
92
|
trailing_dependent_phrase=DEFAULT_TRAILING_DEPENDENT_PHRASE,
|
|
93
93
|
):
|
|
94
94
|
"""Align reference lines and wrap only overflowing edited prose."""
|
|
95
|
-
text2 = text2.replace("\u00a0", " ").replace("\u2004", " ")
|
|
96
95
|
# {{{ choose the nearby reference width before any line linting
|
|
97
96
|
reference_lines = classify_lines(text1, filetype)
|
|
98
97
|
prose_rows = [
|
|
@@ -47,6 +47,129 @@ def test_partial_matching_lines_restore_whitespace_first(tmp_path):
|
|
|
47
47
|
assert new.read_text() == expected
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
@pytest.mark.parametrize("reference,current", [
|
|
51
|
+
(
|
|
52
|
+
r"the TEMPO-SO~4~ probe ($32.9;\text{kJ}/\text{mol}$"
|
|
53
|
+
"(@fig:DodecaTSO4TempCycle, blue),\nwhich\n",
|
|
54
|
+
r"the TEMPO-SO~4~ probe ($32.9;\text{kJ}/\text{mol}$"
|
|
55
|
+
" (@fig:DodecaTSO4TempCycle, blue),\nwhich\n",
|
|
56
|
+
),
|
|
57
|
+
(
|
|
58
|
+
r"the TEMPO-SO~4~ probe inside small RMs dispersed in"
|
|
59
|
+
"\ndodecane ($32.9;\\text{kJ}/\\text{mol}$ : "
|
|
60
|
+
"@fig:DodecaTSO4TempCycle, blue),\nwhich\n",
|
|
61
|
+
r"the TEMPO-SO~4~ probe inside small RMs dispersed in"
|
|
62
|
+
"\ndodecane ($32.9;\\text{kJ}/\\text{mol}$: "
|
|
63
|
+
"@fig:DodecaTSO4TempCycle, blue),\nwhich\n",
|
|
64
|
+
),
|
|
65
|
+
("First $x$ (reference).\n", "First $x$(reference).\n"),
|
|
66
|
+
("First $x$: reference.\n", "First $x$ : reference.\n"),
|
|
67
|
+
("First words continue here.\n", "First words \ncontinue here.\n"),
|
|
68
|
+
("A long unchanged introductory line stays here.\n"
|
|
69
|
+
"First words\\\ncontinue here.\n",
|
|
70
|
+
"A long unchanged introductory line stays here.\n"
|
|
71
|
+
"First words\\ continue here.\n"),
|
|
72
|
+
("Keep ordinary spaces.\n", "Keep\u00a0ordinary\u2004spaces.\n"),
|
|
73
|
+
(r"Use $\text{a,b}$ here." + "\n",
|
|
74
|
+
r"Use $\text{a, b}$ here." + "\n"),
|
|
75
|
+
(r"Use $\text{a, b}$ here." + "\n",
|
|
76
|
+
r"Use $\text{a,b}$ here." + "\n"),
|
|
77
|
+
(r"Use $\text{a,{b,c}}$ here." + "\n",
|
|
78
|
+
r"Use $\text{a, {b, c}}$ here." + "\n"),
|
|
79
|
+
(r"Use $\text{a \text{b} c,d}$ here." + "\n",
|
|
80
|
+
r"Use $\text{a \text{b} c, d}$ here." + "\n"),
|
|
81
|
+
(r"Use $\alpha{}b$ here." + "\n",
|
|
82
|
+
r"Use $\alpha b$ here." + "\n"),
|
|
83
|
+
(r"Use $\custom{a,b}$ here." + "\n",
|
|
84
|
+
r"Use $\custom{a, b}$ here." + "\n"),
|
|
85
|
+
("Use $<!-- hidden words -->$ here.\n",
|
|
86
|
+
"Use $<!--hidden words-->$ here.\n"),
|
|
87
|
+
])
|
|
88
|
+
def test_rendered_spacing_survives_shared_alignment_and_wmatch(
|
|
89
|
+
tmp_path, reference, current,
|
|
90
|
+
):
|
|
91
|
+
for result in align_line_breaks(reference, current, width=1000):
|
|
92
|
+
assert result["aligned"] == result["before"]
|
|
93
|
+
old, new = tmp_path / "old.md", tmp_path / "new.md"
|
|
94
|
+
old.write_text(reference)
|
|
95
|
+
new.write_text(current)
|
|
96
|
+
run([str(old), str(new)], wrapnumber=1000)
|
|
97
|
+
assert new.read_text() == current
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_removed_hard_break_is_not_restored_by_alignment(tmp_path):
|
|
101
|
+
reference = "First words \ncontinue here.\n"
|
|
102
|
+
current = "First words continue here.\n"
|
|
103
|
+
(result,) = align_line_breaks(reference, current)
|
|
104
|
+
assert " \n" not in result["aligned"]
|
|
105
|
+
old, new = tmp_path / "old.md", tmp_path / "new.md"
|
|
106
|
+
old.write_text(reference)
|
|
107
|
+
new.write_text(current)
|
|
108
|
+
run([str(old), str(new)])
|
|
109
|
+
assert " \n" not in new.read_text()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@pytest.mark.parametrize("context", ["{}", "Use ${}$ here."])
|
|
113
|
+
@pytest.mark.parametrize("before,after", [
|
|
114
|
+
("alpha,beta", "alpha, beta"),
|
|
115
|
+
("alpha, beta", "alpha,beta"),
|
|
116
|
+
("alpha(beta)", "alpha (beta)"),
|
|
117
|
+
("alpha (beta)", "alpha(beta)"),
|
|
118
|
+
("alpha:beta", "alpha :beta"),
|
|
119
|
+
("alpha :beta", "alpha:beta"),
|
|
120
|
+
])
|
|
121
|
+
def test_alignment_preserves_last_space_everywhere(
|
|
122
|
+
tmp_path, context, before, after,
|
|
123
|
+
):
|
|
124
|
+
reference = context.format(before) + "\n"
|
|
125
|
+
current = context.format(after) + "\n"
|
|
126
|
+
for result in align_line_breaks(reference, current):
|
|
127
|
+
assert result["aligned"] == result["before"]
|
|
128
|
+
old, new = tmp_path / "old.md", tmp_path / "new.md"
|
|
129
|
+
old.write_text(reference)
|
|
130
|
+
new.write_text(current)
|
|
131
|
+
run([str(old), str(new)])
|
|
132
|
+
assert new.read_text() == current
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_extra_spaces_and_presentation_margins_can_be_cleaned(tmp_path):
|
|
136
|
+
reference = "Keep one separator here.\n"
|
|
137
|
+
current = " Keep one \t separator here.\n"
|
|
138
|
+
(result,) = align_line_breaks(reference, current, width=79)
|
|
139
|
+
assert result["aligned"] == reference
|
|
140
|
+
old, new = tmp_path / "old.md", tmp_path / "new.md"
|
|
141
|
+
old.write_text(reference)
|
|
142
|
+
new.write_text(current)
|
|
143
|
+
run([str(old), str(new)])
|
|
144
|
+
assert new.read_text() == reference
|
|
145
|
+
new.write_text(reference.rstrip("\n") + " \n")
|
|
146
|
+
autofix_markdown_file(new, wrapnumber=79)
|
|
147
|
+
assert new.read_text() == reference
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_cpb_preserves_rendered_spacing_while_restoring_source_breaks(
|
|
151
|
+
tmp_path,
|
|
152
|
+
):
|
|
153
|
+
import subprocess
|
|
154
|
+
|
|
155
|
+
reference = (
|
|
156
|
+
"A probe inside small RMs\ndispersed in dodecane "
|
|
157
|
+
"($32.9;\\text{kJ}/\\text{mol}$ : @fig:cycle, blue),\nwhich\n"
|
|
158
|
+
)
|
|
159
|
+
current = reference.replace("RMs\ndispersed", "RMs dispersed").replace(
|
|
160
|
+
"$ :", "$:"
|
|
161
|
+
)
|
|
162
|
+
path = tmp_path / "source.md"
|
|
163
|
+
subprocess.run(["git", "init", str(tmp_path)], check=True,
|
|
164
|
+
capture_output=True)
|
|
165
|
+
path.write_text(reference)
|
|
166
|
+
subprocess.run(["git", "-C", str(tmp_path), "add", "source.md"],
|
|
167
|
+
check=True, capture_output=True)
|
|
168
|
+
path.write_text(current)
|
|
169
|
+
autofix_markdown_file(path, wrapnumber=1000, git_index=True)
|
|
170
|
+
assert path.read_text() == reference.replace("$ :", "$:")
|
|
171
|
+
|
|
172
|
+
|
|
50
173
|
@pytest.mark.parametrize("old_prefix,new_prefix", [
|
|
51
174
|
("", " "), (" ", ""), (" ", " "),
|
|
52
175
|
])
|
|
@@ -80,6 +203,10 @@ def test_leading_indentation_edits_do_not_overlap_whitespace_restoration():
|
|
|
80
203
|
("> Quote.\n", " > Quote.\n"),
|
|
81
204
|
("> First.\n continuation.\n", "> First.\n continuation.\n"),
|
|
82
205
|
("```\n Code.\n```\n", "```\n Code.\n```\n"),
|
|
206
|
+
("Introduction.\n\n Indented paragraph.\n",
|
|
207
|
+
"Introduction.\n\n Indented paragraph.\n"),
|
|
208
|
+
("Introduction.\n\n Indented paragraph.\n",
|
|
209
|
+
"Introduction.\n\n Indented paragraph.\n"),
|
|
83
210
|
])
|
|
84
211
|
def test_structural_indentation_is_preserved(reference, current):
|
|
85
212
|
assert all(
|
|
@@ -177,6 +304,63 @@ def test_comment_alignment_preserves_reference_whitespace():
|
|
|
177
304
|
assert restored == reference
|
|
178
305
|
|
|
179
306
|
|
|
307
|
+
@pytest.mark.parametrize("ending", ["\n", "\r\n"])
|
|
308
|
+
@pytest.mark.parametrize("body", [
|
|
309
|
+
r"$$R_c \approx (100\,\text{nm·K})/\Delta T$$",
|
|
310
|
+
r"$$R_c \approx 100/28 \approx 3.6\,\text{nm}$$",
|
|
311
|
+
"Attached(punctuation),without spaces.",
|
|
312
|
+
])
|
|
313
|
+
def test_hidden_source_layout_matches_across_attached_punctuation(
|
|
314
|
+
tmp_path, body, ending,
|
|
315
|
+
):
|
|
316
|
+
import subprocess
|
|
317
|
+
|
|
318
|
+
reference = (
|
|
319
|
+
"Visible prose.\n<!--\nRS: Calculation:\n" + body + "\n-->\n"
|
|
320
|
+
"Visible $x$ (reference): preserve this space.\n"
|
|
321
|
+
).replace("\n", ending)
|
|
322
|
+
changed_body = body.replace("$$", "$$\n", 1)
|
|
323
|
+
if body.endswith("$$"):
|
|
324
|
+
changed_body = changed_body[:-2] + "\n$$"
|
|
325
|
+
else:
|
|
326
|
+
changed_body = body.replace("(", " ( ").replace(
|
|
327
|
+
"),", " ) ,\n"
|
|
328
|
+
)
|
|
329
|
+
current = reference.replace(body, changed_body.replace("\n", ending))
|
|
330
|
+
restored = current
|
|
331
|
+
for result in reversed(align_line_breaks(reference, current, width=79)):
|
|
332
|
+
restored = (
|
|
333
|
+
restored[:result["start"]] + result["aligned"]
|
|
334
|
+
+ restored[result["stop"]:]
|
|
335
|
+
)
|
|
336
|
+
assert restored == reference
|
|
337
|
+
old, new = tmp_path / "old.md", tmp_path / "new.md"
|
|
338
|
+
old.write_bytes(reference.encode())
|
|
339
|
+
new.write_bytes(current.encode())
|
|
340
|
+
run([str(old), str(new)])
|
|
341
|
+
# wmatch reads text with universal newline handling.
|
|
342
|
+
assert new.read_text() == reference.replace(ending, "\n")
|
|
343
|
+
subprocess.run(["git", "init", str(tmp_path)], check=True,
|
|
344
|
+
capture_output=True)
|
|
345
|
+
new.write_bytes(reference.encode())
|
|
346
|
+
subprocess.run(["git", "-C", str(tmp_path), "add", "new.md"],
|
|
347
|
+
check=True, capture_output=True)
|
|
348
|
+
subprocess.run(["git", "-C", str(tmp_path), "config", "user.name",
|
|
349
|
+
"Test"], check=True)
|
|
350
|
+
subprocess.run(["git", "-C", str(tmp_path), "config", "user.email",
|
|
351
|
+
"test@example.com"], check=True)
|
|
352
|
+
subprocess.run(["git", "-C", str(tmp_path), "commit", "-m", "Base"],
|
|
353
|
+
check=True, capture_output=True)
|
|
354
|
+
subprocess.run(["git", "-C", str(tmp_path), "tag", "jf_last"],
|
|
355
|
+
check=True)
|
|
356
|
+
new.write_bytes(current.encode())
|
|
357
|
+
autofix_markdown_file(new, wrapnumber=79, git_ref="jf_last")
|
|
358
|
+
assert new.read_bytes() == reference.encode()
|
|
359
|
+
assert not autofix_markdown_file(
|
|
360
|
+
new, wrapnumber=79, git_ref="jf_last",
|
|
361
|
+
)["fixes"]
|
|
362
|
+
|
|
363
|
+
|
|
180
364
|
def test_literal_comment_delimiters_remain_opaque():
|
|
181
365
|
delimiter = "`"
|
|
182
366
|
reference = f"Use {delimiter}<!-- hidden words -->{delimiter} here.\n"
|
|
@@ -203,8 +387,6 @@ def test_literal_comment_delimiters_remain_opaque():
|
|
|
203
387
|
"$$\n" + r"r(w_0) = \begin{cases}" + "\n"
|
|
204
388
|
+ r"m w_0 + \delta & w_0 < 20 \\[8pt]" + "\n"
|
|
205
389
|
+ r"c & w_0 \geq 20\end{cases}" + "\n$$\n"),
|
|
206
|
-
("Use $<!-- hidden words -->$ here.\n",
|
|
207
|
-
"Use $<!--hidden words-->$ here.\n"),
|
|
208
390
|
])
|
|
209
391
|
def test_math_layout_restores_baseline_without_prose_lint(reference, current):
|
|
210
392
|
for result in reversed(align_line_breaks(reference, current, width=79)):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/__version__.txt
RENAMED
|
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
|
{pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/.jupyter_cache/global.db
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg
RENAMED
|
File without changes
|
{pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/independent.qmd
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/test_include.qmd
RENAMED
|
File without changes
|
{pydifftools-0.1.53 → pydifftools-0.1.54}/example_notebook/project1/subproject1/tryforerror.qmd
RENAMED
|
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
|
|
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
|
|
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
|