pyDiffTools 0.1.42__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.
Files changed (114) hide show
  1. {pydifftools-0.1.42/pyDiffTools.egg-info → pydifftools-0.1.43}/PKG-INFO +1 -1
  2. {pydifftools-0.1.42 → pydifftools-0.1.43/pyDiffTools.egg-info}/PKG-INFO +1 -1
  3. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/continuous.py +101 -43
  4. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/wrap_sentences.py +7 -2
  5. {pydifftools-0.1.42 → pydifftools-0.1.43}/pyproject.toml +1 -1
  6. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_wrap_check.py +65 -6
  7. {pydifftools-0.1.42 → pydifftools-0.1.43}/LICENSE.md +0 -0
  8. {pydifftools-0.1.42 → pydifftools-0.1.43}/MANIFEST.in +0 -0
  9. {pydifftools-0.1.42 → pydifftools-0.1.43}/README.rst +0 -0
  10. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/_quarto.yml +0 -0
  11. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
  12. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
  13. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
  14. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
  15. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
  16. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
  17. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
  18. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
  19. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
  20. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
  21. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
  22. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
  23. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
  24. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
  25. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
  26. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
  27. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
  28. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
  29. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
  30. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
  31. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
  32. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/.jupyter_cache/global.db +0 -0
  33. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/example.qmd +0 -0
  34. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/example.tex +0 -0
  35. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/index.qmd +0 -0
  36. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
  37. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
  38. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
  39. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
  40. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/independent.qmd +0 -0
  41. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/index.qmd +0 -0
  42. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/tasks.qmd +0 -0
  43. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/test_include.qmd +0 -0
  44. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
  45. {pydifftools-0.1.42 → pydifftools-0.1.43}/example_notebook/project1/test_include.qmd +0 -0
  46. {pydifftools-0.1.42 → pydifftools-0.1.43}/pyDiffTools.egg-info/SOURCES.txt +0 -0
  47. {pydifftools-0.1.42 → pydifftools-0.1.43}/pyDiffTools.egg-info/dependency_links.txt +0 -0
  48. {pydifftools-0.1.42 → pydifftools-0.1.43}/pyDiffTools.egg-info/entry_points.txt +0 -0
  49. {pydifftools-0.1.42 → pydifftools-0.1.43}/pyDiffTools.egg-info/requires.txt +0 -0
  50. {pydifftools-0.1.42 → pydifftools-0.1.43}/pyDiffTools.egg-info/top_level.txt +0 -0
  51. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/__init__.py +0 -0
  52. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/bibliography.py +0 -0
  53. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/browser_lifecycle.py +0 -0
  54. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/check_numbers.py +0 -0
  55. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/citation_dialog.py +0 -0
  56. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/command_line.py +0 -0
  57. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/command_registry.py +0 -0
  58. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/comment_functions.py +0 -0
  59. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/comment_migration.py +0 -0
  60. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/comment_tags.lua +0 -0
  61. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/comment_tags_margin.lua +0 -0
  62. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/comment_tags_no_comments.lua +0 -0
  63. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/comment_toggle.js +0 -0
  64. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/comments.css +0 -0
  65. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/copy_files.py +0 -0
  66. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/diff-doc.js +0 -0
  67. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/doc_contents.py +0 -0
  68. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/flowchart/__init__.py +0 -0
  69. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/flowchart/comparison.py +0 -0
  70. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/flowchart/dot_to_yaml.py +0 -0
  71. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/flowchart/graph.py +0 -0
  72. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/flowchart/svg-pan-zoom.min.js +0 -0
  73. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/flowchart/watch_graph.py +0 -0
  74. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/flowchart/wgrph_view.js +0 -0
  75. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/forward_search.py +0 -0
  76. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/git_gd.py +0 -0
  77. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/git_gd_history.py +0 -0
  78. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/git_gd_image.py +0 -0
  79. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/git_gd_qt.py +0 -0
  80. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/html_comments.py +0 -0
  81. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/html_uncomments.py +0 -0
  82. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/log_example.py +0 -0
  83. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/match_spaces.py +0 -0
  84. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/notebook/__init__.py +0 -0
  85. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/notebook/display.py +0 -0
  86. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/notebook/fast_build.py +0 -0
  87. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/notebook/tex_to_qmd.py +0 -0
  88. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/onewordify.py +0 -0
  89. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/onewordify_undo.py +0 -0
  90. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/outline.py +0 -0
  91. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/rearrange_tex.py +0 -0
  92. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/searchacro.py +0 -0
  93. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/separate_comments.py +0 -0
  94. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/split_conflict.py +0 -0
  95. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/unseparate_comments.py +0 -0
  96. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/update_check.py +0 -0
  97. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/xml2xlsx.vbs +0 -0
  98. {pydifftools-0.1.42 → pydifftools-0.1.43}/pydifftools/zotero.py +0 -0
  99. {pydifftools-0.1.42 → pydifftools-0.1.43}/setup.cfg +0 -0
  100. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_bibliography.py +0 -0
  101. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_browser_lifecycle.py +0 -0
  102. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_check_single_use.py +0 -0
  103. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_command_line_help.py +0 -0
  104. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_comment_migration.py +0 -0
  105. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_continuous_shutdown.py +0 -0
  106. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_forward_search.py +0 -0
  107. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_git_gd_history.py +0 -0
  108. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_git_gd_image.py +0 -0
  109. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_git_gd_qt.py +0 -0
  110. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_rrng.py +0 -0
  111. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_tex_to_qmd.py +0 -0
  112. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_update_check.py +0 -0
  113. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_wrapping.py +0 -0
  114. {pydifftools-0.1.42 → pydifftools-0.1.43}/tests/test_zotero.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyDiffTools
3
- Version: 0.1.42
3
+ Version: 0.1.43
4
4
  Summary: Diff tools
5
5
  Author: J M Franck
6
6
  License: Copyright (c) 2015, jmfranck
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyDiffTools
3
- Version: 0.1.42
3
+ Version: 0.1.43
4
4
  Summary: Diff tools
5
5
  Author: J M Franck
6
6
  License: Copyright (c) 2015, jmfranck
@@ -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
- records = [
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
- dialog.resize(760, 480)
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
- line = record["line"]
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
- heading.setText("I fixed this source line automatically.")
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
- before_lines = record["before"].splitlines() or [""]
202
- after_lines = record["after"].splitlines() or [""]
203
- source_html = ""
204
- numbers = []
205
- if "\n" in record["after"]:
206
- after_html = "<br>↳ ".join(
207
- escape(value)
208
- for value in record["after"].split("\n")
209
- )
210
- source_html = (
211
- "<pre style='font-family:monospace; margin:0'>"
212
- + "Before:<br>"
213
- + "<br>".join(escape(value) for value in before_lines)
214
- + "<br><br>After:<br>"
215
- + after_html
216
- + "</pre>"
217
- )
218
- numbers = [""] + list(
219
- range(line, line + len(before_lines))
220
- )
221
- numbers += ["", ""]
222
- numbers += list(range(line, line + len(after_lines)))
223
- line_numbers.setText("<br>".join(str(value) for value in numbers))
224
- preview.setHtml(source_html)
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
- heading.setText("This source span is not closed.")
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(
@@ -1190,10 +1190,15 @@ def apply_markdown_issue_fix(content, line_number, message):
1190
1190
  else:
1191
1191
  span = found.span("gap")
1192
1192
  joined = ""
1193
- before = content[found.start() : found.end()]
1194
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]
1195
1200
  after = updated[
1196
- found.start() : span[0] + len(joined) + found.end() - span[1]
1201
+ line_start : line_end - (span[1] - span[0]) + len(joined)
1197
1202
  ]
1198
1203
  return (
1199
1204
  updated,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyDiffTools"
7
- version = "0.1.42"
7
+ version = "0.1.43"
8
8
  authors = [{ name = "J M Franck" }]
9
9
  description = "Diff tools"
10
10
  readme = "README.rst"
@@ -423,11 +423,6 @@ def test_qt_fix_and_reload_windows_show_source_changes(tmp_path):
423
423
  )
424
424
  seen["preview"] = dialog.findChild(QTextEdit).toPlainText()
425
425
  seen["button"] = dialog.findChild(QPushButton).text()
426
- seen["line_gutter"] = next(
427
- label
428
- for label in dialog.findChildren(QLabel)
429
- if "#666" in label.styleSheet()
430
- ).text()
431
426
  seen["heading"] = dialog.findChildren(QLabel)[0].text()
432
427
  dialog.findChild(QPushButton).click()
433
428
 
@@ -435,7 +430,7 @@ def test_qt_fix_and_reload_windows_show_source_changes(tmp_path):
435
430
  show_markdown_fix_dialog(report)
436
431
  assert "↳ collection of words" in seen["preview"]
437
432
  assert seen["button"] == "Done"
438
- assert "1" in seen["line_gutter"]
433
+ assert re.search(r"^ +1 − This deliberately", seen["preview"], re.M)
439
434
  assert "line 1" not in seen["heading"].lower()
440
435
 
441
436
  def inspect_reload_window():
@@ -454,6 +449,70 @@ def test_qt_fix_and_reload_windows_show_source_changes(tmp_path):
454
449
  assert seen["reload_button"] == "I've reloaded"
455
450
 
456
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
+
457
516
  def test_qt_unclosed_math_window_bolds_source_and_requests_confirmation():
458
517
  from PySide6.QtCore import QTimer
459
518
  from PySide6.QtWidgets import (
File without changes
File without changes
File without changes
File without changes