pyDiffTools 0.1.28__tar.gz → 0.1.30__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 (109) hide show
  1. {pydifftools-0.1.28/pyDiffTools.egg-info → pydifftools-0.1.30}/PKG-INFO +39 -4
  2. {pydifftools-0.1.28 → pydifftools-0.1.30}/README.rst +33 -3
  3. {pydifftools-0.1.28 → pydifftools-0.1.30/pyDiffTools.egg-info}/PKG-INFO +39 -4
  4. {pydifftools-0.1.28 → pydifftools-0.1.30}/pyDiffTools.egg-info/SOURCES.txt +12 -1
  5. {pydifftools-0.1.28 → pydifftools-0.1.30}/pyDiffTools.egg-info/requires.txt +5 -0
  6. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/command_line.py +124 -28
  7. pydifftools-0.1.30/pydifftools/continuous.py +730 -0
  8. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/doc_contents.py +23 -8
  9. pydifftools-0.1.30/pydifftools/forward_search.py +124 -0
  10. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/git_gd.py +216 -58
  11. pydifftools-0.1.30/pydifftools/git_gd_history.py +329 -0
  12. pydifftools-0.1.30/pydifftools/git_gd_image.py +754 -0
  13. pydifftools-0.1.30/pydifftools/git_gd_qt.py +591 -0
  14. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/match_spaces.py +380 -235
  15. pydifftools-0.1.30/pydifftools/notebook/display.py +67 -0
  16. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/notebook/fast_build.py +1248 -674
  17. pydifftools-0.1.30/pydifftools/outline.py +184 -0
  18. pydifftools-0.1.30/pydifftools/wrap_sentences.py +1022 -0
  19. {pydifftools-0.1.28 → pydifftools-0.1.30}/pyproject.toml +6 -1
  20. pydifftools-0.1.30/tests/test_check_single_use.py +45 -0
  21. {pydifftools-0.1.28 → pydifftools-0.1.30}/tests/test_command_line_help.py +64 -0
  22. pydifftools-0.1.30/tests/test_continuous_shutdown.py +391 -0
  23. pydifftools-0.1.30/tests/test_forward_search.py +339 -0
  24. pydifftools-0.1.30/tests/test_git_gd_history.py +203 -0
  25. pydifftools-0.1.30/tests/test_git_gd_image.py +316 -0
  26. pydifftools-0.1.30/tests/test_git_gd_qt.py +142 -0
  27. pydifftools-0.1.30/tests/test_wrap_check.py +141 -0
  28. pydifftools-0.1.30/tests/test_wrapping.py +500 -0
  29. pydifftools-0.1.28/pydifftools/continuous.py +0 -488
  30. pydifftools-0.1.28/pydifftools/git_gd_qt.py +0 -334
  31. pydifftools-0.1.28/pydifftools/outline.py +0 -173
  32. pydifftools-0.1.28/pydifftools/wrap_sentences.py +0 -501
  33. pydifftools-0.1.28/tests/test_continuous_shutdown.py +0 -64
  34. {pydifftools-0.1.28 → pydifftools-0.1.30}/LICENSE.md +0 -0
  35. {pydifftools-0.1.28 → pydifftools-0.1.30}/MANIFEST.in +0 -0
  36. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/_quarto.yml +0 -0
  37. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/__version__.txt +0 -0
  38. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/1a724af72b16f5a9e607e12b1c721645/base.ipynb +0 -0
  39. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/1b28fc9daac9081847e5161b2c546f8a/base.ipynb +0 -0
  40. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/231f64eee282fa225d1104935cf80a24/base.ipynb +0 -0
  41. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/26e56f6b0ff54851a45145157f2f0dc4/base.ipynb +0 -0
  42. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/311fabd7029ffd050d056e2f316eb50f/base.ipynb +0 -0
  43. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/57da2021e5b156ac3adf01398201c723/base.ipynb +0 -0
  44. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/62b24ea7da75011d92b0f8924faa208d/base.ipynb +0 -0
  45. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/7f1b20d69d889514ab5d1cc92e3cb14f/base.ipynb +0 -0
  46. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/86f74c8c54a87ff892d9b15dd714e8f0/base.ipynb +0 -0
  47. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/88893b4234eac2945d9d6cb2e277f186/base.ipynb +0 -0
  48. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/9a40046ada6f582ee34af00fbdbfb417/base.ipynb +0 -0
  49. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/a1bf4d270d0641ff41faf1d7cce3439a/base.ipynb +0 -0
  50. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/a3789f7d9585a781f2a1c60ce95ff10d/base.ipynb +0 -0
  51. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/be46ecba858d39ad5f0c46902ddf1c02/base.ipynb +0 -0
  52. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/d0cbc57a12f2ccce710a5afd04cc05e7/base.ipynb +0 -0
  53. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/d3e12d320b14228f701231ae32ddd7dd/base.ipynb +0 -0
  54. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/eb434f61555438d020a6970a5dbf9ee8/base.ipynb +0 -0
  55. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/f6b0e73aa7fa029134665d4dde57e096/base.ipynb +0 -0
  56. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/f719a6e4ff09873cb0ffb06ec9d232f9/base.ipynb +0 -0
  57. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/executed/feeee244a7ce3d60e1a227eb604df823/base.ipynb +0 -0
  58. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/.jupyter_cache/global.db +0 -0
  59. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/example.qmd +0 -0
  60. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/example.tex +0 -0
  61. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/index.qmd +0 -0
  62. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/.jupyter_cache/__version__.txt +0 -0
  63. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/.jupyter_cache/executed/ca90e4df5f4f0583df6554156a68dc7f/base.ipynb +0 -0
  64. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/.jupyter_cache/global.db +0 -0
  65. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/end_vs_he_sketch.jpg +0 -0
  66. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/independent.qmd +0 -0
  67. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/index.qmd +0 -0
  68. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/tasks.qmd +0 -0
  69. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/test_include.qmd +0 -0
  70. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/subproject1/tryforerror.qmd +0 -0
  71. {pydifftools-0.1.28 → pydifftools-0.1.30}/example_notebook/project1/test_include.qmd +0 -0
  72. {pydifftools-0.1.28 → pydifftools-0.1.30}/pyDiffTools.egg-info/dependency_links.txt +0 -0
  73. {pydifftools-0.1.28 → pydifftools-0.1.30}/pyDiffTools.egg-info/entry_points.txt +0 -0
  74. {pydifftools-0.1.28 → pydifftools-0.1.30}/pyDiffTools.egg-info/top_level.txt +0 -0
  75. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/__init__.py +0 -0
  76. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/browser_lifecycle.py +0 -0
  77. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/check_numbers.py +0 -0
  78. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/command_registry.py +0 -0
  79. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/comment_functions.py +0 -0
  80. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/comment_tags.lua +0 -0
  81. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/comment_tags_margin.lua +0 -0
  82. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/comment_tags_no_comments.lua +0 -0
  83. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/comment_toggle.js +0 -0
  84. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/comments.css +0 -0
  85. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/copy_files.py +0 -0
  86. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/diff-doc.js +0 -0
  87. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/flowchart/__init__.py +0 -0
  88. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/flowchart/dot_to_yaml.py +0 -0
  89. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/flowchart/graph.py +0 -0
  90. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/flowchart/watch_graph.py +0 -0
  91. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/html_comments.py +0 -0
  92. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/html_uncomments.py +0 -0
  93. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/log_example.py +0 -0
  94. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/notebook/__init__.py +0 -0
  95. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/notebook/tex_to_qmd.py +0 -0
  96. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/onewordify.py +0 -0
  97. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/onewordify_undo.py +0 -0
  98. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/rearrange_tex.py +0 -0
  99. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/searchacro.py +0 -0
  100. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/separate_comments.py +0 -0
  101. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/split_conflict.py +0 -0
  102. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/unseparate_comments.py +0 -0
  103. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/update_check.py +0 -0
  104. {pydifftools-0.1.28 → pydifftools-0.1.30}/pydifftools/xml2xlsx.vbs +0 -0
  105. {pydifftools-0.1.28 → pydifftools-0.1.30}/setup.cfg +0 -0
  106. {pydifftools-0.1.28 → pydifftools-0.1.30}/tests/test_browser_lifecycle.py +0 -0
  107. {pydifftools-0.1.28 → pydifftools-0.1.30}/tests/test_rrng.py +0 -0
  108. {pydifftools-0.1.28 → pydifftools-0.1.30}/tests/test_tex_to_qmd.py +0 -0
  109. {pydifftools-0.1.28 → pydifftools-0.1.30}/tests/test_update_check.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyDiffTools
3
- Version: 0.1.28
3
+ Version: 0.1.30
4
4
  Summary: Diff tools
5
5
  Author: J M Franck
6
6
  License: Copyright (c) 2015, jmfranck
@@ -34,6 +34,8 @@ License: Copyright (c) 2015, jmfranck
34
34
 
35
35
  Description-Content-Type: text/x-rst
36
36
  License-File: LICENSE.md
37
+ Requires-Dist: numpy
38
+ Requires-Dist: Pillow
37
39
  Requires-Dist: selenium
38
40
  Requires-Dist: fuzzywuzzy[speedup]
39
41
  Requires-Dist: PyYAML>=6.0
@@ -41,11 +43,14 @@ Requires-Dist: watchdog
41
43
  Requires-Dist: pydot
42
44
  Requires-Dist: python-dateutil
43
45
  Requires-Dist: jinja2
46
+ Requires-Dist: ipykernel
47
+ Requires-Dist: matplotlib
44
48
  Requires-Dist: nbformat
45
49
  Requires-Dist: nbconvert
46
50
  Requires-Dist: pygments
47
51
  Requires-Dist: ansi2html
48
52
  Requires-Dist: lxml
53
+ Requires-Dist: PySide6
49
54
  Dynamic: license-file
50
55
 
51
56
  pydifftools
@@ -106,10 +111,32 @@ included are (listed in order of fun/utility):
106
111
  ``_build``/``_display`` directories; with ``--watch`` it starts the HTTP
107
112
  server and automatically rebuilds the staged fragments whenever you edit
108
113
  a ``.qmd`` file.
109
- - `pydifft gd [git diff args...]` shows the same Qt review table as the old
114
+ - ``pydifft tree`` (or ``git tree`` with the alias installed) opens the last
115
+ 40 commits across all branches, in Git date order. Use the down arrow
116
+ below the history to add the next 40 commits. Colors follow
117
+ first-parent ancestry; merged branches join the receiving branch.
118
+ Tags and branch tips have vector icon badges; hashes appear on hover.
119
+ Click any part of a commit row
120
+ to compare with the working directory, or right-click to copy its hash
121
+ or set a commit as the comparison endpoint. The right-click menu can restore
122
+ the working-directory endpoint. Diff window titles show the equivalent
123
+ arguments, preferring tags, then branch names, then six-character hashes.
124
+ Run ``pydifft tree --install`` to add the matching ``git tree`` alias.
125
+ - ``pydifft gd`` (or ``git gd`` with the alias installed) reviews unstaged
126
+ changes, like bare ``git diff``.
127
+ ``pydifft gd [git diff args...]`` shows the same Qt review table as the old
110
128
  ``git_gd_qt.py`` helper before launching ``git difftool`` for a selected
111
- file. Run ``pydifft gd --install`` to add the matching ``git gd`` alias
112
- to your global git config.
129
+ file.
130
+ Image rows are scored in the background and displayed as normalized
131
+ ``rgb X.X a X.X`` RMS changes; RGB change orders the image rows as scores
132
+ arrive.
133
+ Raster images open in a Qt viewer that aligns the old and new image,
134
+ displays their RGB difference, and uses up/down controls to switch
135
+ among the original, difference, and aligned new image. Images with an
136
+ alpha channel are displayed over a checkerboard; when transparency
137
+ changes, an additional red/blue alpha-difference view is included.
138
+ Run ``pydifft gd --install`` to add the matching ``git gd`` alias to
139
+ your global git config.
113
140
  - `pydifft qmdinit [directory]` scaffolds a new Quarto-style project using
114
141
  the bundled templates and example ``project1`` hierarchy, then downloads
115
142
  MathJax into ``_template/mathjax`` so the builder can run immediately.
@@ -120,12 +147,20 @@ included are (listed in order of fun/utility):
120
147
  wrapping, ideal for when you are
121
148
  working on manuscripts that you
122
149
  are version tracking with git.
150
+ Headers, fenced code blocks, and Pandoc tables retain their formatting.
151
+ Display-math delimiters get their own lines while equation contents retain
152
+ their wrapping; inline-math boundaries are preferred places to wrap prose.
123
153
  - `pydifft wmatch` ("whitespace match"): a script that matches whitespace between two text files.
124
154
 
125
155
  * pandoc can convert between markdown/latex/word, but doing this messes with your whitespace and gvimdiff comparisons.
126
156
 
127
157
  * this allows you to use an original file with good whitespace formatting as a "template" that you can match other (e.g. pandoc converted file) onto another
128
158
 
159
+ * changed prose lines exceeding 1.5 times the nearby reference width are
160
+ wrapped using the same sentence and punctuation rules as ``wr``.
161
+ Existing surrounding line breaks are retained; the fallback width is
162
+ 80 columns when the reference provides too little prose.
163
+
129
164
  - `pydifft wd` ("word diff"): generate "track changes" word files starting from pandoc markdown in a git history. Assuming that you have copied diff-doc.js (copied + licensed from elsewhere) into your home directory, this will use pandoc to convert the markdown files to MS Word, then use the MS Word comparison tool to generate a document where all relevant changes are shown with "track changes."
130
165
 
131
166
  * by default, this uses the file `template.docx` in the current directory as a pandoc word template
@@ -56,10 +56,32 @@ included are (listed in order of fun/utility):
56
56
  ``_build``/``_display`` directories; with ``--watch`` it starts the HTTP
57
57
  server and automatically rebuilds the staged fragments whenever you edit
58
58
  a ``.qmd`` file.
59
- - `pydifft gd [git diff args...]` shows the same Qt review table as the old
59
+ - ``pydifft tree`` (or ``git tree`` with the alias installed) opens the last
60
+ 40 commits across all branches, in Git date order. Use the down arrow
61
+ below the history to add the next 40 commits. Colors follow
62
+ first-parent ancestry; merged branches join the receiving branch.
63
+ Tags and branch tips have vector icon badges; hashes appear on hover.
64
+ Click any part of a commit row
65
+ to compare with the working directory, or right-click to copy its hash
66
+ or set a commit as the comparison endpoint. The right-click menu can restore
67
+ the working-directory endpoint. Diff window titles show the equivalent
68
+ arguments, preferring tags, then branch names, then six-character hashes.
69
+ Run ``pydifft tree --install`` to add the matching ``git tree`` alias.
70
+ - ``pydifft gd`` (or ``git gd`` with the alias installed) reviews unstaged
71
+ changes, like bare ``git diff``.
72
+ ``pydifft gd [git diff args...]`` shows the same Qt review table as the old
60
73
  ``git_gd_qt.py`` helper before launching ``git difftool`` for a selected
61
- file. Run ``pydifft gd --install`` to add the matching ``git gd`` alias
62
- to your global git config.
74
+ file.
75
+ Image rows are scored in the background and displayed as normalized
76
+ ``rgb X.X a X.X`` RMS changes; RGB change orders the image rows as scores
77
+ arrive.
78
+ Raster images open in a Qt viewer that aligns the old and new image,
79
+ displays their RGB difference, and uses up/down controls to switch
80
+ among the original, difference, and aligned new image. Images with an
81
+ alpha channel are displayed over a checkerboard; when transparency
82
+ changes, an additional red/blue alpha-difference view is included.
83
+ Run ``pydifft gd --install`` to add the matching ``git gd`` alias to
84
+ your global git config.
63
85
  - `pydifft qmdinit [directory]` scaffolds a new Quarto-style project using
64
86
  the bundled templates and example ``project1`` hierarchy, then downloads
65
87
  MathJax into ``_template/mathjax`` so the builder can run immediately.
@@ -70,12 +92,20 @@ included are (listed in order of fun/utility):
70
92
  wrapping, ideal for when you are
71
93
  working on manuscripts that you
72
94
  are version tracking with git.
95
+ Headers, fenced code blocks, and Pandoc tables retain their formatting.
96
+ Display-math delimiters get their own lines while equation contents retain
97
+ their wrapping; inline-math boundaries are preferred places to wrap prose.
73
98
  - `pydifft wmatch` ("whitespace match"): a script that matches whitespace between two text files.
74
99
 
75
100
  * pandoc can convert between markdown/latex/word, but doing this messes with your whitespace and gvimdiff comparisons.
76
101
 
77
102
  * this allows you to use an original file with good whitespace formatting as a "template" that you can match other (e.g. pandoc converted file) onto another
78
103
 
104
+ * changed prose lines exceeding 1.5 times the nearby reference width are
105
+ wrapped using the same sentence and punctuation rules as ``wr``.
106
+ Existing surrounding line breaks are retained; the fallback width is
107
+ 80 columns when the reference provides too little prose.
108
+
79
109
  - `pydifft wd` ("word diff"): generate "track changes" word files starting from pandoc markdown in a git history. Assuming that you have copied diff-doc.js (copied + licensed from elsewhere) into your home directory, this will use pandoc to convert the markdown files to MS Word, then use the MS Word comparison tool to generate a document where all relevant changes are shown with "track changes."
80
110
 
81
111
  * by default, this uses the file `template.docx` in the current directory as a pandoc word template
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyDiffTools
3
- Version: 0.1.28
3
+ Version: 0.1.30
4
4
  Summary: Diff tools
5
5
  Author: J M Franck
6
6
  License: Copyright (c) 2015, jmfranck
@@ -34,6 +34,8 @@ License: Copyright (c) 2015, jmfranck
34
34
 
35
35
  Description-Content-Type: text/x-rst
36
36
  License-File: LICENSE.md
37
+ Requires-Dist: numpy
38
+ Requires-Dist: Pillow
37
39
  Requires-Dist: selenium
38
40
  Requires-Dist: fuzzywuzzy[speedup]
39
41
  Requires-Dist: PyYAML>=6.0
@@ -41,11 +43,14 @@ Requires-Dist: watchdog
41
43
  Requires-Dist: pydot
42
44
  Requires-Dist: python-dateutil
43
45
  Requires-Dist: jinja2
46
+ Requires-Dist: ipykernel
47
+ Requires-Dist: matplotlib
44
48
  Requires-Dist: nbformat
45
49
  Requires-Dist: nbconvert
46
50
  Requires-Dist: pygments
47
51
  Requires-Dist: ansi2html
48
52
  Requires-Dist: lxml
53
+ Requires-Dist: PySide6
49
54
  Dynamic: license-file
50
55
 
51
56
  pydifftools
@@ -106,10 +111,32 @@ included are (listed in order of fun/utility):
106
111
  ``_build``/``_display`` directories; with ``--watch`` it starts the HTTP
107
112
  server and automatically rebuilds the staged fragments whenever you edit
108
113
  a ``.qmd`` file.
109
- - `pydifft gd [git diff args...]` shows the same Qt review table as the old
114
+ - ``pydifft tree`` (or ``git tree`` with the alias installed) opens the last
115
+ 40 commits across all branches, in Git date order. Use the down arrow
116
+ below the history to add the next 40 commits. Colors follow
117
+ first-parent ancestry; merged branches join the receiving branch.
118
+ Tags and branch tips have vector icon badges; hashes appear on hover.
119
+ Click any part of a commit row
120
+ to compare with the working directory, or right-click to copy its hash
121
+ or set a commit as the comparison endpoint. The right-click menu can restore
122
+ the working-directory endpoint. Diff window titles show the equivalent
123
+ arguments, preferring tags, then branch names, then six-character hashes.
124
+ Run ``pydifft tree --install`` to add the matching ``git tree`` alias.
125
+ - ``pydifft gd`` (or ``git gd`` with the alias installed) reviews unstaged
126
+ changes, like bare ``git diff``.
127
+ ``pydifft gd [git diff args...]`` shows the same Qt review table as the old
110
128
  ``git_gd_qt.py`` helper before launching ``git difftool`` for a selected
111
- file. Run ``pydifft gd --install`` to add the matching ``git gd`` alias
112
- to your global git config.
129
+ file.
130
+ Image rows are scored in the background and displayed as normalized
131
+ ``rgb X.X a X.X`` RMS changes; RGB change orders the image rows as scores
132
+ arrive.
133
+ Raster images open in a Qt viewer that aligns the old and new image,
134
+ displays their RGB difference, and uses up/down controls to switch
135
+ among the original, difference, and aligned new image. Images with an
136
+ alpha channel are displayed over a checkerboard; when transparency
137
+ changes, an additional red/blue alpha-difference view is included.
138
+ Run ``pydifft gd --install`` to add the matching ``git gd`` alias to
139
+ your global git config.
113
140
  - `pydifft qmdinit [directory]` scaffolds a new Quarto-style project using
114
141
  the bundled templates and example ``project1`` hierarchy, then downloads
115
142
  MathJax into ``_template/mathjax`` so the builder can run immediately.
@@ -120,12 +147,20 @@ included are (listed in order of fun/utility):
120
147
  wrapping, ideal for when you are
121
148
  working on manuscripts that you
122
149
  are version tracking with git.
150
+ Headers, fenced code blocks, and Pandoc tables retain their formatting.
151
+ Display-math delimiters get their own lines while equation contents retain
152
+ their wrapping; inline-math boundaries are preferred places to wrap prose.
123
153
  - `pydifft wmatch` ("whitespace match"): a script that matches whitespace between two text files.
124
154
 
125
155
  * pandoc can convert between markdown/latex/word, but doing this messes with your whitespace and gvimdiff comparisons.
126
156
 
127
157
  * this allows you to use an original file with good whitespace formatting as a "template" that you can match other (e.g. pandoc converted file) onto another
128
158
 
159
+ * changed prose lines exceeding 1.5 times the nearby reference width are
160
+ wrapped using the same sentence and punctuation rules as ``wr``.
161
+ Existing surrounding line breaks are retained; the fallback width is
162
+ 80 columns when the reference provides too little prose.
163
+
129
164
  - `pydifft wd` ("word diff"): generate "track changes" word files starting from pandoc markdown in a git history. Assuming that you have copied diff-doc.js (copied + licensed from elsewhere) into your home directory, this will use pandoc to convert the markdown files to MS Word, then use the MS Word comparison tool to generate a document where all relevant changes are shown with "track changes."
130
165
 
131
166
  * by default, this uses the file `template.docx` in the current directory as a pandoc word template
@@ -59,7 +59,10 @@ pydifftools/continuous.py
59
59
  pydifftools/copy_files.py
60
60
  pydifftools/diff-doc.js
61
61
  pydifftools/doc_contents.py
62
+ pydifftools/forward_search.py
62
63
  pydifftools/git_gd.py
64
+ pydifftools/git_gd_history.py
65
+ pydifftools/git_gd_image.py
63
66
  pydifftools/git_gd_qt.py
64
67
  pydifftools/html_comments.py
65
68
  pydifftools/html_uncomments.py
@@ -81,11 +84,19 @@ pydifftools/flowchart/dot_to_yaml.py
81
84
  pydifftools/flowchart/graph.py
82
85
  pydifftools/flowchart/watch_graph.py
83
86
  pydifftools/notebook/__init__.py
87
+ pydifftools/notebook/display.py
84
88
  pydifftools/notebook/fast_build.py
85
89
  pydifftools/notebook/tex_to_qmd.py
86
90
  tests/test_browser_lifecycle.py
91
+ tests/test_check_single_use.py
87
92
  tests/test_command_line_help.py
88
93
  tests/test_continuous_shutdown.py
94
+ tests/test_forward_search.py
95
+ tests/test_git_gd_history.py
96
+ tests/test_git_gd_image.py
97
+ tests/test_git_gd_qt.py
89
98
  tests/test_rrng.py
90
99
  tests/test_tex_to_qmd.py
91
- tests/test_update_check.py
100
+ tests/test_update_check.py
101
+ tests/test_wrap_check.py
102
+ tests/test_wrapping.py
@@ -1,3 +1,5 @@
1
+ numpy
2
+ Pillow
1
3
  selenium
2
4
  fuzzywuzzy[speedup]
3
5
  PyYAML>=6.0
@@ -5,8 +7,11 @@ watchdog
5
7
  pydot
6
8
  python-dateutil
7
9
  jinja2
10
+ ipykernel
11
+ matplotlib
8
12
  nbformat
9
13
  nbconvert
10
14
  pygments
11
15
  ansi2html
12
16
  lxml
17
+ PySide6
@@ -10,7 +10,6 @@ import re
10
10
  import nbformat
11
11
  import difflib
12
12
  import shutil
13
- import socket
14
13
  import importlib.util
15
14
  from pathlib import Path
16
15
  from . import (
@@ -20,7 +19,15 @@ from . import (
20
19
  update_check,
21
20
  )
22
21
  from .continuous import cpb, FORWARD_SEARCH_HOST, FORWARD_SEARCH_PORT
22
+ from .forward_search import (
23
+ ForwardSearchProtocolError,
24
+ ForwardSearchUnavailable,
25
+ send_forward_search,
26
+ )
23
27
  from .wrap_sentences import wr as wrap_sentences_wr # registers wrap command
28
+ from .wrap_sentences import ( # registers wrchk command
29
+ wrchk as wrap_sentences_wrchk,
30
+ )
24
31
  from .separate_comments import tex_sepcomments
25
32
  from .unseparate_comments import tex_unsepcomments
26
33
  from .comment_functions import matchingbrackets
@@ -356,7 +363,10 @@ def gvr(arguments):
356
363
  subprocess.Popen(" ".join(cmd))
357
364
 
358
365
 
359
- @register_command("match whitespace")
366
+ @register_command(
367
+ "match whitespace",
368
+ filename_extensions={"arguments": [".md", ".tex"]},
369
+ )
360
370
  def wmatch(arguments):
361
371
  match_spaces.run(arguments)
362
372
 
@@ -530,7 +540,21 @@ def mfs(text):
530
540
  if marker_match:
531
541
  search_text = search_text[: marker_match.start()]
532
542
  search_text = re.sub(r"\[@[^\]]+\]", " ", search_text)
533
- search_text = search_text.replace("**", " ").replace("*", " ")
543
+ # Strip paired markup delimiters (bold/italic, strikethrough,
544
+ # superscript/subscript). These delimiters hug the text they wrap with no
545
+ # space in the rendered output (e.g. "x^2^" renders as "x2"), so they are
546
+ # dropped rather than replaced with a space. Plain str.replace is used
547
+ # (not regex) so this is linear time regardless of how many delimiter
548
+ # characters appear.
549
+ search_text = (
550
+ search_text.replace("**", "")
551
+ .replace("__", "")
552
+ .replace("~~", "")
553
+ .replace("*", "")
554
+ .replace("_", "")
555
+ .replace("~", "")
556
+ .replace("^", "")
557
+ )
534
558
  search_text = re.sub(r"\s+", " ", search_text).strip()
535
559
  if not search_text:
536
560
  search_text = text.strip()
@@ -540,16 +564,27 @@ def mfs(text):
540
564
  (FORWARD_SEARCH_HOST, FORWARD_SEARCH_PORT),
541
565
  (QMDB_FORWARD_SEARCH_HOST, QMDB_FORWARD_SEARCH_PORT),
542
566
  ]
543
- client = None
544
- for address in socket_addresses:
545
- candidate = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
546
- try:
547
- candidate.connect(address)
548
- client = candidate
549
- break
550
- except OSError:
551
- candidate.close()
552
- if client is None:
567
+
568
+ def try_existing_listener():
569
+ protocol_errors = []
570
+ for address in socket_addresses:
571
+ try:
572
+ send_forward_search(address, search_text)
573
+ except ForwardSearchUnavailable:
574
+ continue
575
+ except ForwardSearchProtocolError as exc:
576
+ protocol_errors.append(str(exc))
577
+ continue
578
+ return True
579
+ if protocol_errors:
580
+ raise RuntimeError(
581
+ "A forward-search port accepted the connection but did not "
582
+ "acknowledge the pydifft protocol. Refusing to open another "
583
+ "browser window.\n" + "\n".join(protocol_errors)
584
+ )
585
+ return False
586
+
587
+ if not try_existing_listener():
553
588
  # If no listener is running yet, choose a markdown file in this
554
589
  # directory that contains the requested search text and start cpb for
555
590
  # it.
@@ -581,24 +616,14 @@ def mfs(text):
581
616
  # Wait up to 20 seconds so the child can bring up the listener,
582
617
  # then resend the forward-search text.
583
618
  for _ in range(80):
584
- for address in socket_addresses:
585
- candidate = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
586
- try:
587
- candidate.connect(address)
588
- client = candidate
589
- break
590
- except OSError:
591
- candidate.close()
592
- if client is not None:
593
- break
619
+ if try_existing_listener():
620
+ return
594
621
  time.sleep(0.25)
595
622
  else:
596
623
  raise RuntimeError(
597
- "Started cpb automatically, but the forward search socket "
598
- "did not come up within 20 seconds."
624
+ "Started cpb automatically, but no acknowledged forward "
625
+ "search endpoint came up within 20 seconds."
599
626
  )
600
- client.sendall(search_text.encode("utf-8"))
601
- client.close()
602
627
 
603
628
 
604
629
  @register_command("Convert xml to xlsx")
@@ -943,11 +968,82 @@ def main(argv=None):
943
968
  "argument --no-comments: not allowed with argument "
944
969
  "--comments-to-margin"
945
970
  )
971
+ if (
972
+ namespace.command == "qmdb"
973
+ and namespace.always_code
974
+ and namespace.no_code
975
+ ):
976
+ parser._pydifft_subparsers["qmdb"].error(
977
+ "argument --no-code: not allowed with argument --always-code"
978
+ )
946
979
  handler = namespace._handler
947
980
  handler_kwargs = dict(vars(namespace))
948
981
  handler_kwargs.pop("_handler", None)
949
982
  handler_kwargs.pop("command", None)
950
- handler(**handler_kwargs)
983
+ # {{{ explain Chrome and ChromeDriver version mismatches
984
+ from selenium.common.exceptions import SessionNotCreatedException
985
+
986
+ try:
987
+ handler(**handler_kwargs)
988
+ except SessionNotCreatedException as exc:
989
+ details = str(exc)
990
+ driver_match = re.search(
991
+ r"ChromeDriver only supports Chrome version (\d+)",
992
+ details,
993
+ )
994
+ browser_match = re.search(
995
+ r"Current browser version is (\d+)",
996
+ details,
997
+ )
998
+ if driver_match is None or browser_match is None:
999
+ raise
1000
+
1001
+ driver_major = int(driver_match.group(1))
1002
+ browser_major = int(browser_match.group(1))
1003
+ print(
1004
+ "pydifft: Chrome could not start because ChromeDriver "
1005
+ f"{driver_major} and Chrome {browser_major} do not match.",
1006
+ file=sys.stderr,
1007
+ )
1008
+ if shutil.which("apt-get") is not None:
1009
+ if browser_major < driver_major:
1010
+ binary_match = re.search(
1011
+ r"binary path ([^;\n]+)",
1012
+ details,
1013
+ )
1014
+ browser_binary = (
1015
+ binary_match.group(1) if binary_match is not None else ""
1016
+ )
1017
+ browser_package = (
1018
+ "chromium"
1019
+ if "chromium" in browser_binary
1020
+ else "google-chrome-stable"
1021
+ )
1022
+ packages = browser_package
1023
+ elif driver_major < browser_major:
1024
+ packages = "chromium-driver"
1025
+ else:
1026
+ packages = "google-chrome-stable chromium-driver"
1027
+ print(
1028
+ "Update the older system package:\n"
1029
+ " sudo apt update\n"
1030
+ f" sudo apt install --only-upgrade {packages}",
1031
+ file=sys.stderr,
1032
+ )
1033
+ else:
1034
+ print(
1035
+ "Update the older Chrome or ChromeDriver installation so "
1036
+ "their major versions match.",
1037
+ file=sys.stderr,
1038
+ )
1039
+ print(
1040
+ "Then retry. You can verify the versions with:\n"
1041
+ " google-chrome --version\n"
1042
+ " chromedriver --version",
1043
+ file=sys.stderr,
1044
+ )
1045
+ raise SystemExit(1) from None
1046
+ # }}}
951
1047
 
952
1048
 
953
1049
  if __name__ == "__main__":