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.
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/PKG-INFO +8 -6
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/cli.py +0 -9
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/common.py +3 -2
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/__init__.py +7 -9
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/chgksuite_parser.py +7 -16
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/db.py +2 -1
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/docx.py +1 -1
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/latex.py +2 -1
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/lj.py +2 -1
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/openquiz.py +2 -1
- chgksuite-0.27.0/chgksuite/composer/markdown.py → chgksuite-0.27.0b3/chgksuite/composer/reddit.py +25 -35
- chgksuite-0.27.0b3/chgksuite/handouter/runner.py +243 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/tex_internals.py +2 -12
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/parser.py +24 -26
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/parser_db.py +2 -1
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/trello.py +8 -7
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/typotools.py +4 -4
- chgksuite-0.27.0b3/chgksuite/version.py +1 -0
- chgksuite-0.27.0b3/chgksuite.egg-info/PKG-INFO +40 -0
- chgksuite-0.27.0b3/chgksuite.egg-info/SOURCES.txt +67 -0
- chgksuite-0.27.0b3/chgksuite.egg-info/dependency_links.txt +1 -0
- chgksuite-0.27.0b3/chgksuite.egg-info/entry_points.txt +2 -0
- chgksuite-0.27.0b3/chgksuite.egg-info/requires.txt +19 -0
- chgksuite-0.27.0b3/chgksuite.egg-info/top_level.txt +1 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/history.md +1 -2
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/pyproject.toml +17 -6
- chgksuite-0.27.0b3/setup.cfg +4 -0
- chgksuite-0.27.0/.github/workflows/build.yml +0 -291
- chgksuite-0.27.0/.gitignore +0 -10
- chgksuite-0.27.0/.gitlab-ci.yml +0 -17
- chgksuite-0.27.0/.hgignore +0 -2
- chgksuite-0.27.0/.~lock.results.xlsx# +0 -1
- chgksuite-0.27.0/adhoc/regexes_fixer.py +0 -66
- chgksuite-0.27.0/author_counter.py +0 -24
- chgksuite-0.27.0/chgksuite/_html2md.py +0 -90
- chgksuite-0.27.0/chgksuite/handouter/runner.py +0 -461
- chgksuite-0.27.0/chgksuite/lastdir +0 -1
- chgksuite-0.27.0/chgksuite/version.py +0 -1
- chgksuite-0.27.0/debug_0.txt +0 -3
- chgksuite-0.27.0/debug_1.json +0 -10
- chgksuite-0.27.0/debug_1a.json +0 -10
- chgksuite-0.27.0/debug_2.json +0 -10
- chgksuite-0.27.0/debug_3.json +0 -10
- chgksuite-0.27.0/debug_4.json +0 -14
- chgksuite-0.27.0/debug_5.json +0 -14
- chgksuite-0.27.0/debug_6.json +0 -10
- chgksuite-0.27.0/debug_final.json +0 -10
- chgksuite-0.27.0/dev_readme.md +0 -25
- chgksuite-0.27.0/docs/.cache/.gitignore +0 -1
- chgksuite-0.27.0/docs/.cache/12897346880794287463 +0 -43
- chgksuite-0.27.0/docs/.cache/13071136909783630831 +0 -27
- chgksuite-0.27.0/docs/.cache/13307108790744403429 +0 -58
- chgksuite-0.27.0/docs/.cache/13333983167045209281 +0 -27
- chgksuite-0.27.0/docs/.cache/14085495286103177657 +0 -4
- chgksuite-0.27.0/docs/.cache/15213489598760314030 +0 -149
- chgksuite-0.27.0/docs/.cache/15319492834190874243 +0 -4
- chgksuite-0.27.0/docs/.cache/17387058097034297385 +0 -4
- chgksuite-0.27.0/docs/.cache/17722115158263369208 +0 -4
- chgksuite-0.27.0/docs/.cache/18247088324849079572 +0 -4
- chgksuite-0.27.0/docs/.cache/1840587404175770520 +0 -43
- chgksuite-0.27.0/docs/.cache/2517734129797249711 +0 -4
- chgksuite-0.27.0/docs/.cache/273431981325847810 +0 -164
- chgksuite-0.27.0/docs/.cache/2872065536916780406 +0 -27
- chgksuite-0.27.0/docs/.cache/3476900567878811119 +0 -4
- chgksuite-0.27.0/docs/.cache/4757258273854424423 +0 -58
- chgksuite-0.27.0/docs/.cache/5728722062471071239 +0 -58
- chgksuite-0.27.0/docs/.cache/6061198691539556612 +0 -4
- chgksuite-0.27.0/docs/.cache/6079179394456200124 +0 -4
- chgksuite-0.27.0/docs/.cache/735877668610100612 +0 -73
- chgksuite-0.27.0/docs/.cache/9345880734637750342 +0 -4
- chgksuite-0.27.0/docs/.cache/9490951945832949972 +0 -4
- chgksuite-0.27.0/docs/docs/4s.md +0 -229
- chgksuite-0.27.0/docs/docs/add_stats.md +0 -9
- chgksuite-0.27.0/docs/docs/base.md +0 -43
- chgksuite-0.27.0/docs/docs/i14n.md +0 -31
- chgksuite-0.27.0/docs/docs/images/base.png +0 -0
- chgksuite-0.27.0/docs/docs/images/douplet_problem.png +0 -0
- chgksuite-0.27.0/docs/docs/images/i14n.png +0 -0
- chgksuite-0.27.0/docs/docs/images/i14n_parse.png +0 -0
- chgksuite-0.27.0/docs/docs/images/lj.png +0 -0
- chgksuite-0.27.0/docs/docs/images/main.png +0 -0
- chgksuite-0.27.0/docs/docs/images/openquiz.png +0 -0
- chgksuite-0.27.0/docs/docs/images/openquiz2.png +0 -0
- chgksuite-0.27.0/docs/docs/images/parse.png +0 -0
- chgksuite-0.27.0/docs/docs/images/pptx.png +0 -0
- chgksuite-0.27.0/docs/docs/images/pptx_additional_conf.png +0 -0
- chgksuite-0.27.0/docs/docs/images/pptx_slide_a.png +0 -0
- chgksuite-0.27.0/docs/docs/images/pptx_slide_q.png +0 -0
- chgksuite-0.27.0/docs/docs/images/roenko.png +0 -0
- chgksuite-0.27.0/docs/docs/images/rozhdsushkov.png +0 -0
- chgksuite-0.27.0/docs/docs/images/stats.png +0 -0
- chgksuite-0.27.0/docs/docs/images/telegram.png +0 -0
- chgksuite-0.27.0/docs/docs/images/trello_download.png +0 -0
- chgksuite-0.27.0/docs/docs/images/trello_token.png +0 -0
- chgksuite-0.27.0/docs/docs/images/trello_upload.png +0 -0
- chgksuite-0.27.0/docs/docs/images/word.png +0 -0
- chgksuite-0.27.0/docs/docs/index.md +0 -59
- chgksuite-0.27.0/docs/docs/lj.md +0 -9
- chgksuite-0.27.0/docs/docs/openquiz.md +0 -7
- chgksuite-0.27.0/docs/docs/pptx.md +0 -66
- chgksuite-0.27.0/docs/docs/stylesheets/extra.css +0 -29
- chgksuite-0.27.0/docs/docs/telegram.md +0 -46
- chgksuite-0.27.0/docs/docs/trello.md +0 -31
- chgksuite-0.27.0/docs/docs/word.md +0 -24
- chgksuite-0.27.0/docs/mkdocs.yml +0 -35
- chgksuite-0.27.0/hook-dateparser.py +0 -12
- chgksuite-0.27.0/packer.py +0 -172
- chgksuite-0.27.0/pytest.ini +0 -5
- chgksuite-0.27.0/pytest.sh +0 -7
- chgksuite-0.27.0/re_helper.py +0 -24
- chgksuite-0.27.0/requirements_dev.txt +0 -2
- chgksuite-0.27.0/results.xlsx +0 -0
- chgksuite-0.27.0/ruff.toml +0 -2
- chgksuite-0.27.0/test_multiple_images.txt +0 -3
- chgksuite-0.27.0/test_oschr/404.jpg +0 -0
- chgksuite-0.27.0/test_oschr/Arhipova_Shtirlic-shel-po-koridoru-.803300.pdf/stirlitz_was_walking.fbd +0 -525
- chgksuite-0.27.0/test_oschr/Arhipova_Shtirlic-shel-po-koridoru-.803300.pdf/stirlitz_was_walking.pdf +0 -0
- chgksuite-0.27.0/test_oschr/alexeeva.jpeg +0 -0
- chgksuite-0.27.0/test_oschr/arhipova.txt +0 -1030
- chgksuite-0.27.0/test_oschr/ber.png +0 -0
- chgksuite-0.27.0/test_oschr/columns.txt +0 -35
- chgksuite-0.27.0/test_oschr/columns_ru.pdf +0 -0
- chgksuite-0.27.0/test_oschr/cool.pdf +0 -0
- chgksuite-0.27.0/test_oschr/cool.png +0 -0
- chgksuite-0.27.0/test_oschr/dish.png +0 -0
- chgksuite-0.27.0/test_oschr/dubinki.png +0 -0
- chgksuite-0.27.0/test_oschr/duran01.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran02.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran03.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran04.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran05.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran06.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran07.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran08.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran09.jpg +0 -0
- chgksuite-0.27.0/test_oschr/duran10.jpg +0 -0
- chgksuite-0.27.0/test_oschr/eisenhower.png +0 -0
- chgksuite-0.27.0/test_oschr/emo.pdf +0 -0
- chgksuite-0.27.0/test_oschr/emo.png +0 -0
- chgksuite-0.27.0/test_oschr/emosong.png +0 -0
- chgksuite-0.27.0/test_oschr/emosong1.png +0 -0
- chgksuite-0.27.0/test_oschr/emosong2.png +0 -0
- chgksuite-0.27.0/test_oschr/handouts_test.txt +0 -30
- chgksuite-0.27.0/test_oschr/handouts_test_ru.tex +0 -296
- chgksuite-0.27.0/test_oschr/karikatura_razdatka.png +0 -0
- chgksuite-0.27.0/test_oschr/kuzmin-tat.png +0 -0
- chgksuite-0.27.0/test_oschr/kuzmin.txt +0 -13242
- chgksuite-0.27.0/test_oschr/otbor_studchr.txt +0 -79
- chgksuite-0.27.0/test_oschr/otbor_studchr_handouts.txt +0 -16
- chgksuite-0.27.0/test_oschr/otbor_studchr_handouts_ru.pdf +0 -0
- chgksuite-0.27.0/test_oschr/panchenko.txt +0 -23670
- chgksuite-0.27.0/test_oschr/zine.png +0 -0
- chgksuite-0.27.0/test_with_image.txt +0 -3
- chgksuite-0.27.0/test_with_real_image.txt +0 -3
- chgksuite-0.27.0/tests/2019-07-23_beln19_u.docx +0 -0
- chgksuite-0.27.0/tests/2019-07-23_beln19_u.docx.canon +0 -690
- chgksuite-0.27.0/tests/Kubok_knyagini_Olgi-2015.docx +0 -0
- chgksuite-0.27.0/tests/Kubok_knyagini_Olgi-2015.docx.canon +0 -644
- chgksuite-0.27.0/tests/Shkolny_Chemp_Estonii-2014_(48v).docx +0 -0
- chgksuite-0.27.0/tests/Shkolny_Chemp_Estonii-2014_(48v).docx.canon +0 -361
- chgksuite-0.27.0/tests/__init__.py +0 -0
- chgksuite-0.27.0/tests/balt09-1.txt +0 -783
- chgksuite-0.27.0/tests/balt09-1.txt.canon +0 -286
- chgksuite-0.27.0/tests/borromeo.txt +0 -11
- chgksuite-0.27.0/tests/borromeo.txt.canon +0 -16
- chgksuite-0.27.0/tests/canonize.py +0 -69
- chgksuite-0.27.0/tests/chgksuite_test.py +0 -364
- chgksuite-0.27.0/tests/conftest.py +0 -21
- chgksuite-0.27.0/tests/encrypt_test_files.py +0 -147
- chgksuite-0.27.0/tests/haifa2025.docx +0 -0
- chgksuite-0.27.0/tests/haifa2025.docx.canon +0 -349
- chgksuite-0.27.0/tests/haifa2025.docx.encrypted +0 -0
- chgksuite-0.27.0/tests/haifa2025.docx.encrypted.canon +0 -0
- chgksuite-0.27.0/tests/link_unwrap.docx +0 -0
- chgksuite-0.27.0/tests/link_unwrap.docx.canon +0 -10
- chgksuite-0.27.0/tests/ljcredentials +0 -1
- chgksuite-0.27.0/tests/long_handout.png +0 -0
- chgksuite-0.27.0/tests/malkin_papkov_synchr.docx +0 -0
- chgksuite-0.27.0/tests/malkin_papkov_synchr.docx.canon +0 -99
- chgksuite-0.27.0/tests/octo2021_khmelkov.docx +0 -0
- chgksuite-0.27.0/tests/octo2021_khmelkov.docx.canon +0 -102
- chgksuite-0.27.0/tests/ovsch_boronenko_3.4s +0 -334
- chgksuite-0.27.0/tests/ovsch_boronenko_3.docx +0 -0
- chgksuite-0.27.0/tests/ovsch_boronenko_3.docx.canon +0 -334
- chgksuite-0.27.0/tests/pass1.docx +0 -0
- chgksuite-0.27.0/tests/pass1.docx.canon +0 -183
- chgksuite-0.27.0/tests/settings.json +0 -3
- chgksuite-0.27.0/tests/single_number_line_test.docx +0 -0
- chgksuite-0.27.0/tests/single_number_line_test.docx.canon +0 -46
- chgksuite-0.27.0/tests/smalltest.4s +0 -6
- chgksuite-0.27.0/tests/test.jpg +0 -0
- chgksuite-0.27.0/tests/test_blitz.txt +0 -8
- chgksuite-0.27.0/tests/test_blitz.txt.canon +0 -9
- chgksuite-0.27.0/tests/tourrev_with_razmin.docx +0 -0
- chgksuite-0.27.0/tests/tourrev_with_razmin.docx.canon +0 -34
- 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
- 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
- chgksuite-0.27.0/uv.lock +0 -1454
- 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
- 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
- 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
- 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
- chgksuite-0.27.0//321/216 +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/LICENSE +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/MANIFEST.in +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/README.md +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/__init__.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/__main__.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/composer_common.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/pptx.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/stats.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/telegram.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/composer/telegram_bot.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/__init__.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/gen.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/installer.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/pack.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/handouter/utils.py +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/cheader.tex +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/fix-unnumbered-sections.sty +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_az.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_by.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_by_tar.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_en.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_kz_cyr.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_ru.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_sr.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_ua.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_uz.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/labels_uz_cyr.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/pptx_config.toml +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_az.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_by.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_by_tar.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_en.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_kz_cyr.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_ru.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_sr.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_ua.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_uz.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/regexes_uz_cyr.json +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/template.docx +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/template.pptx +0 -0
- {chgksuite-0.27.0 → chgksuite-0.27.0b3}/chgksuite/resources/trello.json +0 -0
- {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.
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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",
|
|
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",
|
|
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.
|
|
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",
|
|
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
|
-
|
|
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",
|
|
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
|
|
152
|
-
exporter =
|
|
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
|
|
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
|
|
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
|
-
|
|
125
|
-
|
|
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",
|
|
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",
|
|
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",
|
|
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"\\[
|
|
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",
|
|
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",
|
|
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",
|
|
178
|
+
with codecs.open(outfilename, "w", "utf8") as f:
|
|
178
179
|
f.write(json.dumps(result, indent=2, ensure_ascii=False))
|
chgksuite-0.27.0/chgksuite/composer/markdown.py → chgksuite-0.27.0b3/chgksuite/composer/reddit.py
RENAMED
|
@@ -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
|
|
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
|
|
18
|
+
def reddityapper(self, e):
|
|
18
19
|
if isinstance(e, str):
|
|
19
|
-
return self.
|
|
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.
|
|
23
|
+
return self.reddit_element_layout(e)
|
|
23
24
|
else:
|
|
24
|
-
return " \n".join([self.
|
|
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
|
|
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
|
-
|
|
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
|
|
60
|
+
def reddit_element_layout(self, e):
|
|
65
61
|
res = ""
|
|
66
62
|
if isinstance(e, str):
|
|
67
|
-
res = self.
|
|
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.
|
|
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
|
|
74
|
+
def reddit_format_element(self, pair):
|
|
79
75
|
if pair[0] == "Question":
|
|
80
|
-
return self.
|
|
76
|
+
return self.reddit_format_question(pair[1])
|
|
81
77
|
|
|
82
|
-
def
|
|
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.
|
|
83
|
+
self.reddityapper(q["question"]),
|
|
88
84
|
)
|
|
89
85
|
if "number" not in q:
|
|
90
86
|
self.qcount += 1
|
|
91
|
-
|
|
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.
|
|
89
|
+
res += "__Зачёт:__ {} \n".format(self.reddityapper(q["zachet"]))
|
|
98
90
|
if "nezachet" in q:
|
|
99
|
-
res += "__Незачёт:__ {} \n".format(self.
|
|
91
|
+
res += "__Незачёт:__ {} \n".format(self.reddityapper(q["nezachet"]))
|
|
100
92
|
if "comment" in q:
|
|
101
|
-
res += "__Комментарий:__ {} \n".format(self.
|
|
93
|
+
res += "__Комментарий:__ {} \n".format(self.reddityapper(q["comment"]))
|
|
102
94
|
if "source" in q:
|
|
103
|
-
res += "__Источник:__ {} \n".format(self.
|
|
95
|
+
res += "__Источник:__ {} \n".format(self.reddityapper(q["source"]))
|
|
104
96
|
if "author" in q:
|
|
105
|
-
res += "
|
|
106
|
-
spoiler_end, self.markdownyapper(q["author"])
|
|
107
|
-
)
|
|
97
|
+
res += "!<\n__Автор:__ {} \n".format(self.reddityapper(q["author"]))
|
|
108
98
|
else:
|
|
109
|
-
res +=
|
|
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.
|
|
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",
|
|
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>]
|
|
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>}"""
|