pyDiffTools 0.1.39__tar.gz → 0.1.40__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.39/pyDiffTools.egg-info → pydifftools-0.1.40}/PKG-INFO +1 -1
- {pydifftools-0.1.39 → pydifftools-0.1.40/pyDiffTools.egg-info}/PKG-INFO +1 -1
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/wrap_sentences.py +90 -14
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pyproject.toml +1 -1
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_wrap_check.py +80 -2
- {pydifftools-0.1.39 → pydifftools-0.1.40}/LICENSE.md +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/MANIFEST.in +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/README.rst +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/_quarto.yml +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/example.qmd +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/example.tex +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/index.qmd +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/independent.qmd +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/index.qmd +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/tasks.qmd +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/test_include.qmd +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/test_include.qmd +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pyDiffTools.egg-info/SOURCES.txt +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pyDiffTools.egg-info/dependency_links.txt +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pyDiffTools.egg-info/entry_points.txt +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pyDiffTools.egg-info/requires.txt +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pyDiffTools.egg-info/top_level.txt +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/__init__.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/bibliography.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/browser_lifecycle.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/check_numbers.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/citation_dialog.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/command_line.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/command_registry.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/comment_functions.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/comment_migration.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/comment_tags.lua +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/comment_tags_margin.lua +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/comment_tags_no_comments.lua +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/comment_toggle.js +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/comments.css +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/continuous.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/copy_files.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/diff-doc.js +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/doc_contents.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/flowchart/__init__.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/flowchart/comparison.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/flowchart/dot_to_yaml.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/flowchart/graph.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/flowchart/svg-pan-zoom.min.js +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/flowchart/watch_graph.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/flowchart/wgrph_view.js +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/forward_search.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/git_gd.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/git_gd_history.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/git_gd_image.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/git_gd_qt.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/html_comments.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/html_uncomments.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/log_example.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/match_spaces.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/notebook/__init__.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/notebook/display.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/notebook/fast_build.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/notebook/tex_to_qmd.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/onewordify.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/onewordify_undo.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/outline.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/rearrange_tex.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/searchacro.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/separate_comments.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/split_conflict.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/unseparate_comments.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/update_check.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/xml2xlsx.vbs +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/pydifftools/zotero.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/setup.cfg +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_bibliography.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_browser_lifecycle.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_check_single_use.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_command_line_help.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_comment_migration.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_continuous_shutdown.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_forward_search.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_git_gd_history.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_git_gd_image.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_git_gd_qt.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_rrng.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_tex_to_qmd.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_update_check.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_wrapping.py +0 -0
- {pydifftools-0.1.39 → pydifftools-0.1.40}/tests/test_zotero.py +0 -0
|
@@ -16,6 +16,16 @@ PARAGRAPH_SPLIT = re.compile(r"(\n(?:[ \t]*\n)+)")
|
|
|
16
16
|
SENTENCE_END = r"[^.!?]{3}[.!?]"
|
|
17
17
|
SENTENCE_SPLIT = re.compile("(" + SENTENCE_END + r")[ \n]")
|
|
18
18
|
SENTENCE_BOUNDARY = re.compile("(" + SENTENCE_END + r")([ \n])")
|
|
19
|
+
# A word is a run of non-space characters, except that an attribute block
|
|
20
|
+
# attached to a figure's closing ")" (or any "{#id ...}" block) stays inside
|
|
21
|
+
# the word, so a break never lands inside a pandoc-crossref marker.
|
|
22
|
+
WORD = re.compile(r"(?:(?<=\))\{[^}]*\}|\{#[^}]*\}|\S)+")
|
|
23
|
+
# A pandoc-crossref marker must directly follow the closing "$$" of its
|
|
24
|
+
# equation or the closing ")" of its figure, and must stay on one line.
|
|
25
|
+
DETACHED_CROSSREF = re.compile(
|
|
26
|
+
r"(?:(?<!\\)\$\$|\))(?P<gap>[ \t]*\n?[ \t]*)(?=\{#(?:eq|fig):)"
|
|
27
|
+
r"|(?P<marker>\{#(?:eq|fig):[^}\n]*\n[^}]*\})"
|
|
28
|
+
)
|
|
19
29
|
LATEX_MACRO_SPLIT = re.compile(
|
|
20
30
|
r"(\\(?:begin|end|usepackage|newcommand|section"
|
|
21
31
|
r"|subsection|subsubsection|paragraph|input){[^}]*})"
|
|
@@ -584,6 +594,11 @@ def classify_lines(
|
|
|
584
594
|
if not equation.endswith("\n"):
|
|
585
595
|
equation += "\n"
|
|
586
596
|
equation += "$$"
|
|
597
|
+
# keep a pandoc-crossref marker on its closing "$$"
|
|
598
|
+
marker = re.match(r"\{#eq:[^}]*\}", content[stop:])
|
|
599
|
+
if marker:
|
|
600
|
+
equation += marker[0]
|
|
601
|
+
stop += marker.end()
|
|
587
602
|
if stop < len(content):
|
|
588
603
|
equation += "\n"
|
|
589
604
|
if content[stop] == "\n":
|
|
@@ -686,7 +701,9 @@ def wrap_prose(
|
|
|
686
701
|
lines = []
|
|
687
702
|
indentation = 0
|
|
688
703
|
for sentence in sentences:
|
|
689
|
-
words = [
|
|
704
|
+
words = [
|
|
705
|
+
re.sub(r"\s+", " ", word) for word in WORD.findall(sentence)
|
|
706
|
+
]
|
|
690
707
|
boundaries = _math_boundaries(words)
|
|
691
708
|
if filetype == "latex":
|
|
692
709
|
indentation = 0
|
|
@@ -794,6 +811,15 @@ def _prepare(filename, cleanoo=False, i=-1):
|
|
|
794
811
|
def wr(filename, wrapnumber=45, punctuation_slop=20, cleanoo=False, i=-1):
|
|
795
812
|
alltext, filetype, indent_amount, _ = _prepare(filename, cleanoo, i)
|
|
796
813
|
if filetype == "markdown":
|
|
814
|
+
# reattach detached pandoc-crossref markers before wrapping
|
|
815
|
+
alltext = DETACHED_CROSSREF.sub(
|
|
816
|
+
lambda found: (
|
|
817
|
+
re.sub(r"\s+", " ", found["marker"])
|
|
818
|
+
if found["marker"]
|
|
819
|
+
else found[0][: len(found[0]) - len(found["gap"])]
|
|
820
|
+
),
|
|
821
|
+
alltext,
|
|
822
|
+
)
|
|
797
823
|
result = wrap_blocks(
|
|
798
824
|
markdown_blocks(alltext),
|
|
799
825
|
wrapnumber,
|
|
@@ -865,7 +891,7 @@ def check_prose(content, wrapnumber, punctuation_slop, line_start=1):
|
|
|
865
891
|
if fragment:
|
|
866
892
|
# {{{ check line lengths within this sentence fragment
|
|
867
893
|
words, positions = [], []
|
|
868
|
-
for match in
|
|
894
|
+
for match in WORD.finditer(fragment):
|
|
869
895
|
words.append(match.group())
|
|
870
896
|
positions.append(frag_offset + match.start())
|
|
871
897
|
if words:
|
|
@@ -987,6 +1013,9 @@ def markdown_lint_issues_from_text(
|
|
|
987
1013
|
prose_content = re.sub(
|
|
988
1014
|
r"<!--.*?(?:-->|\Z)", mask_comment, content, flags=re.DOTALL
|
|
989
1015
|
)
|
|
1016
|
+
# trailing spaces are reported separately below, and a double space
|
|
1017
|
+
# (a hard line break) must not look like a sentence ending mid-line
|
|
1018
|
+
prose_content = re.sub(r"[ \t]+$", "", prose_content, flags=re.M)
|
|
990
1019
|
issues = [
|
|
991
1020
|
issue
|
|
992
1021
|
for line, width, span in _iter_block_spans(
|
|
@@ -998,6 +1027,27 @@ def markdown_lint_issues_from_text(
|
|
|
998
1027
|
(issue["line"], issue["message"])
|
|
999
1028
|
for issue in unclosed_markdown_spans(content)
|
|
1000
1029
|
)
|
|
1030
|
+
# {{{ report single trailing spaces and detached crossref markers
|
|
1031
|
+
fence = None
|
|
1032
|
+
for number, line in enumerate(content.splitlines(), start=1):
|
|
1033
|
+
opening = re.match(r"[ \t]*(\x60{3,}|~{3,})", line)
|
|
1034
|
+
if opening and (fence is None or opening[1].startswith(fence)):
|
|
1035
|
+
fence = None if fence else opening[1]
|
|
1036
|
+
elif fence is None and re.search(r"(?<! ) $", line):
|
|
1037
|
+
issues.append((
|
|
1038
|
+
number,
|
|
1039
|
+
"trailing space: remove the single space at the end of this "
|
|
1040
|
+
"line (two spaces are a deliberate hard line break)",
|
|
1041
|
+
))
|
|
1042
|
+
for found in DETACHED_CROSSREF.finditer(prose_content):
|
|
1043
|
+
if found["gap"] == "":
|
|
1044
|
+
continue
|
|
1045
|
+
issues.append((
|
|
1046
|
+
prose_content.count("\n", 0, found.start()) + 1,
|
|
1047
|
+
"detached crossref marker: keep the {#eq:...} or {#fig:...} "
|
|
1048
|
+
"marker on one line, directly after the closing $$ or )",
|
|
1049
|
+
))
|
|
1050
|
+
# }}}
|
|
1001
1051
|
return sorted(issues)
|
|
1002
1052
|
|
|
1003
1053
|
|
|
@@ -1101,6 +1151,33 @@ def apply_markdown_issue_fix(content, line_number, message):
|
|
|
1101
1151
|
raise ValueError(
|
|
1102
1152
|
f"Markdown issue refers to missing line {line_number}"
|
|
1103
1153
|
)
|
|
1154
|
+
if message.startswith("detached crossref marker"):
|
|
1155
|
+
# {{{ join the marker onto its "$$" or ")" (this can remove a line)
|
|
1156
|
+
start = sum(len(line) for line in lines[:index])
|
|
1157
|
+
found = next(
|
|
1158
|
+
found
|
|
1159
|
+
for found in DETACHED_CROSSREF.finditer(content, start)
|
|
1160
|
+
if found["gap"] != ""
|
|
1161
|
+
)
|
|
1162
|
+
if found["gap"] is None:
|
|
1163
|
+
span = found.span("marker")
|
|
1164
|
+
joined = re.sub(r"\s+", " ", found["marker"])
|
|
1165
|
+
else:
|
|
1166
|
+
span = found.span("gap")
|
|
1167
|
+
joined = ""
|
|
1168
|
+
before = content[found.start() : found.end()]
|
|
1169
|
+
updated = content[: span[0]] + joined + content[span[1] :]
|
|
1170
|
+
after = updated[
|
|
1171
|
+
found.start() : span[0] + len(joined) + found.end() - span[1]
|
|
1172
|
+
]
|
|
1173
|
+
return (
|
|
1174
|
+
updated,
|
|
1175
|
+
before,
|
|
1176
|
+
after,
|
|
1177
|
+
"A crossref marker was separated from its equation or figure. "
|
|
1178
|
+
"I joined it back on.",
|
|
1179
|
+
)
|
|
1180
|
+
# }}}
|
|
1104
1181
|
old_line = lines[index]
|
|
1105
1182
|
ending = ""
|
|
1106
1183
|
if old_line.endswith("\r\n"):
|
|
@@ -1123,6 +1200,14 @@ def apply_markdown_issue_fix(content, line_number, message):
|
|
|
1123
1200
|
else:
|
|
1124
1201
|
prefix = re.match(r"^[ \t]*", old_line).group()
|
|
1125
1202
|
# }}}
|
|
1203
|
+
if message.startswith("trailing space:"):
|
|
1204
|
+
lines[index] = old_line[:-1] + ending
|
|
1205
|
+
return (
|
|
1206
|
+
"".join(lines),
|
|
1207
|
+
old_line,
|
|
1208
|
+
old_line[:-1],
|
|
1209
|
+
"A line ended with a single stray space. I removed it.",
|
|
1210
|
+
)
|
|
1126
1211
|
if message.startswith("line too long:"):
|
|
1127
1212
|
match = re.search(r"after '(.+?)' \(before '(.+?)'\); move", message)
|
|
1128
1213
|
if match is None:
|
|
@@ -1164,22 +1249,13 @@ def apply_markdown_issue_fix(content, line_number, message):
|
|
|
1164
1249
|
else:
|
|
1165
1250
|
raise ValueError(f"No automatic fix is available for {message!r}")
|
|
1166
1251
|
|
|
1167
|
-
if not first.strip():
|
|
1252
|
+
if not first.strip() or not second.strip():
|
|
1168
1253
|
# a break here would insert a blank line, i.e. a paragraph break
|
|
1169
1254
|
raise ValueError(
|
|
1170
1255
|
f"Automatic fix would leave an empty line at {line_number}"
|
|
1171
1256
|
)
|
|
1172
|
-
|
|
1173
|
-
|
|
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
|
-
)
|
|
1257
|
+
lines[index] = first + ending + prefix + second + ending
|
|
1258
|
+
after = first + "\n" + prefix + second
|
|
1183
1259
|
return "".join(lines), old_line, after, reason
|
|
1184
1260
|
|
|
1185
1261
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import re
|
|
1
2
|
import subprocess
|
|
2
3
|
|
|
3
4
|
import pytest
|
|
@@ -150,15 +151,92 @@ def test_long_line_fix_splits_at_the_word_after_the_break():
|
|
|
150
151
|
assert fixed.startswith("for $30\\;\\text{s}$ ($3\\times$\nfor AOT)")
|
|
151
152
|
|
|
152
153
|
|
|
153
|
-
def
|
|
154
|
+
def test_single_trailing_space_is_flagged_and_removed(tmp_path):
|
|
155
|
+
# from RM_ESR: a sentence ending in a stray space
|
|
154
156
|
path = tmp_path / "source.md"
|
|
155
157
|
path.write_text("It melts near 238 K. \nIn contrast, it stays.\n")
|
|
156
158
|
|
|
159
|
+
issues = markdown_lint_issues_from_text(path.read_text(), wrapnumber=55)
|
|
157
160
|
autofix_markdown_file(path)
|
|
158
161
|
|
|
162
|
+
assert (1, "trailing space") in [
|
|
163
|
+
(line, message.split(":")[0]) for line, message in issues
|
|
164
|
+
]
|
|
159
165
|
fixed = path.read_text()
|
|
160
166
|
assert fixed.startswith("It melts near 238 K.\nIn contrast,")
|
|
161
|
-
assert "\n
|
|
167
|
+
assert " \n" not in fixed
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def test_double_trailing_space_hard_break_is_allowed():
|
|
171
|
+
source = "The first line ends here with a break \nand continues.\n"
|
|
172
|
+
|
|
173
|
+
assert markdown_lint_issues_from_text(source, wrapnumber=55) == []
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@pytest.mark.parametrize(
|
|
177
|
+
"detached",
|
|
178
|
+
[
|
|
179
|
+
# equation markers must sit directly on the closing $$
|
|
180
|
+
"Intro.\n$$\nx = y\n$$ {#eq:x}\nwhere this holds.\n",
|
|
181
|
+
"Intro.\n$$\nx = y\n$$\n{#eq:x}\nwhere this holds.\n",
|
|
182
|
+
# figure markers must sit directly on the closing ) (from eigenmode)
|
|
183
|
+
"\n"
|
|
184
|
+
'{#fig:ProbeMagFieldsDrawing width="4in"}\n',
|
|
185
|
+
# and must not be split across lines (from RM_ESR)
|
|
186
|
+
""
|
|
187
|
+
"{#fig:justSpectraCat16\nwidth=4in}\n",
|
|
188
|
+
],
|
|
189
|
+
)
|
|
190
|
+
def test_detached_crossref_marker_is_flagged_and_joined(tmp_path, detached):
|
|
191
|
+
path = tmp_path / "source.md"
|
|
192
|
+
path.write_text(detached)
|
|
193
|
+
|
|
194
|
+
issues = markdown_lint_issues_from_text(detached, wrapnumber=55)
|
|
195
|
+
report = autofix_markdown_file(path)
|
|
196
|
+
|
|
197
|
+
fixed = path.read_text()
|
|
198
|
+
assert [message.split(":")[0] for _, message in issues] == [
|
|
199
|
+
"detached crossref marker"
|
|
200
|
+
]
|
|
201
|
+
assert report["fixes"]
|
|
202
|
+
assert markdown_lint_issues_from_text(fixed, wrapnumber=55) == []
|
|
203
|
+
assert re.search(r"(\$\$|\))\{#(eq|fig):[^}\n]*\}", fixed)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def test_figure_crossref_marker_is_never_split_from_its_figure(tmp_path):
|
|
207
|
+
# from RM_ESR: a caption spanning lines, ending in a marker with
|
|
208
|
+
# attributes; wr and the linter must treat "...){#fig:... }" as one word
|
|
209
|
+
source = (
|
|
210
|
+
"\n"
|
|
214
|
+
"{#fig:HESimul width=5.5in}\n"
|
|
215
|
+
)
|
|
216
|
+
path = tmp_path / "source.md"
|
|
217
|
+
path.write_text(source)
|
|
218
|
+
|
|
219
|
+
wr(str(path), 55)
|
|
220
|
+
|
|
221
|
+
wrapped = path.read_text()
|
|
222
|
+
assert (
|
|
223
|
+
"(green)](Figures/HE_Easyspin_Simul_100mM.png)"
|
|
224
|
+
"{#fig:HESimul width=5.5in}\n"
|
|
225
|
+
) in wrapped
|
|
226
|
+
assert markdown_lint_issues_from_text(wrapped, wrapnumber=55) == []
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def test_wr_keeps_equation_marker_on_closing_dollars(tmp_path):
|
|
230
|
+
path = tmp_path / "source.md"
|
|
231
|
+
path.write_text(
|
|
232
|
+
"Intro.\n$$\nx = y\n$$ {#eq:tauFromLinewidth}\nwhere this holds.\n"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
wr(str(path), 55)
|
|
236
|
+
|
|
237
|
+
wrapped = path.read_text()
|
|
238
|
+
assert "\n$${#eq:tauFromLinewidth}\n" in wrapped
|
|
239
|
+
assert markdown_lint_issues_from_text(wrapped, wrapnumber=55) == []
|
|
162
240
|
|
|
163
241
|
|
|
164
242
|
def test_autofix_fixes_every_line_in_one_pass_from_the_end(tmp_path):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.39 → pydifftools-0.1.40}/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.39 → pydifftools-0.1.40}/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.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg
RENAMED
|
File without changes
|
{pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/independent.qmd
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.39 → pydifftools-0.1.40}/example_notebook/project1/subproject1/test_include.qmd
RENAMED
|
File without changes
|
{pydifftools-0.1.39 → pydifftools-0.1.40}/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
|