pyDiffTools 0.1.41__tar.gz → 0.1.43__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.41/pyDiffTools.egg-info → pydifftools-0.1.43}/PKG-INFO +1 -1
- {pydifftools-0.1.41 → pydifftools-0.1.43/pyDiffTools.egg-info}/PKG-INFO +1 -1
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/continuous.py +110 -45
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/wrap_sentences.py +56 -69
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pyproject.toml +1 -1
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_wrap_check.py +110 -34
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_wrapping.py +2 -1
- {pydifftools-0.1.41 → pydifftools-0.1.43}/LICENSE.md +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/MANIFEST.in +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/README.rst +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/_quarto.yml +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/example.qmd +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/example.tex +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/index.qmd +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/independent.qmd +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/index.qmd +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/tasks.qmd +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/test_include.qmd +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/test_include.qmd +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pyDiffTools.egg-info/SOURCES.txt +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pyDiffTools.egg-info/dependency_links.txt +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pyDiffTools.egg-info/entry_points.txt +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pyDiffTools.egg-info/requires.txt +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pyDiffTools.egg-info/top_level.txt +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/__init__.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/bibliography.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/browser_lifecycle.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/check_numbers.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/citation_dialog.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/command_line.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/command_registry.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/comment_functions.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/comment_migration.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/comment_tags.lua +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/comment_tags_margin.lua +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/comment_tags_no_comments.lua +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/comment_toggle.js +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/comments.css +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/copy_files.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/diff-doc.js +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/doc_contents.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/flowchart/__init__.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/flowchart/comparison.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/flowchart/dot_to_yaml.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/flowchart/graph.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/flowchart/svg-pan-zoom.min.js +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/flowchart/watch_graph.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/flowchart/wgrph_view.js +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/forward_search.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/git_gd.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/git_gd_history.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/git_gd_image.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/git_gd_qt.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/html_comments.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/html_uncomments.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/log_example.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/match_spaces.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/notebook/__init__.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/notebook/display.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/notebook/fast_build.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/notebook/tex_to_qmd.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/onewordify.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/onewordify_undo.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/outline.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/rearrange_tex.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/searchacro.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/separate_comments.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/split_conflict.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/unseparate_comments.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/update_check.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/xml2xlsx.vbs +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/pydifftools/zotero.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/setup.cfg +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_bibliography.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_browser_lifecycle.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_check_single_use.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_command_line_help.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_comment_migration.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_continuous_shutdown.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_forward_search.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_git_gd_history.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_git_gd_image.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_git_gd_qt.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_rrng.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_tex_to_qmd.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_update_check.py +0 -0
- {pydifftools-0.1.41 → pydifftools-0.1.43}/tests/test_zotero.py +0 -0
|
@@ -132,7 +132,7 @@ def show_markdown_fix_dialog(report):
|
|
|
132
132
|
from html import escape
|
|
133
133
|
|
|
134
134
|
from PySide6.QtCore import Qt
|
|
135
|
-
from PySide6.QtGui import QFontDatabase
|
|
135
|
+
from PySide6.QtGui import QFontDatabase, QFontMetrics
|
|
136
136
|
from PySide6.QtWidgets import (
|
|
137
137
|
QApplication,
|
|
138
138
|
QDialog,
|
|
@@ -145,14 +145,7 @@ def show_markdown_fix_dialog(report):
|
|
|
145
145
|
|
|
146
146
|
fixes = report["fixes"]
|
|
147
147
|
warnings = report["warnings"]
|
|
148
|
-
|
|
149
|
-
{"record_type": "fix", **fix}
|
|
150
|
-
for fix in fixes
|
|
151
|
-
] + [
|
|
152
|
-
{"record_type": "warning", **warning}
|
|
153
|
-
for warning in warnings
|
|
154
|
-
]
|
|
155
|
-
if not records:
|
|
148
|
+
if not fixes and not warnings:
|
|
156
149
|
return
|
|
157
150
|
|
|
158
151
|
dialog = QDialog()
|
|
@@ -160,7 +153,53 @@ def show_markdown_fix_dialog(report):
|
|
|
160
153
|
QApplication.instance() or QApplication([])
|
|
161
154
|
)
|
|
162
155
|
dialog.setWindowTitle("Markdown source fixes")
|
|
163
|
-
|
|
156
|
+
fixed_font = QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont)
|
|
157
|
+
# {{{ group fixes of one kind onto pages that fill the screen
|
|
158
|
+
screen_height = dialog.screen().availableGeometry().height()
|
|
159
|
+
dialog.resize(900, int(screen_height * 0.85))
|
|
160
|
+
# leave room for the heading, explanation, button and margins
|
|
161
|
+
page_rows = max(
|
|
162
|
+
3,
|
|
163
|
+
int(
|
|
164
|
+
(screen_height * 0.85 - 120)
|
|
165
|
+
/ QFontMetrics(fixed_font).lineSpacing()
|
|
166
|
+
),
|
|
167
|
+
)
|
|
168
|
+
groups = {}
|
|
169
|
+
for fix in fixes:
|
|
170
|
+
groups.setdefault(fix["reason"], []).append(fix)
|
|
171
|
+
records = []
|
|
172
|
+
for reason, group in groups.items():
|
|
173
|
+
page = []
|
|
174
|
+
rows = 0
|
|
175
|
+
for fix in sorted(group, key=lambda fix: fix["line"]):
|
|
176
|
+
# a blank line separates each fix from the one before it, and a
|
|
177
|
+
# fix that only drops trailing spaces shows just its old line
|
|
178
|
+
fix_rows = (
|
|
179
|
+
len(fix["before"].splitlines() or [""])
|
|
180
|
+
+ (
|
|
181
|
+
0
|
|
182
|
+
if fix["after"] == fix["before"].rstrip()
|
|
183
|
+
else len(fix["after"].splitlines() or [""])
|
|
184
|
+
)
|
|
185
|
+
+ (1 if page else 0)
|
|
186
|
+
)
|
|
187
|
+
if page and rows + fix_rows > page_rows:
|
|
188
|
+
records.append(
|
|
189
|
+
{"record_type": "fix", "reason": reason, "fixes": page}
|
|
190
|
+
)
|
|
191
|
+
page = []
|
|
192
|
+
rows = 0
|
|
193
|
+
fix_rows -= 1
|
|
194
|
+
page.append(fix)
|
|
195
|
+
rows += fix_rows
|
|
196
|
+
records.append(
|
|
197
|
+
{"record_type": "fix", "reason": reason, "fixes": page}
|
|
198
|
+
)
|
|
199
|
+
records += [
|
|
200
|
+
{"record_type": "warning", **warning} for warning in warnings
|
|
201
|
+
]
|
|
202
|
+
# }}}
|
|
164
203
|
layout = QVBoxLayout(dialog)
|
|
165
204
|
heading = QLabel()
|
|
166
205
|
heading.setWordWrap(True)
|
|
@@ -175,14 +214,10 @@ def show_markdown_fix_dialog(report):
|
|
|
175
214
|
Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
|
|
176
215
|
)
|
|
177
216
|
line_numbers.setStyleSheet("color: #666; padding-right: 8px;")
|
|
178
|
-
line_numbers.setFont(
|
|
179
|
-
QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont)
|
|
180
|
-
)
|
|
217
|
+
line_numbers.setFont(fixed_font)
|
|
181
218
|
preview = QTextEdit()
|
|
182
219
|
preview.setReadOnly(True)
|
|
183
|
-
preview.setFont(
|
|
184
|
-
QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont)
|
|
185
|
-
)
|
|
220
|
+
preview.setFont(fixed_font)
|
|
186
221
|
preview_row.addWidget(line_numbers)
|
|
187
222
|
preview_row.addWidget(preview, 1)
|
|
188
223
|
layout.addLayout(preview_row, 1)
|
|
@@ -194,37 +229,60 @@ def show_markdown_fix_dialog(report):
|
|
|
194
229
|
|
|
195
230
|
def show_record():
|
|
196
231
|
record = records[index]
|
|
197
|
-
|
|
232
|
+
page = (
|
|
233
|
+
f" (page {index + 1} of {len(records)})"
|
|
234
|
+
if len(records) > 1
|
|
235
|
+
else ""
|
|
236
|
+
)
|
|
198
237
|
if record["record_type"] == "fix":
|
|
199
|
-
|
|
238
|
+
count = len(record["fixes"])
|
|
239
|
+
heading.setText(
|
|
240
|
+
"I fixed this source line automatically." + page
|
|
241
|
+
if count == 1
|
|
242
|
+
else f"I fixed these {count} source lines automatically."
|
|
243
|
+
+ page
|
|
244
|
+
)
|
|
200
245
|
details.setText(record["reason"])
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
246
|
+
line_numbers.setVisible(False)
|
|
247
|
+
# {{{ show each fix as numbered before (−) and after (+) lines
|
|
248
|
+
entries = []
|
|
249
|
+
for fix in record["fixes"]:
|
|
250
|
+
rows = []
|
|
251
|
+
for offset, value in enumerate(
|
|
252
|
+
fix["before"].splitlines() or [""]
|
|
253
|
+
):
|
|
254
|
+
stripped = value.rstrip(" ")
|
|
255
|
+
rows.append(
|
|
256
|
+
f"<span style='color:#666'>{fix['line'] + offset:>6}"
|
|
257
|
+
"</span> − "
|
|
258
|
+
+ escape(stripped)
|
|
259
|
+
# make stray trailing spaces visible
|
|
260
|
+
+ "<span style='background:#fbb'>·</span>"
|
|
261
|
+
* (len(value) - len(stripped))
|
|
262
|
+
)
|
|
263
|
+
for offset, value in enumerate(
|
|
264
|
+
[]
|
|
265
|
+
if fix["after"] == fix["before"].rstrip()
|
|
266
|
+
else fix["after"].split("\n")
|
|
267
|
+
):
|
|
268
|
+
rows.append(
|
|
269
|
+
f"<span style='color:#666'>{fix['line'] + offset:>6}"
|
|
270
|
+
"</span> "
|
|
271
|
+
+ ("+ " if offset == 0 else "↳ ")
|
|
272
|
+
+ escape(value)
|
|
273
|
+
)
|
|
274
|
+
entries.append("<br>".join(rows))
|
|
275
|
+
preview.setHtml(
|
|
276
|
+
"<pre style='font-family:monospace; margin:0'>"
|
|
277
|
+
+ "<br><br>".join(entries)
|
|
278
|
+
+ "</pre>"
|
|
279
|
+
)
|
|
280
|
+
# }}}
|
|
225
281
|
button.setText("Next" if index + 1 < len(records) else "Done")
|
|
226
282
|
else:
|
|
227
|
-
|
|
283
|
+
line = record["line"]
|
|
284
|
+
heading.setText("This source span is not closed." + page)
|
|
285
|
+
line_numbers.setVisible(True)
|
|
228
286
|
if record["kind"] == "math":
|
|
229
287
|
delimiter = record["delimiter"]
|
|
230
288
|
details.setText(
|
|
@@ -303,6 +361,7 @@ def run_pandoc(
|
|
|
303
361
|
comments_to_margin=False,
|
|
304
362
|
no_comments=False,
|
|
305
363
|
comment_filter_session=None,
|
|
364
|
+
wrapnumber=79,
|
|
306
365
|
):
|
|
307
366
|
# {{{ automatically fix Markdown source and request edits for
|
|
308
367
|
# unfinished spans
|
|
@@ -310,7 +369,7 @@ def run_pandoc(
|
|
|
310
369
|
|
|
311
370
|
automatic_fixes_were_made = False
|
|
312
371
|
while True:
|
|
313
|
-
report = autofix_markdown_file(filename,
|
|
372
|
+
report = autofix_markdown_file(filename, wrapnumber=wrapnumber)
|
|
314
373
|
automatic_fixes_were_made |= bool(report["fixes"])
|
|
315
374
|
if report["fixes"] or report["warnings"]:
|
|
316
375
|
user_says_fixed = show_markdown_fix_dialog(report)
|
|
@@ -789,10 +848,14 @@ class Handler(FileSystemEventHandler):
|
|
|
789
848
|
"no_comments": (
|
|
790
849
|
"Render the HTML without comment tags or comment div blocks."
|
|
791
850
|
),
|
|
851
|
+
"wrapnumber": (
|
|
852
|
+
"Maximum source line width; the automatic Markdown fixes break "
|
|
853
|
+
"only lines longer than this."
|
|
854
|
+
),
|
|
792
855
|
},
|
|
793
856
|
filename_extensions={"filename": ".md"},
|
|
794
857
|
)
|
|
795
|
-
def cpb(filename, comments_to_margin=False, no_comments=False):
|
|
858
|
+
def cpb(filename, comments_to_margin=False, no_comments=False, wrapnumber=79):
|
|
796
859
|
source_path = os.path.normpath(os.path.abspath(filename))
|
|
797
860
|
source_dir = os.path.dirname(source_path)
|
|
798
861
|
html_file = filename.rsplit(".", 1)[0] + ".html"
|
|
@@ -836,6 +899,7 @@ def cpb(filename, comments_to_margin=False, no_comments=False):
|
|
|
836
899
|
comments_to_margin=comments_to_margin,
|
|
837
900
|
no_comments=no_comments,
|
|
838
901
|
comment_filter_session=comment_filter_session,
|
|
902
|
+
wrapnumber=wrapnumber,
|
|
839
903
|
)
|
|
840
904
|
append_autorefresh(html_file)
|
|
841
905
|
notice = zotero_notice()
|
|
@@ -971,6 +1035,7 @@ def cpb(filename, comments_to_margin=False, no_comments=False):
|
|
|
971
1035
|
comments_to_margin=comments_to_margin,
|
|
972
1036
|
no_comments=no_comments,
|
|
973
1037
|
comment_filter_session=comment_filter_session,
|
|
1038
|
+
wrapnumber=wrapnumber,
|
|
974
1039
|
)
|
|
975
1040
|
append_autorefresh(html_file)
|
|
976
1041
|
except Exception as exc:
|
|
@@ -658,18 +658,29 @@ def _next_break(words, wrapnumber, punctuation_slop, boundaries, offset):
|
|
|
658
658
|
Shared by wrap_prose (which then emits that line) and check_prose
|
|
659
659
|
(which replays the same choice to see if a source line agrees).
|
|
660
660
|
"""
|
|
661
|
+
# counts[j] - 1 is the length of the line holding words[: j + 1]
|
|
661
662
|
counts = list(itertools.accumulate(len(word) + 1 for word in words))
|
|
662
|
-
|
|
663
|
+
if counts[-1] - 1 <= wrapnumber:
|
|
664
|
+
# the rest fits, so there is nothing to break
|
|
665
|
+
return len(words) - 1
|
|
666
|
+
# the last word that fits within the width (or the first word, if even
|
|
667
|
+
# that is too long)
|
|
668
|
+
upto = max(
|
|
669
|
+
[j for j, count in enumerate(counts) if count - 1 <= wrapnumber]
|
|
670
|
+
or [0]
|
|
671
|
+
)
|
|
672
|
+
# prefer to end the line on a clause (comma, paren, dash, ...) or at an
|
|
673
|
+
# inline-math boundary within punctuation_slop characters of that break
|
|
663
674
|
candidates = [
|
|
664
675
|
j
|
|
665
|
-
for j, word in enumerate(words)
|
|
666
|
-
if (
|
|
676
|
+
for j, word in enumerate(words[: upto + 1])
|
|
677
|
+
if (
|
|
678
|
+
(len(word) > 1 and word[-1] in ",;:)-")
|
|
679
|
+
or offset + j in boundaries
|
|
680
|
+
)
|
|
681
|
+
and counts[upto] - counts[j] < punctuation_slop
|
|
667
682
|
]
|
|
668
|
-
if candidates
|
|
669
|
-
punct = min(candidates, key=lambda j: abs(counts[j] - wrapnumber))
|
|
670
|
-
if punct < upto and upto - punct < punctuation_slop:
|
|
671
|
-
upto = punct
|
|
672
|
-
return upto
|
|
683
|
+
return max(candidates) if candidates else upto
|
|
673
684
|
|
|
674
685
|
|
|
675
686
|
def wrap_prose(
|
|
@@ -805,6 +816,11 @@ def _prepare(filename, cleanoo=False, i=-1):
|
|
|
805
816
|
"filename": "Input file to wrap. Use '-' to read from stdin.",
|
|
806
817
|
"cleanoo": "Strip LibreOffice markup before wrapping.",
|
|
807
818
|
"i": "Indentation level for wrapped lines.",
|
|
819
|
+
"wrapnumber": "Maximum line width in characters.",
|
|
820
|
+
"punctuation_slop": (
|
|
821
|
+
"End a line early on a clause (comma, paren, dash, ...) when "
|
|
822
|
+
"that is within this many characters of the widest break."
|
|
823
|
+
),
|
|
808
824
|
},
|
|
809
825
|
filename_extensions={"filename": [".md", ".tex"]},
|
|
810
826
|
)
|
|
@@ -920,7 +936,16 @@ def check_prose(content, wrapnumber, punctuation_slop, line_start=1):
|
|
|
920
936
|
and not breaks_after[actual_end]
|
|
921
937
|
):
|
|
922
938
|
actual_end += 1
|
|
923
|
-
|
|
939
|
+
line_length = (
|
|
940
|
+
positions[actual_end]
|
|
941
|
+
+ len(words[actual_end])
|
|
942
|
+
- positions[fragment_offset]
|
|
943
|
+
)
|
|
944
|
+
# only a line that exceeds the width is too long
|
|
945
|
+
if (
|
|
946
|
+
actual_end > wr_end
|
|
947
|
+
and line_length > wrapnumber
|
|
948
|
+
):
|
|
924
949
|
overflow = words[wr_end + 1]
|
|
925
950
|
issue_line = para_line + stripped.count(
|
|
926
951
|
"\n", 0, positions[actual_end]
|
|
@@ -1004,13 +1029,9 @@ def _iter_block_spans(blocks, wrapnumber, line_start=1):
|
|
|
1004
1029
|
|
|
1005
1030
|
|
|
1006
1031
|
def markdown_lint_issues_from_text(
|
|
1007
|
-
content, wrapnumber=45, punctuation_slop=20
|
|
1032
|
+
content, wrapnumber=45, punctuation_slop=20
|
|
1008
1033
|
):
|
|
1009
|
-
"""Return Markdown writing issues, including unfinished source spans.
|
|
1010
|
-
|
|
1011
|
-
With `max_line_length`, a prose line is only too long when it holds
|
|
1012
|
-
more than that many characters, instead of wr's greedy line choice.
|
|
1013
|
-
"""
|
|
1034
|
+
"""Return Markdown writing issues, including unfinished source spans."""
|
|
1014
1035
|
def mask_comment(match):
|
|
1015
1036
|
return "".join("\n" if char == "\n" else " " for char in match[0])
|
|
1016
1037
|
|
|
@@ -1020,30 +1041,13 @@ def markdown_lint_issues_from_text(
|
|
|
1020
1041
|
# trailing spaces are reported separately below, and a double space
|
|
1021
1042
|
# (a hard line break) must not look like a sentence ending mid-line
|
|
1022
1043
|
prose_content = re.sub(r"[ \t]+$", "", prose_content, flags=re.M)
|
|
1023
|
-
issues = [
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
for issue in check_prose(span, width, punctuation_slop, line)
|
|
1029
|
-
|
|
1030
|
-
"line too long:"
|
|
1031
|
-
):
|
|
1032
|
-
issues.append(issue)
|
|
1033
|
-
if max_line_length is not None:
|
|
1034
|
-
# {{{ flag prose lines longer than the character limit
|
|
1035
|
-
for number in range(line, line + len(span.splitlines())):
|
|
1036
|
-
text = prose_lines[number - 1]
|
|
1037
|
-
# a single unbreakable word cannot be shortened
|
|
1038
|
-
if len(text) > max_line_length and len(
|
|
1039
|
-
WORD.findall(text)
|
|
1040
|
-
) > 1:
|
|
1041
|
-
issues.append((
|
|
1042
|
-
number,
|
|
1043
|
-
f"line over {max_line_length} characters: break "
|
|
1044
|
-
"it at a word boundary",
|
|
1045
|
-
))
|
|
1046
|
-
# }}}
|
|
1044
|
+
issues = [
|
|
1045
|
+
issue
|
|
1046
|
+
for line, width, span in _iter_block_spans(
|
|
1047
|
+
markdown_blocks(prose_content), wrapnumber
|
|
1048
|
+
)
|
|
1049
|
+
for issue in check_prose(span, width, punctuation_slop, line)
|
|
1050
|
+
]
|
|
1047
1051
|
issues.extend(
|
|
1048
1052
|
(issue["line"], issue["message"])
|
|
1049
1053
|
for issue in unclosed_markdown_spans(content)
|
|
@@ -1186,10 +1190,15 @@ def apply_markdown_issue_fix(content, line_number, message):
|
|
|
1186
1190
|
else:
|
|
1187
1191
|
span = found.span("gap")
|
|
1188
1192
|
joined = ""
|
|
1189
|
-
before = content[found.start() : found.end()]
|
|
1190
1193
|
updated = content[: span[0]] + joined + content[span[1] :]
|
|
1194
|
+
# report the whole source lines around the join
|
|
1195
|
+
line_start = content.rfind("\n", 0, found.start()) + 1
|
|
1196
|
+
line_end = content.find("\n", max(found.end(), span[1]))
|
|
1197
|
+
if line_end == -1:
|
|
1198
|
+
line_end = len(content)
|
|
1199
|
+
before = content[line_start:line_end]
|
|
1191
1200
|
after = updated[
|
|
1192
|
-
|
|
1201
|
+
line_start : line_end - (span[1] - span[0]) + len(joined)
|
|
1193
1202
|
]
|
|
1194
1203
|
return (
|
|
1195
1204
|
updated,
|
|
@@ -1229,25 +1238,7 @@ def apply_markdown_issue_fix(content, line_number, message):
|
|
|
1229
1238
|
old_line[:-1],
|
|
1230
1239
|
"A line ended with a single stray space. I removed it.",
|
|
1231
1240
|
)
|
|
1232
|
-
if message.startswith("line
|
|
1233
|
-
# {{{ break at the last word boundary that fits the limit
|
|
1234
|
-
limit = int(re.match(r"line over (\d+)", message)[1])
|
|
1235
|
-
gaps = [
|
|
1236
|
-
found.end()
|
|
1237
|
-
for found in WORD.finditer(old_line)
|
|
1238
|
-
if container.end() < found.end() < len(old_line.rstrip())
|
|
1239
|
-
]
|
|
1240
|
-
fitting = [gap for gap in gaps if gap <= limit]
|
|
1241
|
-
# when even the first word is too long, break right after it
|
|
1242
|
-
split_at = fitting[-1] if fitting else gaps[0]
|
|
1243
|
-
first = old_line[:split_at].rstrip()
|
|
1244
|
-
second = old_line[split_at:].lstrip(" \t")
|
|
1245
|
-
reason = (
|
|
1246
|
-
f"This line was longer than {limit} characters. "
|
|
1247
|
-
"I moved the last words onto a new line."
|
|
1248
|
-
)
|
|
1249
|
-
# }}}
|
|
1250
|
-
elif message.startswith("line too long:"):
|
|
1241
|
+
if message.startswith("line too long:"):
|
|
1251
1242
|
match = re.search(r"after '(.+?)' \(before '(.+?)'\); move", message)
|
|
1252
1243
|
if match is None:
|
|
1253
1244
|
raise ValueError(
|
|
@@ -1298,9 +1289,7 @@ def apply_markdown_issue_fix(content, line_number, message):
|
|
|
1298
1289
|
return "".join(lines), old_line, after, reason
|
|
1299
1290
|
|
|
1300
1291
|
|
|
1301
|
-
def autofix_markdown_file(
|
|
1302
|
-
filename, wrapnumber=55, punctuation_slop=20, max_line_length=None
|
|
1303
|
-
):
|
|
1292
|
+
def autofix_markdown_file(filename, wrapnumber=55, punctuation_slop=20):
|
|
1304
1293
|
"""Apply safe source line breaks and report unfinished source spans."""
|
|
1305
1294
|
with open(filename, encoding="utf-8", newline="") as fp:
|
|
1306
1295
|
content = fp.read()
|
|
@@ -1309,10 +1298,7 @@ def autofix_markdown_file(
|
|
|
1309
1298
|
# issue at a time re-lints the whole file for every single fix.
|
|
1310
1299
|
for _ in range(100):
|
|
1311
1300
|
issues = markdown_lint_issues_from_text(
|
|
1312
|
-
content,
|
|
1313
|
-
wrapnumber=wrapnumber,
|
|
1314
|
-
punctuation_slop=punctuation_slop,
|
|
1315
|
-
max_line_length=max_line_length,
|
|
1301
|
+
content, wrapnumber=wrapnumber, punctuation_slop=punctuation_slop
|
|
1316
1302
|
)
|
|
1317
1303
|
fixable = {}
|
|
1318
1304
|
for line_number, message in issues:
|
|
@@ -1358,8 +1344,9 @@ def autofix_markdown_file(
|
|
|
1358
1344
|
@register_command(
|
|
1359
1345
|
"check wrapping and sentence-break rules (for markdown or latex).",
|
|
1360
1346
|
"check that a file already obeys wr's wrapping rules -- without\n"
|
|
1361
|
-
"rewriting anything. Reports a source line as too long if it
|
|
1362
|
-
"
|
|
1347
|
+
"rewriting anything. Reports a source line as too long if it is\n"
|
|
1348
|
+
"longer than --wrapnumber characters (and suggests the break wr would\n"
|
|
1349
|
+
"use, which favors ending on a clause a few words early), and\n"
|
|
1363
1350
|
"reports a sentence that ends in the middle of a source line\n"
|
|
1364
1351
|
"instead of at a line break. Prints 'file:line: message' for each\n"
|
|
1365
1352
|
"violation and exits non-zero if any are found. Takes the same\n"
|
|
@@ -253,49 +253,66 @@ def test_autofix_fixes_every_line_in_one_pass_from_the_end(tmp_path):
|
|
|
253
253
|
assert markdown_lint_issues_from_text(fixed, wrapnumber=55) == []
|
|
254
254
|
|
|
255
255
|
|
|
256
|
-
def
|
|
257
|
-
# from RM_ESR:
|
|
256
|
+
def test_only_lines_longer_than_the_width_are_too_long():
|
|
257
|
+
# from RM_ESR: short lines ending on a clause used to be flagged, since
|
|
258
|
+
# wr broke at a comma or paren even when the rest of the line fit
|
|
258
259
|
source = (
|
|
259
|
-
"
|
|
260
|
-
"
|
|
260
|
+
"(see @fig:CaldararuTau) indicates that\n"
|
|
261
|
+
"This is especially true, given that a comparison\n"
|
|
261
262
|
)
|
|
262
263
|
|
|
263
|
-
assert markdown_lint_issues_from_text(source, 55)
|
|
264
|
-
assert markdown_lint_issues_from_text(source,
|
|
264
|
+
assert markdown_lint_issues_from_text(source, 55) == []
|
|
265
|
+
assert markdown_lint_issues_from_text(source, 79) == []
|
|
266
|
+
assert [
|
|
267
|
+
message.split(":")[0]
|
|
268
|
+
for _, message in markdown_lint_issues_from_text(source, 40)
|
|
269
|
+
] == ["line too long"]
|
|
265
270
|
|
|
266
271
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
# from RM_ESR: a sentence that grew past 79 characters
|
|
272
|
+
def test_long_line_breaks_early_on_a_nearby_clause(tmp_path):
|
|
273
|
+
# from RM_ESR: several clauses on one line that grew past 79
|
|
270
274
|
line = (
|
|
271
|
-
|
|
272
|
-
"
|
|
273
|
-
"experiment.\n"
|
|
275
|
+
"Finally, it estimates the rotational correlation time, "
|
|
276
|
+
"*via* the classic Kivelson equation, as a function of temperature.\n"
|
|
274
277
|
)
|
|
275
278
|
path = tmp_path / "source.md"
|
|
276
279
|
path.write_text(line)
|
|
277
280
|
|
|
278
|
-
|
|
279
|
-
report = autofix_markdown_file(path, max_line_length=79)
|
|
281
|
+
report = autofix_markdown_file(path, wrapnumber=79)
|
|
280
282
|
|
|
281
283
|
fixed = path.read_text()
|
|
282
|
-
assert
|
|
283
|
-
"line over 79 characters"
|
|
284
|
-
]
|
|
285
|
-
assert "79 characters" in report["fixes"][0]["reason"]
|
|
284
|
+
assert fixed.split() == line.split()
|
|
286
285
|
assert all(len(text) <= 79 for text in fixed.splitlines())
|
|
287
|
-
|
|
288
|
-
#
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
286
|
+
# the widest break is after "classic" (72 characters); "time," is 18
|
|
287
|
+
# characters before that, within the slop, so the line ends on it
|
|
288
|
+
assert fixed.splitlines()[0].endswith("rotational correlation time,")
|
|
289
|
+
assert len(report["fixes"]) == 1
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def test_clause_far_before_the_width_does_not_force_an_early_break():
|
|
293
|
+
line = (
|
|
294
|
+
"Finally, it estimates the rotational correlation time of the "
|
|
295
|
+
"probe and many other ordinary words here.\n"
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
first = wrap_prose(line, 79).splitlines()[0]
|
|
293
299
|
|
|
300
|
+
assert first.startswith("Finally, it estimates")
|
|
301
|
+
assert len(first) > 70
|
|
294
302
|
|
|
295
|
-
def test_character_limit_skips_a_single_unbreakable_word():
|
|
296
|
-
source = "https://example.org/" + "x" * 90 + "\n"
|
|
297
303
|
|
|
298
|
-
|
|
304
|
+
@pytest.mark.parametrize("width", [20, 45, 55, 79])
|
|
305
|
+
def test_wr_never_runs_past_the_width(width):
|
|
306
|
+
text = (
|
|
307
|
+
"This script determines the field positions, and amplitudes, of the "
|
|
308
|
+
"spectral lines (for an entire variable-temperature experiment) -- "
|
|
309
|
+
"and it implements spline-based smoothing of the spectra.\n"
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
wrapped = wrap_prose(text, width)
|
|
313
|
+
|
|
314
|
+
assert all(len(line) <= width for line in wrapped.splitlines())
|
|
315
|
+
assert markdown_lint_issues_from_text(wrapped, width) == []
|
|
299
316
|
|
|
300
317
|
|
|
301
318
|
def test_unclosed_math_is_reported_after_fifty_lines():
|
|
@@ -406,19 +423,14 @@ def test_qt_fix_and_reload_windows_show_source_changes(tmp_path):
|
|
|
406
423
|
)
|
|
407
424
|
seen["preview"] = dialog.findChild(QTextEdit).toPlainText()
|
|
408
425
|
seen["button"] = dialog.findChild(QPushButton).text()
|
|
409
|
-
seen["line_gutter"] = next(
|
|
410
|
-
label
|
|
411
|
-
for label in dialog.findChildren(QLabel)
|
|
412
|
-
if "#666" in label.styleSheet()
|
|
413
|
-
).text()
|
|
414
426
|
seen["heading"] = dialog.findChildren(QLabel)[0].text()
|
|
415
427
|
dialog.findChild(QPushButton).click()
|
|
416
428
|
|
|
417
429
|
QTimer.singleShot(0, inspect_fix_window)
|
|
418
430
|
show_markdown_fix_dialog(report)
|
|
419
|
-
assert "↳ of words" in seen["preview"]
|
|
431
|
+
assert "↳ collection of words" in seen["preview"]
|
|
420
432
|
assert seen["button"] == "Done"
|
|
421
|
-
assert "1"
|
|
433
|
+
assert re.search(r"^ +1 − This deliberately", seen["preview"], re.M)
|
|
422
434
|
assert "line 1" not in seen["heading"].lower()
|
|
423
435
|
|
|
424
436
|
def inspect_reload_window():
|
|
@@ -437,6 +449,70 @@ def test_qt_fix_and_reload_windows_show_source_changes(tmp_path):
|
|
|
437
449
|
assert seen["reload_button"] == "I've reloaded"
|
|
438
450
|
|
|
439
451
|
|
|
452
|
+
def test_qt_fix_window_groups_fixes_of_one_kind_onto_full_pages(tmp_path):
|
|
453
|
+
pytest.importorskip("PySide6")
|
|
454
|
+
from PySide6.QtCore import QTimer
|
|
455
|
+
from PySide6.QtWidgets import QApplication, QDialog, QPushButton
|
|
456
|
+
from PySide6.QtWidgets import QLabel, QTextEdit
|
|
457
|
+
|
|
458
|
+
from pydifftools.continuous import show_markdown_fix_dialog
|
|
459
|
+
|
|
460
|
+
app = QApplication.instance() or QApplication([])
|
|
461
|
+
# from RM_ESR: many stray trailing spaces plus one other kind of fix
|
|
462
|
+
source_path = tmp_path / "content.md"
|
|
463
|
+
source_path.write_text(
|
|
464
|
+
"".join(f"Sentence number {j} ends here. \n" for j in range(60))
|
|
465
|
+
+ "\n$$\nx = y\n$$ {#eq:tauFromLinewidth}\n"
|
|
466
|
+
)
|
|
467
|
+
report = autofix_markdown_file(source_path)
|
|
468
|
+
assert len(report["fixes"]) == 61
|
|
469
|
+
pages = []
|
|
470
|
+
|
|
471
|
+
def inspect_page():
|
|
472
|
+
dialog = next(
|
|
473
|
+
widget
|
|
474
|
+
for widget in app.topLevelWidgets()
|
|
475
|
+
if isinstance(widget, QDialog)
|
|
476
|
+
and widget.isVisible()
|
|
477
|
+
and widget.windowTitle() == "Markdown source fixes"
|
|
478
|
+
)
|
|
479
|
+
preview = dialog.findChild(QTextEdit).toPlainText()
|
|
480
|
+
pages.append(
|
|
481
|
+
{
|
|
482
|
+
"heading": dialog.findChildren(QLabel)[0].text(),
|
|
483
|
+
"details": dialog.findChildren(QLabel)[1].text(),
|
|
484
|
+
"entries": preview.split("\n\n"),
|
|
485
|
+
}
|
|
486
|
+
)
|
|
487
|
+
button = dialog.findChild(QPushButton)
|
|
488
|
+
if button.text() == "Next":
|
|
489
|
+
QTimer.singleShot(0, inspect_page)
|
|
490
|
+
button.click()
|
|
491
|
+
|
|
492
|
+
QTimer.singleShot(0, inspect_page)
|
|
493
|
+
show_markdown_fix_dialog(report)
|
|
494
|
+
|
|
495
|
+
trailing = [page for page in pages if "stray space" in page["details"]]
|
|
496
|
+
crossref = [page for page in pages if "crossref" in page["details"]]
|
|
497
|
+
# one kind per page, many fixes per page, and every fix shown once
|
|
498
|
+
assert len(trailing) + len(crossref) == len(pages)
|
|
499
|
+
assert len(crossref) == 1
|
|
500
|
+
assert 1 < len(trailing) < 60
|
|
501
|
+
assert all(len(page["entries"]) > 5 for page in trailing[:-1])
|
|
502
|
+
assert sum(len(page["entries"]) for page in trailing) == 60
|
|
503
|
+
assert f"(page 1 of {len(pages)})" in pages[0]["heading"]
|
|
504
|
+
# a trailing-space entry is just the numbered line with its stray space
|
|
505
|
+
# made visible, while other fixes also show the line after the fix
|
|
506
|
+
assert re.fullmatch(
|
|
507
|
+
r" +1 − Sentence number 0 ends here\.·", trailing[0]["entries"][0]
|
|
508
|
+
)
|
|
509
|
+
assert re.fullmatch(
|
|
510
|
+
r" +64 − \$\$ \{#eq:tauFromLinewidth\}\n +64 \+ "
|
|
511
|
+
r"\$\$\{#eq:tauFromLinewidth\}",
|
|
512
|
+
crossref[0]["entries"][0],
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
|
|
440
516
|
def test_qt_unclosed_math_window_bolds_source_and_requests_confirmation():
|
|
441
517
|
from PySide6.QtCore import QTimer
|
|
442
518
|
from PySide6.QtWidgets import (
|
|
@@ -423,7 +423,8 @@ def test_nested_containers_keep_terms_items_and_paragraphs_separate():
|
|
|
423
423
|
result = wrap_blocks(markdown_blocks(source), 25)
|
|
424
424
|
assert result.startswith("Term\n: first definition\n")
|
|
425
425
|
assert "\n - a nested item with\n" in result
|
|
426
|
-
|
|
426
|
+
# the quotation is 17 wide, so wr never lets it run past that
|
|
427
|
+
assert "\n > a nested\n" in result
|
|
427
428
|
assert "\n: a second definition\n" in result
|
|
428
429
|
assert "\n\nOutside prose" in result
|
|
429
430
|
assert wrap_blocks(markdown_blocks(result), 25) == result
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.41 → pydifftools-0.1.43}/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.41 → pydifftools-0.1.43}/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.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg
RENAMED
|
File without changes
|
{pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/independent.qmd
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydifftools-0.1.41 → pydifftools-0.1.43}/example_notebook/project1/subproject1/test_include.qmd
RENAMED
|
File without changes
|
{pydifftools-0.1.41 → pydifftools-0.1.43}/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
|