chgksuite 0.27.0__tar.gz → 0.27.0b3__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 (245) hide show
  1. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/PKG-INFO +8 -6
  2. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/cli.py +0 -9
  3. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/common.py +3 -2
  4. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/__init__.py +7 -9
  5. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/chgksuite_parser.py +7 -16
  6. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/db.py +2 -1
  7. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/docx.py +1 -1
  8. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/latex.py +2 -1
  9. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/lj.py +2 -1
  10. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/openquiz.py +2 -1
  11. chgksuite-0.27.0/chgksuite/composer/markdown.py → chgksuite-0.27.0b3/chgksuite/composer/reddit.py +25 -35
  12. chgksuite-0.27.0b3/chgksuite/handouter/runner.py +243 -0
  13. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/tex_internals.py +2 -12
  14. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/parser.py +24 -26
  15. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/parser_db.py +2 -1
  16. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/trello.py +8 -7
  17. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/typotools.py +4 -4
  18. chgksuite-0.27.0b3/chgksuite/version.py +1 -0
  19. chgksuite-0.27.0b3/chgksuite.egg-info/PKG-INFO +40 -0
  20. chgksuite-0.27.0b3/chgksuite.egg-info/SOURCES.txt +67 -0
  21. chgksuite-0.27.0b3/chgksuite.egg-info/dependency_links.txt +1 -0
  22. chgksuite-0.27.0b3/chgksuite.egg-info/entry_points.txt +2 -0
  23. chgksuite-0.27.0b3/chgksuite.egg-info/requires.txt +19 -0
  24. chgksuite-0.27.0b3/chgksuite.egg-info/top_level.txt +1 -0
  25. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/history.md +1 -2
  26. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/pyproject.toml +17 -6
  27. chgksuite-0.27.0b3/setup.cfg +4 -0
  28. chgksuite-0.27.0/.github/workflows/build.yml +0 -291
  29. chgksuite-0.27.0/.gitignore +0 -10
  30. chgksuite-0.27.0/.gitlab-ci.yml +0 -17
  31. chgksuite-0.27.0/.hgignore +0 -2
  32. chgksuite-0.27.0/.~lock.results.xlsx# +0 -1
  33. chgksuite-0.27.0/adhoc/regexes_fixer.py +0 -66
  34. chgksuite-0.27.0/author_counter.py +0 -24
  35. chgksuite-0.27.0/chgksuite/_html2md.py +0 -90
  36. chgksuite-0.27.0/chgksuite/handouter/runner.py +0 -461
  37. chgksuite-0.27.0/chgksuite/lastdir +0 -1
  38. chgksuite-0.27.0/chgksuite/version.py +0 -1
  39. chgksuite-0.27.0/debug_0.txt +0 -3
  40. chgksuite-0.27.0/debug_1.json +0 -10
  41. chgksuite-0.27.0/debug_1a.json +0 -10
  42. chgksuite-0.27.0/debug_2.json +0 -10
  43. chgksuite-0.27.0/debug_3.json +0 -10
  44. chgksuite-0.27.0/debug_4.json +0 -14
  45. chgksuite-0.27.0/debug_5.json +0 -14
  46. chgksuite-0.27.0/debug_6.json +0 -10
  47. chgksuite-0.27.0/debug_final.json +0 -10
  48. chgksuite-0.27.0/dev_readme.md +0 -25
  49. chgksuite-0.27.0/docs/.cache/.gitignore +0 -1
  50. chgksuite-0.27.0/docs/.cache/12897346880794287463 +0 -43
  51. chgksuite-0.27.0/docs/.cache/13071136909783630831 +0 -27
  52. chgksuite-0.27.0/docs/.cache/13307108790744403429 +0 -58
  53. chgksuite-0.27.0/docs/.cache/13333983167045209281 +0 -27
  54. chgksuite-0.27.0/docs/.cache/14085495286103177657 +0 -4
  55. chgksuite-0.27.0/docs/.cache/15213489598760314030 +0 -149
  56. chgksuite-0.27.0/docs/.cache/15319492834190874243 +0 -4
  57. chgksuite-0.27.0/docs/.cache/17387058097034297385 +0 -4
  58. chgksuite-0.27.0/docs/.cache/17722115158263369208 +0 -4
  59. chgksuite-0.27.0/docs/.cache/18247088324849079572 +0 -4
  60. chgksuite-0.27.0/docs/.cache/1840587404175770520 +0 -43
  61. chgksuite-0.27.0/docs/.cache/2517734129797249711 +0 -4
  62. chgksuite-0.27.0/docs/.cache/273431981325847810 +0 -164
  63. chgksuite-0.27.0/docs/.cache/2872065536916780406 +0 -27
  64. chgksuite-0.27.0/docs/.cache/3476900567878811119 +0 -4
  65. chgksuite-0.27.0/docs/.cache/4757258273854424423 +0 -58
  66. chgksuite-0.27.0/docs/.cache/5728722062471071239 +0 -58
  67. chgksuite-0.27.0/docs/.cache/6061198691539556612 +0 -4
  68. chgksuite-0.27.0/docs/.cache/6079179394456200124 +0 -4
  69. chgksuite-0.27.0/docs/.cache/735877668610100612 +0 -73
  70. chgksuite-0.27.0/docs/.cache/9345880734637750342 +0 -4
  71. chgksuite-0.27.0/docs/.cache/9490951945832949972 +0 -4
  72. chgksuite-0.27.0/docs/docs/4s.md +0 -229
  73. chgksuite-0.27.0/docs/docs/add_stats.md +0 -9
  74. chgksuite-0.27.0/docs/docs/base.md +0 -43
  75. chgksuite-0.27.0/docs/docs/i14n.md +0 -31
  76. chgksuite-0.27.0/docs/docs/images/base.png +0 -0
  77. chgksuite-0.27.0/docs/docs/images/douplet_problem.png +0 -0
  78. chgksuite-0.27.0/docs/docs/images/i14n.png +0 -0
  79. chgksuite-0.27.0/docs/docs/images/i14n_parse.png +0 -0
  80. chgksuite-0.27.0/docs/docs/images/lj.png +0 -0
  81. chgksuite-0.27.0/docs/docs/images/main.png +0 -0
  82. chgksuite-0.27.0/docs/docs/images/openquiz.png +0 -0
  83. chgksuite-0.27.0/docs/docs/images/openquiz2.png +0 -0
  84. chgksuite-0.27.0/docs/docs/images/parse.png +0 -0
  85. chgksuite-0.27.0/docs/docs/images/pptx.png +0 -0
  86. chgksuite-0.27.0/docs/docs/images/pptx_additional_conf.png +0 -0
  87. chgksuite-0.27.0/docs/docs/images/pptx_slide_a.png +0 -0
  88. chgksuite-0.27.0/docs/docs/images/pptx_slide_q.png +0 -0
  89. chgksuite-0.27.0/docs/docs/images/roenko.png +0 -0
  90. chgksuite-0.27.0/docs/docs/images/rozhdsushkov.png +0 -0
  91. chgksuite-0.27.0/docs/docs/images/stats.png +0 -0
  92. chgksuite-0.27.0/docs/docs/images/telegram.png +0 -0
  93. chgksuite-0.27.0/docs/docs/images/trello_download.png +0 -0
  94. chgksuite-0.27.0/docs/docs/images/trello_token.png +0 -0
  95. chgksuite-0.27.0/docs/docs/images/trello_upload.png +0 -0
  96. chgksuite-0.27.0/docs/docs/images/word.png +0 -0
  97. chgksuite-0.27.0/docs/docs/index.md +0 -59
  98. chgksuite-0.27.0/docs/docs/lj.md +0 -9
  99. chgksuite-0.27.0/docs/docs/openquiz.md +0 -7
  100. chgksuite-0.27.0/docs/docs/pptx.md +0 -66
  101. chgksuite-0.27.0/docs/docs/stylesheets/extra.css +0 -29
  102. chgksuite-0.27.0/docs/docs/telegram.md +0 -46
  103. chgksuite-0.27.0/docs/docs/trello.md +0 -31
  104. chgksuite-0.27.0/docs/docs/word.md +0 -24
  105. chgksuite-0.27.0/docs/mkdocs.yml +0 -35
  106. chgksuite-0.27.0/hook-dateparser.py +0 -12
  107. chgksuite-0.27.0/packer.py +0 -172
  108. chgksuite-0.27.0/pytest.ini +0 -5
  109. chgksuite-0.27.0/pytest.sh +0 -7
  110. chgksuite-0.27.0/re_helper.py +0 -24
  111. chgksuite-0.27.0/requirements_dev.txt +0 -2
  112. chgksuite-0.27.0/results.xlsx +0 -0
  113. chgksuite-0.27.0/ruff.toml +0 -2
  114. chgksuite-0.27.0/test_multiple_images.txt +0 -3
  115. chgksuite-0.27.0/test_oschr/404.jpg +0 -0
  116. chgksuite-0.27.0/test_oschr/Arhipova_Shtirlic-shel-po-koridoru-.803300.pdf/stirlitz_was_walking.fbd +0 -525
  117. chgksuite-0.27.0/test_oschr/Arhipova_Shtirlic-shel-po-koridoru-.803300.pdf/stirlitz_was_walking.pdf +0 -0
  118. chgksuite-0.27.0/test_oschr/alexeeva.jpeg +0 -0
  119. chgksuite-0.27.0/test_oschr/arhipova.txt +0 -1030
  120. chgksuite-0.27.0/test_oschr/ber.png +0 -0
  121. chgksuite-0.27.0/test_oschr/columns.txt +0 -35
  122. chgksuite-0.27.0/test_oschr/columns_ru.pdf +0 -0
  123. chgksuite-0.27.0/test_oschr/cool.pdf +0 -0
  124. chgksuite-0.27.0/test_oschr/cool.png +0 -0
  125. chgksuite-0.27.0/test_oschr/dish.png +0 -0
  126. chgksuite-0.27.0/test_oschr/dubinki.png +0 -0
  127. chgksuite-0.27.0/test_oschr/duran01.jpg +0 -0
  128. chgksuite-0.27.0/test_oschr/duran02.jpg +0 -0
  129. chgksuite-0.27.0/test_oschr/duran03.jpg +0 -0
  130. chgksuite-0.27.0/test_oschr/duran04.jpg +0 -0
  131. chgksuite-0.27.0/test_oschr/duran05.jpg +0 -0
  132. chgksuite-0.27.0/test_oschr/duran06.jpg +0 -0
  133. chgksuite-0.27.0/test_oschr/duran07.jpg +0 -0
  134. chgksuite-0.27.0/test_oschr/duran08.jpg +0 -0
  135. chgksuite-0.27.0/test_oschr/duran09.jpg +0 -0
  136. chgksuite-0.27.0/test_oschr/duran10.jpg +0 -0
  137. chgksuite-0.27.0/test_oschr/eisenhower.png +0 -0
  138. chgksuite-0.27.0/test_oschr/emo.pdf +0 -0
  139. chgksuite-0.27.0/test_oschr/emo.png +0 -0
  140. chgksuite-0.27.0/test_oschr/emosong.png +0 -0
  141. chgksuite-0.27.0/test_oschr/emosong1.png +0 -0
  142. chgksuite-0.27.0/test_oschr/emosong2.png +0 -0
  143. chgksuite-0.27.0/test_oschr/handouts_test.txt +0 -30
  144. chgksuite-0.27.0/test_oschr/handouts_test_ru.tex +0 -296
  145. chgksuite-0.27.0/test_oschr/karikatura_razdatka.png +0 -0
  146. chgksuite-0.27.0/test_oschr/kuzmin-tat.png +0 -0
  147. chgksuite-0.27.0/test_oschr/kuzmin.txt +0 -13242
  148. chgksuite-0.27.0/test_oschr/otbor_studchr.txt +0 -79
  149. chgksuite-0.27.0/test_oschr/otbor_studchr_handouts.txt +0 -16
  150. chgksuite-0.27.0/test_oschr/otbor_studchr_handouts_ru.pdf +0 -0
  151. chgksuite-0.27.0/test_oschr/panchenko.txt +0 -23670
  152. chgksuite-0.27.0/test_oschr/zine.png +0 -0
  153. chgksuite-0.27.0/test_with_image.txt +0 -3
  154. chgksuite-0.27.0/test_with_real_image.txt +0 -3
  155. chgksuite-0.27.0/tests/2019-07-23_beln19_u.docx +0 -0
  156. chgksuite-0.27.0/tests/2019-07-23_beln19_u.docx.canon +0 -690
  157. chgksuite-0.27.0/tests/Kubok_knyagini_Olgi-2015.docx +0 -0
  158. chgksuite-0.27.0/tests/Kubok_knyagini_Olgi-2015.docx.canon +0 -644
  159. chgksuite-0.27.0/tests/Shkolny_Chemp_Estonii-2014_(48v).docx +0 -0
  160. chgksuite-0.27.0/tests/Shkolny_Chemp_Estonii-2014_(48v).docx.canon +0 -361
  161. chgksuite-0.27.0/tests/__init__.py +0 -0
  162. chgksuite-0.27.0/tests/balt09-1.txt +0 -783
  163. chgksuite-0.27.0/tests/balt09-1.txt.canon +0 -286
  164. chgksuite-0.27.0/tests/borromeo.txt +0 -11
  165. chgksuite-0.27.0/tests/borromeo.txt.canon +0 -16
  166. chgksuite-0.27.0/tests/canonize.py +0 -69
  167. chgksuite-0.27.0/tests/chgksuite_test.py +0 -364
  168. chgksuite-0.27.0/tests/conftest.py +0 -21
  169. chgksuite-0.27.0/tests/encrypt_test_files.py +0 -147
  170. chgksuite-0.27.0/tests/haifa2025.docx +0 -0
  171. chgksuite-0.27.0/tests/haifa2025.docx.canon +0 -349
  172. chgksuite-0.27.0/tests/haifa2025.docx.encrypted +0 -0
  173. chgksuite-0.27.0/tests/haifa2025.docx.encrypted.canon +0 -0
  174. chgksuite-0.27.0/tests/link_unwrap.docx +0 -0
  175. chgksuite-0.27.0/tests/link_unwrap.docx.canon +0 -10
  176. chgksuite-0.27.0/tests/ljcredentials +0 -1
  177. chgksuite-0.27.0/tests/long_handout.png +0 -0
  178. chgksuite-0.27.0/tests/malkin_papkov_synchr.docx +0 -0
  179. chgksuite-0.27.0/tests/malkin_papkov_synchr.docx.canon +0 -99
  180. chgksuite-0.27.0/tests/octo2021_khmelkov.docx +0 -0
  181. chgksuite-0.27.0/tests/octo2021_khmelkov.docx.canon +0 -102
  182. chgksuite-0.27.0/tests/ovsch_boronenko_3.4s +0 -334
  183. chgksuite-0.27.0/tests/ovsch_boronenko_3.docx +0 -0
  184. chgksuite-0.27.0/tests/ovsch_boronenko_3.docx.canon +0 -334
  185. chgksuite-0.27.0/tests/pass1.docx +0 -0
  186. chgksuite-0.27.0/tests/pass1.docx.canon +0 -183
  187. chgksuite-0.27.0/tests/settings.json +0 -3
  188. chgksuite-0.27.0/tests/single_number_line_test.docx +0 -0
  189. chgksuite-0.27.0/tests/single_number_line_test.docx.canon +0 -46
  190. chgksuite-0.27.0/tests/smalltest.4s +0 -6
  191. chgksuite-0.27.0/tests/test.jpg +0 -0
  192. chgksuite-0.27.0/tests/test_blitz.txt +0 -8
  193. chgksuite-0.27.0/tests/test_blitz.txt.canon +0 -9
  194. chgksuite-0.27.0/tests/tourrev_with_razmin.docx +0 -0
  195. chgksuite-0.27.0/tests/tourrev_with_razmin.docx.canon +0 -34
  196. chgksuite-0.27.0/tests//320/241/320/247/320/240_/320/250/320/265/321/200/320/265/320/264/320/265/320/263/320/260_/320/225/321/200/320/274/320/270/321/210/320/272/320/270/320/275.docx +0 -0
  197. chgksuite-0.27.0/tests//320/241/320/247/320/240_/320/250/320/265/321/200/320/265/320/264/320/265/320/263/320/260_/320/225/321/200/320/274/320/270/321/210/320/272/320/270/320/275.docx.canon +0 -13
  198. chgksuite-0.27.0/uv.lock +0 -1454
  199. chgksuite-0.27.0//320/235/320/276/321/207/321/214/320/241/320/276/320/263/321/200/320/265/320/262/320/260/321/216/321/211/320/265/320/263/320/276/320/236/321/207/320/260/320/263/320/2602025_001.jpeg +0 -0
  200. chgksuite-0.27.0//320/235/320/276/321/207/321/214/320/241/320/276/320/263/321/200/320/265/320/262/320/260/321/216/321/211/320/265/320/263/320/276/320/236/321/207/320/260/320/263/320/2602025_with_stats1.4s +0 -373
  201. chgksuite-0.27.0//320/235/320/276/321/207/321/214/320/241/320/276/320/263/321/200/320/265/320/262/320/260/321/216/321/211/320/265/320/263/320/276/320/236/321/207/320/260/320/263/320/2602025_with_stats1.dbg +0 -562
  202. chgksuite-0.27.0//320/235/320/276/321/207/321/214/320/241/320/276/320/263/321/200/320/265/320/262/320/260/321/216/321/211/320/265/320/263/320/276/320/236/321/207/320/260/320/263/320/2602025_with_stats1.docx +0 -0
  203. chgksuite-0.27.0//321/216 +0 -0
  204. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/LICENSE +0 -0
  205. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/MANIFEST.in +0 -0
  206. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/README.md +0 -0
  207. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/__init__.py +0 -0
  208. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/__main__.py +0 -0
  209. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/composer_common.py +0 -0
  210. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/pptx.py +0 -0
  211. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/stats.py +0 -0
  212. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/telegram.py +0 -0
  213. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/telegram_bot.py +0 -0
  214. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/__init__.py +0 -0
  215. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/gen.py +0 -0
  216. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/installer.py +0 -0
  217. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/pack.py +0 -0
  218. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/utils.py +0 -0
  219. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/cheader.tex +0 -0
  220. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/fix-unnumbered-sections.sty +0 -0
  221. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_az.toml +0 -0
  222. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_by.toml +0 -0
  223. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_by_tar.toml +0 -0
  224. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_en.toml +0 -0
  225. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_kz_cyr.toml +0 -0
  226. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_ru.toml +0 -0
  227. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_sr.toml +0 -0
  228. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_ua.toml +0 -0
  229. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_uz.toml +0 -0
  230. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_uz_cyr.toml +0 -0
  231. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/pptx_config.toml +0 -0
  232. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_az.json +0 -0
  233. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_by.json +0 -0
  234. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_by_tar.json +0 -0
  235. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_en.json +0 -0
  236. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_kz_cyr.json +0 -0
  237. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_ru.json +0 -0
  238. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_sr.json +0 -0
  239. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_ua.json +0 -0
  240. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_uz.json +0 -0
  241. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_uz_cyr.json +0 -0
  242. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/template.docx +0 -0
  243. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/template.pptx +0 -0
  244. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/trello.json +0 -0
  245. {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/vulture_whitelist.py +0 -0
@@ -1,21 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chgksuite
3
- Version: 0.27.0
3
+ Version: 0.27.0b3
4
4
  Summary: A package for chgk automation
5
- Project-URL: Homepage, https://gitlab.com/peczony/chgksuite
6
5
  Author-email: Alexander Pecheny <ap@pecheny.me>
7
6
  License-Expression: MIT
8
- License-File: LICENSE
9
- Classifier: Operating System :: OS Independent
7
+ Project-URL: Homepage, https://gitlab.com/peczony/chgksuite
10
8
  Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
11
10
  Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
12
13
  Requires-Dist: beautifulsoup4
13
14
  Requires-Dist: chardet
15
+ Requires-Dist: dashtable
14
16
  Requires-Dist: dateparser
15
17
  Requires-Dist: mammoth
16
18
  Requires-Dist: openpyxl
17
19
  Requires-Dist: parse
18
- Requires-Dist: pillow
20
+ Requires-Dist: Pillow
19
21
  Requires-Dist: ply
20
22
  Requires-Dist: pypandoc
21
23
  Requires-Dist: pypdf
@@ -27,7 +29,7 @@ Requires-Dist: requests
27
29
  Requires-Dist: toml
28
30
  Requires-Dist: urllib3>=2.6.2
29
31
  Requires-Dist: watchdog
30
- Description-Content-Type: text/markdown
32
+ Dynamic: license-file
31
33
 
32
34
  **chgksuite** is an utility that helps chgk editors.
33
35
 
@@ -596,15 +596,6 @@ class ArgparseBuilder:
596
596
  caption="Имя 4s-файла",
597
597
  filetypes=[("chgksuite markup files", "*.4s")],
598
598
  )
599
- cmdcompose_markdown = cmdcompose_filetype.add_parser("markdown")
600
- self.add_argument(
601
- cmdcompose_markdown,
602
- "filename",
603
- nargs="*",
604
- help="file(s) to compose from.",
605
- caption="Имя 4s-файла",
606
- filetypes=[("chgksuite markup files", "*.4s")],
607
- )
608
599
  cmdcompose_pptx = cmdcompose_filetype.add_parser("pptx")
609
600
  self.add_argument(
610
601
  cmdcompose_pptx,
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
3
  import argparse
4
+ import codecs
4
5
  import csv
5
6
  import itertools
6
7
  import json
@@ -113,7 +114,7 @@ class DefaultArgs:
113
114
  def set_lastdir(path):
114
115
  chgksuite_dir = get_chgksuite_dir()
115
116
  lastdir = os.path.join(chgksuite_dir, "lastdir")
116
- with open(lastdir, "w", encoding="utf-8") as f:
117
+ with codecs.open(lastdir, "w", "utf8") as f:
117
118
  f.write(path)
118
119
 
119
120
 
@@ -121,7 +122,7 @@ def get_lastdir():
121
122
  chgksuite_dir = get_chgksuite_dir()
122
123
  lastdir = os.path.join(chgksuite_dir, "lastdir")
123
124
  if os.path.isfile(lastdir):
124
- with open(lastdir, "r", encoding="utf-8") as f:
125
+ with codecs.open(lastdir, "r", "utf8") as f:
125
126
  return f.read().rstrip()
126
127
  return "."
127
128
 
@@ -1,5 +1,6 @@
1
1
  #!usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
+ import codecs
3
4
  import json
4
5
  import os
5
6
  import shutil
@@ -21,7 +22,7 @@ from chgksuite.composer.docx import DocxExporter
21
22
  from chgksuite.composer.latex import LatexExporter
22
23
  from chgksuite.composer.lj import LjExporter
23
24
  from chgksuite.composer.pptx import PptxExporter
24
- from chgksuite.composer.markdown import MarkdownExporter
25
+ from chgksuite.composer.reddit import RedditExporter
25
26
  from chgksuite.composer.stats import StatsAdder
26
27
  from chgksuite.composer.telegram import TelegramExporter
27
28
  from chgksuite.composer.openquiz import OpenquizExporter
@@ -74,13 +75,10 @@ def process_file_wrapper(filename, sourcedir, targetdir, args):
74
75
 
75
76
  def parse_filepath(filepath, args=None):
76
77
  args = args or DefaultArgs()
77
- with open(filepath, "r", encoding="utf-8") as input_file:
78
+ with codecs.open(filepath, "r", "utf8") as input_file:
78
79
  input_text = input_file.read()
79
80
  input_text = input_text.replace("\r", "")
80
- debug_dir = os.path.dirname(os.path.abspath(filepath))
81
- return parse_4s(
82
- input_text, randomize=args.randomize, debug=args.debug, debug_dir=debug_dir
83
- )
81
+ return parse_4s(input_text, randomize=args.randomize, debug=args.debug)
84
82
 
85
83
 
86
84
  def make_merged_filename(filelist):
@@ -107,7 +105,7 @@ def process_file(filename, tmp_dir, targetdir, args=None, logger=None):
107
105
  targetdir,
108
106
  make_filename(os.path.basename(filename), "dbg", args),
109
107
  )
110
- with open(debug_fn, "w", encoding="utf-8") as output_file:
108
+ with codecs.open(debug_fn, "w", "utf8") as output_file:
111
109
  output_file.write(json.dumps(structure, indent=2, ensure_ascii=False))
112
110
 
113
111
  if not args.filetype:
@@ -148,8 +146,8 @@ def process_file(filename, tmp_dir, targetdir, args=None, logger=None):
148
146
  outfilename = os.path.join(targetdir, make_filename(filename, "txt", args))
149
147
  exporter.export(outfilename)
150
148
 
151
- if args.filetype in ("redditmd", "markdown"):
152
- exporter = MarkdownExporter(structure, args, dir_kwargs)
149
+ if args.filetype == "redditmd":
150
+ exporter = RedditExporter(structure, args, dir_kwargs)
153
151
  outfilename = os.path.join(targetdir, make_filename(filename, "md", args))
154
152
  exporter.export(outfilename)
155
153
 
@@ -1,15 +1,9 @@
1
- import os
1
+ import codecs
2
2
  import random
3
3
  import re
4
4
  from collections import defaultdict
5
5
 
6
- from chgksuite.common import (
7
- QUESTION_LABELS,
8
- check_question,
9
- get_chgksuite_dir,
10
- init_logger,
11
- log_wrap,
12
- )
6
+ from chgksuite.common import QUESTION_LABELS, check_question, init_logger, log_wrap
13
7
  from chgksuite.typotools import remove_excessive_whitespace as rew
14
8
 
15
9
  REQUIRED_LABELS = set(["question", "answer"])
@@ -95,7 +89,7 @@ def replace_counters(string_):
95
89
  return string_
96
90
 
97
91
 
98
- def parse_4s(s, randomize=False, debug=False, logger=None, debug_dir=None):
92
+ def parse_4s(s, randomize=False, debug=False, logger=None):
99
93
  logger = logger or init_logger("composer")
100
94
  mapping = {
101
95
  "#": "meta",
@@ -121,11 +115,8 @@ def parse_4s(s, randomize=False, debug=False, logger=None, debug_dir=None):
121
115
  if s[0] == "\ufeff" and len(s) > 1:
122
116
  s = s[1:]
123
117
 
124
- if debug:
125
- debug_dir = debug_dir or get_chgksuite_dir()
126
- debug_path = os.path.join(debug_dir, "raw.debug")
127
- with open(debug_path, "w", encoding="utf-8") as debugf:
128
- debugf.write(log_wrap(s.split("\n")))
118
+ with codecs.open("raw.debug", "w", "utf8") as debugf:
119
+ debugf.write(log_wrap(s.split("\n")))
129
120
 
130
121
  s = replace_counters(s)
131
122
 
@@ -146,7 +137,7 @@ def parse_4s(s, randomize=False, debug=False, logger=None, debug_dir=None):
146
137
  counter = 1
147
138
 
148
139
  if debug:
149
- with open("debug1st.debug", "w", encoding="utf-8") as debugf:
140
+ with codecs.open("debug1st.debug", "w", "utf8") as debugf:
150
141
  debugf.write(log_wrap(structure))
151
142
 
152
143
  for element in structure:
@@ -239,7 +230,7 @@ def parse_4s(s, randomize=False, debug=False, logger=None, debug_dir=None):
239
230
  i += 1
240
231
 
241
232
  if debug:
242
- with open("debug.debug", "w", encoding="utf-8") as debugf:
233
+ with codecs.open("debug.debug", "w", "utf8") as debugf:
243
234
  debugf.write(log_wrap(final_structure))
244
235
 
245
236
  for element in final_structure:
@@ -1,3 +1,4 @@
1
+ import codecs
1
2
  import datetime
2
3
  import os
3
4
  import re
@@ -210,7 +211,7 @@ class DbExporter(BaseExporter):
210
211
  if res:
211
212
  result.append(res)
212
213
  text = "".join(result)
213
- with open(outfilename, "w", encoding="utf-8") as f:
214
+ with codecs.open(outfilename, "w", "utf8") as f:
214
215
  f.write(text)
215
216
  self.logger.info("Output: {}".format(outfilename))
216
217
  if self.args.clipboard:
@@ -102,7 +102,7 @@ def remove_square_brackets_standalone(s, regexes):
102
102
  s = s.replace("\\[", "LEFTSQUAREBRACKET")
103
103
  s = s.replace("\\]", "RIGHTSQUAREBRACKET")
104
104
  # Use placeholder to preserve handout brackets during removal
105
- s = re.sub(f"\\[({hs}.+?)\\]", "{HANDOUT_PLACEHOLDER\\1}", s, flags=re.DOTALL)
105
+ s = re.sub(f"\\[{hs}(.+?)\\]", "{HANDOUT_PLACEHOLDER\\1}", s, flags=re.DOTALL)
106
106
  i = 0
107
107
  while "[" in s and "]" in s and i < 10:
108
108
  s = re.sub(" *\\[.+?\\]", "", s, flags=re.DOTALL)
@@ -1,3 +1,4 @@
1
+ import codecs
1
2
  import hashlib
2
3
  import os
3
4
  import re
@@ -220,7 +221,7 @@ class LatexExporter(BaseExporter):
220
221
 
221
222
  tex += "\\end{document}"
222
223
 
223
- with open(outfilename, "w", encoding="utf-8") as outfile:
224
+ with codecs.open(outfilename, "w", "utf8") as outfile:
224
225
  outfile.write(tex)
225
226
  cwd = os.getcwd()
226
227
  os.chdir(self.dir_kwargs["tmp_dir"])
@@ -1,3 +1,4 @@
1
+ import codecs
1
2
  import datetime
2
3
  import os
3
4
  import random
@@ -239,7 +240,7 @@ class LjExporter(BaseExporter):
239
240
  "general_impressions_text"
240
241
  ]
241
242
  if self.args.debug:
242
- with open("lj.debug", "w", encoding="utf-8") as f:
243
+ with codecs.open("lj.debug", "w", "utf8") as f:
243
244
  f.write(log_wrap(final_structure))
244
245
  return final_structure
245
246
 
@@ -1,3 +1,4 @@
1
+ import codecs
1
2
  import copy
2
3
  import re
3
4
  import json
@@ -174,5 +175,5 @@ class OpenquizExporter(BaseExporter):
174
175
  result = []
175
176
  for q in questions:
176
177
  result.append(self.oq_format_question(q))
177
- with open(outfilename, "w", encoding="utf-8") as f:
178
+ with codecs.open(outfilename, "w", "utf8") as f:
178
179
  f.write(json.dumps(result, indent=2, ensure_ascii=False))
@@ -1,3 +1,4 @@
1
+ import codecs
1
2
  import os
2
3
 
3
4
  from chgksuite.composer.composer_common import (
@@ -8,20 +9,20 @@ from chgksuite.composer.composer_common import (
8
9
  )
9
10
 
10
11
 
11
- class MarkdownExporter(BaseExporter):
12
+ class RedditExporter(BaseExporter):
12
13
  def __init__(self, *args, **kwargs):
13
14
  super().__init__(*args, **kwargs)
14
15
  self.im = Imgur(self.args.imgur_client_id or IMGUR_CLIENT_ID)
15
16
  self.qcount = 1
16
17
 
17
- def markdownyapper(self, e):
18
+ def reddityapper(self, e):
18
19
  if isinstance(e, str):
19
- return self.markdown_element_layout(e)
20
+ return self.reddit_element_layout(e)
20
21
  elif isinstance(e, list):
21
22
  if not any(isinstance(x, list) for x in e):
22
- return self.markdown_element_layout(e)
23
+ return self.reddit_element_layout(e)
23
24
  else:
24
- return " \n".join([self.markdown_element_layout(x) for x in e])
25
+ return " \n".join([self.reddit_element_layout(x) for x in e])
25
26
 
26
27
  def parse_and_upload_image(self, path):
27
28
  parsed_image = parseimg(
@@ -36,13 +37,11 @@ class MarkdownExporter(BaseExporter):
36
37
  imglink = uploaded_image["data"]["link"]
37
38
  return imglink
38
39
 
39
- def markdownformat(self, s):
40
+ def redditformat(self, s):
40
41
  res = ""
41
42
  for run in self.parse_4s_elem(s):
42
- if run[0] == "":
43
+ if run[0] in ("", "hyperlink"):
43
44
  res += run[1]
44
- if run[0] == "hyperlink":
45
- res += "<{}>".format(run[1])
46
45
  if run[0] == "screen":
47
46
  res += run[1]["for_screen"]
48
47
  if run[0] == "italic":
@@ -52,70 +51,61 @@ class MarkdownExporter(BaseExporter):
52
51
  imglink = run[1]
53
52
  else:
54
53
  imglink = self.parse_and_upload_image(run[1])
55
- if self.args.filetype == "redditmd":
56
- res += "[картинка]({})".format(imglink)
57
- else:
58
- res += "![]({})".format(imglink)
54
+ res += "[картинка]({})".format(imglink)
59
55
  while res.endswith("\n"):
60
56
  res = res[:-1]
61
57
  res = res.replace("\n", " \n")
62
58
  return res
63
59
 
64
- def markdown_element_layout(self, e):
60
+ def reddit_element_layout(self, e):
65
61
  res = ""
66
62
  if isinstance(e, str):
67
- res = self.markdownformat(e)
63
+ res = self.redditformat(e)
68
64
  return res
69
65
  if isinstance(e, list):
70
66
  res = " \n".join(
71
67
  [
72
- "{}\\. {}".format(i + 1, self.markdown_element_layout(x))
68
+ "{}\\. {}".format(i + 1, self.reddit_element_layout(x))
73
69
  for i, x in enumerate(e)
74
70
  ]
75
71
  )
76
72
  return res
77
73
 
78
- def markdown_format_element(self, pair):
74
+ def reddit_format_element(self, pair):
79
75
  if pair[0] == "Question":
80
- return self.markdown_format_question(pair[1])
76
+ return self.reddit_format_question(pair[1])
81
77
 
82
- def markdown_format_question(self, q):
78
+ def reddit_format_question(self, q):
83
79
  if "setcounter" in q:
84
80
  self.qcount = int(q["setcounter"])
85
81
  res = "__Вопрос {}__: {} \n".format(
86
82
  self.qcount if "number" not in q else q["number"],
87
- self.markdownyapper(q["question"]),
83
+ self.reddityapper(q["question"]),
88
84
  )
89
85
  if "number" not in q:
90
86
  self.qcount += 1
91
- spoiler_start = ">!" if self.args.filetype == "redditmd" else ""
92
- spoiler_end = "!<" if self.args.filetype == "redditmd" else ""
93
- res += "__Ответ:__ {}{} \n".format(
94
- spoiler_start, self.markdownyapper(q["answer"])
95
- )
87
+ res += "__Ответ:__ >!{} \n".format(self.reddityapper(q["answer"]))
96
88
  if "zachet" in q:
97
- res += "__Зачёт:__ {} \n".format(self.markdownyapper(q["zachet"]))
89
+ res += "__Зачёт:__ {} \n".format(self.reddityapper(q["zachet"]))
98
90
  if "nezachet" in q:
99
- res += "__Незачёт:__ {} \n".format(self.markdownyapper(q["nezachet"]))
91
+ res += "__Незачёт:__ {} \n".format(self.reddityapper(q["nezachet"]))
100
92
  if "comment" in q:
101
- res += "__Комментарий:__ {} \n".format(self.markdownyapper(q["comment"]))
93
+ res += "__Комментарий:__ {} \n".format(self.reddityapper(q["comment"]))
102
94
  if "source" in q:
103
- res += "__Источник:__ {} \n".format(self.markdownyapper(q["source"]))
95
+ res += "__Источник:__ {} \n".format(self.reddityapper(q["source"]))
104
96
  if "author" in q:
105
- res += "{}\n__Автор:__ {} \n".format(
106
- spoiler_end, self.markdownyapper(q["author"])
107
- )
97
+ res += "!<\n__Автор:__ {} \n".format(self.reddityapper(q["author"]))
108
98
  else:
109
- res += spoiler_end + "\n"
99
+ res += "!<\n"
110
100
  return res
111
101
 
112
102
  def export(self, outfile):
113
103
  result = []
114
104
  for pair in self.structure:
115
- res = self.markdown_format_element(pair)
105
+ res = self.reddit_format_element(pair)
116
106
  if res:
117
107
  result.append(res)
118
108
  text = "\n\n".join(result)
119
- with open(outfile, "w", encoding="utf-8") as f:
109
+ with codecs.open(outfile, "w", "utf8") as f:
120
110
  f.write(text)
121
111
  self.logger.info("Output: {}".format(outfile))
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ import os
4
+ import shutil
5
+ import subprocess
6
+ import time
7
+
8
+ import toml
9
+ from watchdog.events import FileSystemEventHandler
10
+ from watchdog.observers import Observer
11
+
12
+ from chgksuite.common import get_source_dirs
13
+ from chgksuite.handouter.gen import generate_handouts
14
+ from chgksuite.handouter.pack import pack_handouts
15
+ from chgksuite.handouter.installer import get_tectonic_path, install_tectonic
16
+ from chgksuite.handouter.tex_internals import (
17
+ GREYTEXT,
18
+ HEADER,
19
+ IMG,
20
+ IMGWIDTH,
21
+ TIKZBOX_END,
22
+ TIKZBOX_INNER,
23
+ TIKZBOX_START,
24
+ )
25
+ from chgksuite.handouter.utils import parse_handouts, read_file, replace_ext, write_file
26
+
27
+
28
+ class HandoutGenerator:
29
+ SPACE = 1.5 # mm
30
+
31
+ def __init__(self, args):
32
+ self.args = args
33
+ _, resourcedir = get_source_dirs()
34
+ self.labels = toml.loads(
35
+ read_file(os.path.join(resourcedir, f"labels_{args.language}.toml"))
36
+ )
37
+ self.blocks = [self.get_header()]
38
+
39
+ def get_header(self):
40
+ header = HEADER
41
+ header = (
42
+ header.replace("<PAPERWIDTH>", str(self.args.paperwidth))
43
+ .replace("<PAPERHEIGHT>", str(self.args.paperheight))
44
+ .replace("<MARGIN_LEFT>", str(self.args.margin_left))
45
+ .replace("<MARGIN_RIGHT>", str(self.args.margin_right))
46
+ .replace("<MARGIN_TOP>", str(self.args.margin_top))
47
+ .replace("<MARGIN_BOTTOM>", str(self.args.margin_bottom))
48
+ .replace("<TIKZ_MM>", str(self.args.tikz_mm))
49
+ )
50
+ if self.args.font:
51
+ header = header.replace("Arial", self.args.font)
52
+ return header
53
+
54
+ def parse_input(self, filepath):
55
+ contents = read_file(filepath)
56
+ return parse_handouts(contents)
57
+
58
+ def generate_for_question(self, question_num):
59
+ handout_text = self.labels["general"]["handout_for_question"].format(
60
+ question_num
61
+ )
62
+ return GREYTEXT.replace("<GREYTEXT>", handout_text)
63
+
64
+ def make_tikzbox(self, block):
65
+ if block.get("no_center"):
66
+ align = ""
67
+ else:
68
+ align = ", align=center"
69
+ textwidth = ", text width=\\boxwidthinner"
70
+ fs = block.get("font_size") or self.args.font_size
71
+ fontsize = "\\fontsize{FSpt}{LHpt}\\selectfont ".replace("FS", str(fs)).replace(
72
+ "LH", str(round(fs * 1.2, 1))
73
+ )
74
+ contents = block["contents"]
75
+ if block.get("font_family"):
76
+ contents = "\\fontspec{" + block["font_family"] + "}" + contents
77
+ return (
78
+ TIKZBOX_INNER.replace("<CONTENTS>", contents)
79
+ .replace("<ALIGN>", align)
80
+ .replace("<TEXTWIDTH>", textwidth)
81
+ .replace("<FONTSIZE>", fontsize)
82
+ )
83
+
84
+ def get_page_width(self):
85
+ return self.args.paperwidth - self.args.margin_left - self.args.margin_right - 2
86
+
87
+ def generate_regular_block(self, block_):
88
+ block = block_.copy()
89
+ if not (block.get("image") or block.get("text")):
90
+ return
91
+ columns = block["columns"]
92
+ spaces = block["columns"] - 1
93
+ boxwidth = self.args.boxwidth or round(
94
+ (self.get_page_width() - spaces * self.SPACE) / block["columns"],
95
+ 3,
96
+ )
97
+ total_width = boxwidth * columns + spaces * self.SPACE
98
+ if self.args.debug:
99
+ print(
100
+ f"columns: {columns}, boxwidth: {boxwidth}, total width: {total_width}"
101
+ )
102
+ boxwidthinner = self.args.boxwidthinner or (boxwidth - 2 * self.args.tikz_mm)
103
+ header = [
104
+ r"\setlength{\boxwidth}{<Q>mm}%".replace("<Q>", str(boxwidth)),
105
+ r"\setlength{\boxwidthinner}{<Q>mm}%".replace("<Q>", str(boxwidthinner)),
106
+ ]
107
+ rows = []
108
+ contents = []
109
+ if block.get("image"):
110
+ img_qwidth = block.get("resize_image") or 1.0
111
+ imgwidth = IMGWIDTH.replace("<QWIDTH>", str(img_qwidth))
112
+ contents.append(
113
+ IMG.replace("<IMGPATH>", block["image"]).replace("<IMGWIDTH>", imgwidth)
114
+ )
115
+ if block.get("text"):
116
+ contents.append(block["text"])
117
+ block["contents"] = "\\linebreak\n".join(contents)
118
+ if block.get("no_center"):
119
+ block["centering"] = ""
120
+ else:
121
+ block["centering"] = "\\centering"
122
+ for _ in range(block.get("rows") or 1):
123
+ row = (
124
+ TIKZBOX_START.replace("<CENTERING>", block["centering"])
125
+ + "\n".join([self.make_tikzbox(block)] * block["columns"])
126
+ + TIKZBOX_END
127
+ )
128
+ rows.append(row)
129
+ return "\n".join(header) + "\n" + "\n\n\\vspace{1mm}\n\n".join(rows)
130
+
131
+ def generate(self):
132
+ for block in self.parse_input(self.args.filename):
133
+ if not block:
134
+ self.blocks.append("\n\\clearpage\n")
135
+ continue
136
+ if self.args.debug:
137
+ print(block)
138
+ if block.get("for_question"):
139
+ self.blocks.append(self.generate_for_question(block["for_question"]))
140
+ if block.get("columns"):
141
+ block = self.generate_regular_block(block)
142
+ if block:
143
+ self.blocks.append(block)
144
+ self.blocks.append("\\end{document}")
145
+ return "\n\n".join(self.blocks)
146
+
147
+
148
+ def process_file(args, file_dir, bn):
149
+ tex_contents = HandoutGenerator(args).generate()
150
+ tex_path = os.path.join(file_dir, f"{bn}_{args.language}.tex")
151
+ write_file(tex_path, tex_contents)
152
+
153
+ tectonic_path = get_tectonic_path()
154
+ if not tectonic_path:
155
+ print("tectonic is not present, installing it...")
156
+ install_tectonic(args)
157
+ tectonic_path = get_tectonic_path()
158
+ if not tectonic_path:
159
+ raise Exception("tectonic couldn't be installed successfully :(")
160
+ if args.debug:
161
+ print(f"tectonic found at `{tectonic_path}`")
162
+
163
+ subprocess.run(
164
+ [tectonic_path, os.path.basename(tex_path)], check=True, cwd=file_dir
165
+ )
166
+
167
+ output_file = replace_ext(tex_path, "pdf")
168
+
169
+ if args.compress:
170
+ print(f"compressing {output_file}")
171
+ size_before = round(os.stat(output_file).st_size / 1024)
172
+ output_file_compressed = output_file[:-4] + ".compressed.pdf"
173
+ subprocess.run(
174
+ [
175
+ "gs",
176
+ "-sDEVICE=pdfwrite",
177
+ "-dCompatibilityLevel=1.5",
178
+ f"-dPDFSETTINGS=/{args.pdfsettings}",
179
+ "-dNOPAUSE",
180
+ "-dQUIET",
181
+ "-dBATCH",
182
+ f"-sOutputFile={output_file_compressed}",
183
+ output_file,
184
+ ],
185
+ check=True,
186
+ )
187
+ shutil.move(output_file_compressed, output_file)
188
+ size_after = round(os.stat(output_file).st_size / 1024)
189
+ q = round(size_after / size_before, 1)
190
+ print(f"before: {size_before}kb, after: {size_after}kb, compression: {q}")
191
+
192
+ print(f"Output file: {output_file}")
193
+
194
+ if not args.debug:
195
+ os.remove(tex_path)
196
+
197
+
198
+ class FileChangeHandler(FileSystemEventHandler):
199
+ def __init__(self, args, file_dir, bn):
200
+ self.args = args
201
+ self.file_dir = file_dir
202
+ self.bn = bn
203
+ self.last_processed = 0
204
+
205
+ def on_modified(self, event):
206
+ if event.src_path == os.path.abspath(self.args.filename):
207
+ # Debounce to avoid processing the same change multiple times
208
+ current_time = time.time()
209
+ if current_time - self.last_processed > 1:
210
+ print(f"File {self.args.filename} changed, regenerating PDF...")
211
+ process_file(self.args, self.file_dir, self.bn)
212
+ self.last_processed = current_time
213
+
214
+
215
+ def run_handouter(args):
216
+ file_dir = os.path.dirname(os.path.abspath(args.filename))
217
+ bn, _ = os.path.splitext(os.path.basename(args.filename))
218
+
219
+ process_file(args, file_dir, bn)
220
+
221
+ if args.watch:
222
+ print(f"Watching {args.filename} for changes. Press Ctrl+C to stop.")
223
+ event_handler = FileChangeHandler(args, file_dir, bn)
224
+ observer = Observer()
225
+ observer.schedule(event_handler, path=file_dir, recursive=False)
226
+ observer.start()
227
+ try:
228
+ while True:
229
+ time.sleep(1)
230
+ except KeyboardInterrupt:
231
+ observer.stop()
232
+ observer.join()
233
+
234
+
235
+ def gui_handouter(args):
236
+ if args.handoutssubcommand == "run":
237
+ run_handouter(args)
238
+ elif args.handoutssubcommand == "generate":
239
+ generate_handouts(args)
240
+ elif args.handoutssubcommand == "pack":
241
+ pack_handouts(args)
242
+ elif args.handoutssubcommand == "install":
243
+ install_tectonic(args)
@@ -13,7 +13,7 @@ HEADER = r"""
13
13
  \begin{document}
14
14
  \fontsize{14pt}{16pt}\selectfont
15
15
  \setlength\parindent{0pt}
16
- \tikzstyle{box}=[rectangle, inner sep=<TIKZ_MM>mm]
16
+ \tikzstyle{box}=[draw, dashed, rectangle, inner sep=<TIKZ_MM>mm]
17
17
  \raggedright
18
18
  \raggedbottom
19
19
  """.strip()
@@ -25,20 +25,10 @@ TIKZBOX_START = r"""{<CENTERING>
25
25
 
26
26
  TIKZBOX_INNER = r"""
27
27
  \begin{tikzpicture}
28
- \node[box, minimum width=\boxwidth<TEXTWIDTH><ALIGN>] (b) {<FONTSIZE><CONTENTS>\par};
29
- \useasboundingbox (b.south west) rectangle (b.north east);
30
- \draw[<TOP>] ([xshift=<TOP_EXT_L>]b.north west) -- ([xshift=<TOP_EXT_R>]b.north east);
31
- \draw[<BOTTOM>] ([xshift=<BOTTOM_EXT_L>]b.south west) -- ([xshift=<BOTTOM_EXT_R>]b.south east);
32
- \draw[<LEFT>] ([yshift=<LEFT_EXT_T>]b.north west) -- ([yshift=<LEFT_EXT_B>]b.south west);
33
- \draw[<RIGHT>] ([yshift=<RIGHT_EXT_T>]b.north east) -- ([yshift=<RIGHT_EXT_B>]b.south east);
28
+ \node[box, minimum width=\boxwidth<TEXTWIDTH><ALIGN>] {<FONTSIZE><CONTENTS>\par};
34
29
  \end{tikzpicture}
35
30
  """.strip()
36
31
 
37
- # Line styles for box edges
38
- EDGE_SOLID = "line width=0.8pt"
39
- EDGE_DASHED = "dashed"
40
- EDGE_NONE = "draw=none" # Don't draw this edge (to avoid double dashed lines)
41
-
42
32
  TIKZBOX_END = "\n}"
43
33
 
44
34
  IMG = r"""\includegraphics<IMGWIDTH>{<IMGPATH>}"""