pyDiffTools 0.1.37__tar.gz → 0.1.39__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.37/pyDiffTools.egg-info → pydifftools-0.1.39}/PKG-INFO +1 -1
- {pydifftools-0.1.37 → pydifftools-0.1.39/pyDiffTools.egg-info}/PKG-INFO +1 -1
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/comment_migration.py +11 -7
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/wrap_sentences.py +63 -38
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pyproject.toml +1 -1
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_comment_migration.py +11 -2
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_wrap_check.py +55 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/LICENSE.md +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/MANIFEST.in +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/README.rst +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/_quarto.yml +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/example.qmd +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/example.tex +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/index.qmd +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/independent.qmd +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/index.qmd +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/tasks.qmd +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/test_include.qmd +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/test_include.qmd +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pyDiffTools.egg-info/SOURCES.txt +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pyDiffTools.egg-info/dependency_links.txt +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pyDiffTools.egg-info/entry_points.txt +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pyDiffTools.egg-info/requires.txt +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pyDiffTools.egg-info/top_level.txt +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/__init__.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/bibliography.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/browser_lifecycle.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/check_numbers.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/citation_dialog.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/command_line.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/command_registry.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/comment_functions.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/comment_tags.lua +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/comment_tags_margin.lua +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/comment_tags_no_comments.lua +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/comment_toggle.js +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/comments.css +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/continuous.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/copy_files.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/diff-doc.js +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/doc_contents.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/flowchart/__init__.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/flowchart/comparison.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/flowchart/dot_to_yaml.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/flowchart/graph.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/flowchart/svg-pan-zoom.min.js +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/flowchart/watch_graph.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/flowchart/wgrph_view.js +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/forward_search.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/git_gd.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/git_gd_history.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/git_gd_image.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/git_gd_qt.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/html_comments.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/html_uncomments.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/log_example.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/match_spaces.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/notebook/__init__.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/notebook/display.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/notebook/fast_build.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/notebook/tex_to_qmd.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/onewordify.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/onewordify_undo.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/outline.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/rearrange_tex.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/searchacro.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/separate_comments.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/split_conflict.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/unseparate_comments.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/update_check.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/xml2xlsx.vbs +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/pydifftools/zotero.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/setup.cfg +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_bibliography.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_browser_lifecycle.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_check_single_use.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_command_line_help.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_continuous_shutdown.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_forward_search.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_git_gd_history.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_git_gd_image.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_git_gd_qt.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_rrng.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_tex_to_qmd.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_update_check.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_wrapping.py +0 -0
- {pydifftools-0.1.37 → pydifftools-0.1.39}/tests/test_zotero.py +0 -0
|
@@ -78,7 +78,7 @@ def _most_distant_hue(colors):
|
|
|
78
78
|
return (start + gap_size / 2) % 360
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
def _migration_dialog(
|
|
81
|
+
def _migration_dialog(filename, colors, legacy):
|
|
82
82
|
"""Ask Qt for all migrations and return decisions without editing files."""
|
|
83
83
|
script = r"""
|
|
84
84
|
import colorsys
|
|
@@ -95,6 +95,8 @@ from PySide6.QtWidgets import (
|
|
|
95
95
|
)
|
|
96
96
|
|
|
97
97
|
payload = json.loads(sys.argv[1])
|
|
98
|
+
with open(sys.argv[2], encoding="utf-8", newline="") as fp:
|
|
99
|
+
text = fp.read()
|
|
98
100
|
colors = payload["colors"]
|
|
99
101
|
app = QApplication(sys.argv[:1])
|
|
100
102
|
result = {"accepted": True, "replacements": {}, "colors": {}}
|
|
@@ -201,9 +203,9 @@ legacy = payload["legacy"]
|
|
|
201
203
|
if legacy:
|
|
202
204
|
initials = ask_legacy_initials()
|
|
203
205
|
legacy_occurrences = len(re.findall(
|
|
204
|
-
r"</?comment(?:-(?:left|right))?>",
|
|
206
|
+
r"</?comment(?:-(?:left|right))?>", text, re.I
|
|
205
207
|
)) + len(re.findall(
|
|
206
|
-
r"\.comment-(?:left|right)(?=[\s}])",
|
|
208
|
+
r"\.comment-(?:left|right)(?=[\s}])", text, re.I
|
|
207
209
|
))
|
|
208
210
|
if initials is None:
|
|
209
211
|
result["accepted"] = False
|
|
@@ -222,12 +224,12 @@ if legacy:
|
|
|
222
224
|
if result["accepted"]:
|
|
223
225
|
authors = sorted(set(
|
|
224
226
|
initials.upper() for initials in re.findall(
|
|
225
|
-
r"</?([A-Za-z]{2})com(?:-(?:left|right))?>",
|
|
227
|
+
r"</?([A-Za-z]{2})com(?:-(?:left|right))?>", text, re.I
|
|
226
228
|
)
|
|
227
229
|
) | set(
|
|
228
230
|
initials.upper() for initials in re.findall(
|
|
229
231
|
r"\.([A-Za-z]{2})com(?:-(?:left|right))?(?=[\s}])",
|
|
230
|
-
|
|
232
|
+
text, re.I
|
|
231
233
|
)
|
|
232
234
|
))
|
|
233
235
|
if result["replacements"].get("legacy"):
|
|
@@ -279,8 +281,10 @@ if result["accepted"]:
|
|
|
279
281
|
print(json.dumps(result))
|
|
280
282
|
"""
|
|
281
283
|
completed = subprocess.run(
|
|
284
|
+
# the dialog reads the document from its file, since the text of a
|
|
285
|
+
# large document exceeds the operating system's argument limit
|
|
282
286
|
[sys.executable, "-c", textwrap.dedent(script),
|
|
283
|
-
json.dumps({"
|
|
287
|
+
json.dumps({"colors": colors, "legacy": legacy}), filename],
|
|
284
288
|
capture_output=True, text=True,
|
|
285
289
|
)
|
|
286
290
|
if completed.returncode:
|
|
@@ -319,7 +323,7 @@ def prepare_comment_source(filename):
|
|
|
319
323
|
}
|
|
320
324
|
if not has_legacy and authors.issubset(colors):
|
|
321
325
|
return original
|
|
322
|
-
decisions = _migration_dialog(
|
|
326
|
+
decisions = _migration_dialog(filename, colors, has_legacy)
|
|
323
327
|
if not decisions.get("accepted"):
|
|
324
328
|
raise RuntimeError("cpb comment migration was canceled")
|
|
325
329
|
updated = original
|
|
@@ -942,7 +942,9 @@ def _iter_classified_spans(text, filetype, line_start=1):
|
|
|
942
942
|
leaf prose blocks -- both just need the same protected-region
|
|
943
943
|
exclusions wr itself uses.
|
|
944
944
|
"""
|
|
945
|
-
|
|
945
|
+
# normalizing math can add lines (e.g. splitting "$${#eq:x}"), which
|
|
946
|
+
# would shift every reported line number after it
|
|
947
|
+
classified = classify_lines(text, filetype)
|
|
946
948
|
line = line_start
|
|
947
949
|
for wrappable, group in itertools.groupby(classified, key=lambda x: x[0]):
|
|
948
950
|
content = "".join(l for _, l in group)
|
|
@@ -1122,19 +1124,24 @@ def apply_markdown_issue_fix(content, line_number, message):
|
|
|
1122
1124
|
prefix = re.match(r"^[ \t]*", old_line).group()
|
|
1123
1125
|
# }}}
|
|
1124
1126
|
if message.startswith("line too long:"):
|
|
1125
|
-
match = re.search(r"before '(
|
|
1127
|
+
match = re.search(r"after '(.+?)' \(before '(.+?)'\); move", message)
|
|
1126
1128
|
if match is None:
|
|
1127
1129
|
raise ValueError(
|
|
1128
1130
|
f"Cannot find the suggested word in {message!r}"
|
|
1129
1131
|
)
|
|
1130
|
-
word
|
|
1131
|
-
|
|
1132
|
+
# split at the suggested word that follows wr's break word, since the
|
|
1133
|
+
# same word can appear earlier on the line (e.g. "for ... ($3x$ for")
|
|
1134
|
+
position = re.search(
|
|
1135
|
+
r"(?<!\S)" + re.escape(match.group(1)) + r"[ \t]+("
|
|
1136
|
+
+ re.escape(match.group(2)) + r")(?!\S)",
|
|
1137
|
+
old_line,
|
|
1138
|
+
)
|
|
1132
1139
|
if position is None:
|
|
1133
1140
|
raise ValueError(
|
|
1134
|
-
f"Cannot find {match.group(1)!r} on
|
|
1135
|
-
f"{line_number}"
|
|
1141
|
+
f"Cannot find {match.group(2)!r} after {match.group(1)!r} on "
|
|
1142
|
+
f"Markdown line {line_number}"
|
|
1136
1143
|
)
|
|
1137
|
-
split_at = position.start()
|
|
1144
|
+
split_at = position.start(1)
|
|
1138
1145
|
first = old_line[:split_at].rstrip()
|
|
1139
1146
|
second = old_line[split_at:].lstrip(" \t")
|
|
1140
1147
|
reason = (
|
|
@@ -1157,9 +1164,22 @@ def apply_markdown_issue_fix(content, line_number, message):
|
|
|
1157
1164
|
else:
|
|
1158
1165
|
raise ValueError(f"No automatic fix is available for {message!r}")
|
|
1159
1166
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1167
|
+
if not first.strip():
|
|
1168
|
+
# a break here would insert a blank line, i.e. a paragraph break
|
|
1169
|
+
raise ValueError(
|
|
1170
|
+
f"Automatic fix would leave an empty line at {line_number}"
|
|
1171
|
+
)
|
|
1172
|
+
if second.strip():
|
|
1173
|
+
lines[index] = first + ending + prefix + second + ending
|
|
1174
|
+
after = first + "\n" + prefix + second
|
|
1175
|
+
else:
|
|
1176
|
+
# only trailing whitespace followed the break, so drop it rather
|
|
1177
|
+
# than adding a blank line
|
|
1178
|
+
lines[index] = first + ending
|
|
1179
|
+
after = first
|
|
1180
|
+
reason = (
|
|
1181
|
+
"A sentence ended with a trailing space. I removed the space."
|
|
1182
|
+
)
|
|
1163
1183
|
return "".join(lines), old_line, after, reason
|
|
1164
1184
|
|
|
1165
1185
|
|
|
@@ -1168,39 +1188,44 @@ def autofix_markdown_file(filename, wrapnumber=55, punctuation_slop=20):
|
|
|
1168
1188
|
with open(filename, encoding="utf-8", newline="") as fp:
|
|
1169
1189
|
content = fp.read()
|
|
1170
1190
|
fixes = []
|
|
1171
|
-
|
|
1191
|
+
# Lint once, fix every flagged line, then lint again, since fixing one
|
|
1192
|
+
# issue at a time re-lints the whole file for every single fix.
|
|
1193
|
+
for _ in range(100):
|
|
1172
1194
|
issues = markdown_lint_issues_from_text(
|
|
1173
1195
|
content, wrapnumber=wrapnumber, punctuation_slop=punctuation_slop
|
|
1174
1196
|
)
|
|
1175
|
-
fixable =
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
)
|
|
1185
|
-
if fixable is None:
|
|
1197
|
+
fixable = {}
|
|
1198
|
+
for line_number, message in issues:
|
|
1199
|
+
if not message.startswith(
|
|
1200
|
+
("unclosed math:", "unclosed HTML comment:")
|
|
1201
|
+
):
|
|
1202
|
+
# a fix only rewrites its own line, so fix one issue per line
|
|
1203
|
+
# per pass and let the next lint catch whatever remains
|
|
1204
|
+
fixable.setdefault(line_number, message)
|
|
1205
|
+
if not fixable:
|
|
1186
1206
|
break
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
)
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
f"Automatic Markdown fix made no change at line {line_number}"
|
|
1207
|
+
# work from the bottom up so each inserted line break leaves the
|
|
1208
|
+
# line numbers of the remaining issues unchanged
|
|
1209
|
+
pass_fixes = []
|
|
1210
|
+
for line_number in sorted(fixable, reverse=True):
|
|
1211
|
+
updated, before, after, reason = apply_markdown_issue_fix(
|
|
1212
|
+
content, line_number, fixable[line_number]
|
|
1194
1213
|
)
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1214
|
+
if updated == content:
|
|
1215
|
+
raise RuntimeError(
|
|
1216
|
+
"Automatic Markdown fix made no change at line "
|
|
1217
|
+
f"{line_number}"
|
|
1218
|
+
)
|
|
1219
|
+
pass_fixes.append(
|
|
1220
|
+
{
|
|
1221
|
+
"line": line_number,
|
|
1222
|
+
"reason": reason,
|
|
1223
|
+
"before": before,
|
|
1224
|
+
"after": after,
|
|
1225
|
+
}
|
|
1226
|
+
)
|
|
1227
|
+
content = updated
|
|
1228
|
+
fixes.extend(reversed(pass_fixes))
|
|
1204
1229
|
else:
|
|
1205
1230
|
raise RuntimeError("Too many automatic Markdown fixes were needed.")
|
|
1206
1231
|
|
|
@@ -13,11 +13,14 @@ def test_hue_picker_starts_at_seed_and_fills_largest_hue_gap():
|
|
|
13
13
|
assert _most_distant_hue(["#ff0000", "#00ff00"]) == pytest.approx(240)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def test_migration_dialog_builds_qt_script_and_decodes_result(
|
|
16
|
+
def test_migration_dialog_builds_qt_script_and_decodes_result(
|
|
17
|
+
tmp_path, monkeypatch
|
|
18
|
+
):
|
|
17
19
|
captured = {}
|
|
18
20
|
|
|
19
21
|
def fake_run(command, **_kwargs):
|
|
20
22
|
captured["script"] = command[2]
|
|
23
|
+
captured["command"] = command
|
|
21
24
|
compile(command[2], "<comment migration dialog>", "exec")
|
|
22
25
|
return type(
|
|
23
26
|
"Completed",
|
|
@@ -27,11 +30,17 @@ def test_migration_dialog_builds_qt_script_and_decodes_result(monkeypatch):
|
|
|
27
30
|
|
|
28
31
|
monkeypatch.setattr(comment_migration.subprocess, "run", fake_run)
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
path = tmp_path / "notes.md"
|
|
34
|
+
path.write_text("<ABcom>note</ABcom>", encoding="utf-8")
|
|
35
|
+
result = _migration_dialog(str(path), {}, False)
|
|
31
36
|
|
|
32
37
|
assert result == {"accepted": True}
|
|
33
38
|
assert "QColor.fromHsv" in captured["script"]
|
|
34
39
|
assert "QComboBox" in captured["script"]
|
|
40
|
+
# the document is passed by filename, since large files exceed the argv
|
|
41
|
+
# limit
|
|
42
|
+
assert captured["command"][4] == str(path)
|
|
43
|
+
assert "<ABcom>" not in captured["command"][3]
|
|
35
44
|
|
|
36
45
|
|
|
37
46
|
def test_prepare_migrates_legacy_tags_and_div_classes(tmp_path, monkeypatch):
|
|
@@ -120,6 +120,61 @@ def test_one_reported_long_line_is_fixed_at_the_suggested_word():
|
|
|
120
120
|
assert "hard to read" in reason
|
|
121
121
|
|
|
122
122
|
|
|
123
|
+
def test_lint_line_numbers_survive_labeled_display_math():
|
|
124
|
+
# normalizing "$${#eq:x}" for wrapping splits it onto two lines, which
|
|
125
|
+
# must not shift the line numbers reported for later prose
|
|
126
|
+
source = (
|
|
127
|
+
"Intro.\n$$\nx = y\n$${#eq:x}\nwhere this sentence ends. "
|
|
128
|
+
"Another starts.\n"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
((line, message),) = markdown_lint_issues_from_text(source, 55)
|
|
132
|
+
|
|
133
|
+
assert line == 5
|
|
134
|
+
assert message.startswith("sentence ends mid-line")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_long_line_fix_splits_at_the_word_after_the_break():
|
|
138
|
+
# "for" also starts the line, but wr breaks before the second one
|
|
139
|
+
source = (
|
|
140
|
+
"for $30\\;\\text{s}$ ($3\\times$ for AOT) with some more words "
|
|
141
|
+
"added.\n"
|
|
142
|
+
)
|
|
143
|
+
message = (
|
|
144
|
+
"line too long: wr would break after '($3\\times$' (before 'for'); "
|
|
145
|
+
"move 'for' onward to the next line, or shorten this sentence"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
fixed, _, _, _ = apply_markdown_issue_fix(source, 1, message)
|
|
149
|
+
|
|
150
|
+
assert fixed.startswith("for $30\\;\\text{s}$ ($3\\times$\nfor AOT)")
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_trailing_space_after_sentence_is_removed_not_a_blank_line(tmp_path):
|
|
154
|
+
path = tmp_path / "source.md"
|
|
155
|
+
path.write_text("It melts near 238 K. \nIn contrast, it stays.\n")
|
|
156
|
+
|
|
157
|
+
autofix_markdown_file(path)
|
|
158
|
+
|
|
159
|
+
fixed = path.read_text()
|
|
160
|
+
assert fixed.startswith("It melts near 238 K.\nIn contrast,")
|
|
161
|
+
assert "\n\n" not in fixed
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def test_autofix_fixes_every_line_in_one_pass_from_the_end(tmp_path):
|
|
165
|
+
path = tmp_path / "source.md"
|
|
166
|
+
paragraph = "First sentence ends here. A second sentence begins.\n"
|
|
167
|
+
path.write_text("\n".join([paragraph] * 30))
|
|
168
|
+
|
|
169
|
+
report = autofix_markdown_file(path)
|
|
170
|
+
|
|
171
|
+
fixed = path.read_text()
|
|
172
|
+
assert len(report["fixes"]) == 30
|
|
173
|
+
assert [fix["line"] for fix in report["fixes"]] == list(range(1, 60, 2))
|
|
174
|
+
assert fixed.count("\n\n") == 29
|
|
175
|
+
assert markdown_lint_issues_from_text(fixed, wrapnumber=55) == []
|
|
176
|
+
|
|
177
|
+
|
|
123
178
|
def test_unclosed_math_is_reported_after_fifty_lines():
|
|
124
179
|
short_math = "$$\n" + ("x = y\n" * 48)
|
|
125
180
|
long_math = "$$\n" + ("x = y\n" * 49)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.37 → pydifftools-0.1.39}/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.37 → pydifftools-0.1.39}/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.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg
RENAMED
|
File without changes
|
{pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/independent.qmd
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.37 → pydifftools-0.1.39}/example_notebook/project1/subproject1/test_include.qmd
RENAMED
|
File without changes
|
{pydifftools-0.1.37 → pydifftools-0.1.39}/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
|